我正在使用高度为 600
到 1000
像素、宽度为数万或数十万像素的画布元素。但是,经过一定数量的像素(显然是未知的)后,画布不再显示我用 JS 绘制的形状。
有谁知道有没有限制?
在 Chrome 12 和 Firefox 4 中测试。
tens OR hundreds of thousands
...
2014 年 10 月 13 日更新
所有测试的浏览器都对画布元素的高度/宽度有限制,但许多浏览器也限制了画布元素的总面积。对于我能够测试的浏览器,限制如下:
铬合金:
最大高度/宽度:32,767 像素 最大面积:268,435,456 像素(例如,16,384 x 16,384)
火狐:
最大高度/宽度:32,767 像素 最大面积:472,907,776 像素(例如,22,528 x 20,992)
IE:
最大高度/宽度:8,192 像素最大面积:N/A
IE手机:
最大高度/宽度:4,096 像素最大面积:N/A
其他:
我目前无法测试其他浏览器。有关其他限制,请参阅此页面上的其他答案。
在大多数浏览器上超过最大长度/宽度/面积会导致画布无法使用。 (它将忽略任何绘图命令,即使在可用区域中也是如此。) IE 和 IE Mobile 将遵循可用空间内的所有绘图命令。
接受的答案已过时且不完整。
浏览器施加不同的画布大小限制,但这些限制通常会根据可用的平台和硬件而变化。这使得很难做出诸如“[browser]
的最大画布 [area/height/width]
是 [value]
”之类的陈述,因为 [value]
可以根据操作系统、可用 RAM 或 GPU 类型而改变。
有两种处理大型 HTML <canvas>
元素的方法:
将画布尺寸限制为已知可在所有支持的平台上工作的尺寸。在渲染之前以编程方式确定客户端上的画布限制。
那些希望以编程方式确定客户端画布限制的人员应考虑使用 canvas-size。
GitHub:https://github.com/jhildenbiddle/canvas-size
NPM:https://www.npmjs.com/package/canvas-size
从文档:
现代和旧版浏览器广泛支持 HTML 画布元素,但每个浏览器和平台组合都会施加独特的大小限制,超过时会导致画布无法使用。不幸的是,浏览器没有提供一种方法来确定它们的限制是什么,也没有在创建不可用的画布之后提供任何类型的反馈。这使得使用大型画布元素成为一项挑战,尤其是对于支持各种浏览器和平台的应用程序。这个微型库提供浏览器支持的 HTML 画布元素的最大面积、高度和宽度,以及测试自定义画布尺寸的能力。通过在创建新的画布元素之前收集这些信息,应用程序能够在每个浏览器/平台的大小限制内可靠地设置画布尺寸。
各种平台和浏览器组合的测试结果可在此处获得:
测试结果:https://github.com/jhildenbiddle/canvas-size#test-results
完全公开,我是图书馆的作者。我在 2014 年创建了它,最近重新访问了一个新的画布相关项目的代码。我惊讶地发现在 2018 年同样缺乏用于检测画布大小限制的可用工具,因此我更新了代码,发布了它,并希望它能帮助其他遇到类似问题的人。
我在画布高度大于 8000 的 Firefox 上遇到了内存不足错误,chrome 似乎处理得更高,至少到 32000。
编辑:运行更多测试后,我发现 Firefox 16.0.2 出现了一些非常奇怪的错误。
首先,我似乎从内存中(在 javascript 中创建)画布中得到了不同的行为,而不是 html 声明的画布。
其次,如果您没有正确的 html 标记和元字符集,画布可能会被限制为 8196,否则您可以达到 32767。
第三,如果您获取画布的 2d 上下文,然后更改画布大小,您可能也被限制为 8196。只需在获取 2d 上下文之前设置画布大小,您就可以拥有多达 32767 个而不会出现内存错误。
我无法始终如一地得到内存错误,有时它只是在第一页加载时,然后随后的高度变化才起作用。这是我用 http://pastebin.com/zK8nZxdE 测试的 html 文件。
iOS 最大画布尺寸(宽 x 高):
iPod Touch 16GB = 1448x1448
iPad Mini = 2290x2289
iPhone 3 = 1448x1448
iPhone 5 = 2290x2289
2014 年 3 月测试。
要扩展 @FredericCharette 的答案:根据“了解 iOS 资源限制”部分下的 safari's content guide:
对于 RAM 小于 256 MB 的设备,画布元素的最大大小为 3 兆像素,对于 RAM 大于或等于 256 MB 的设备,最大大小为 5 兆像素
因此,任何 5242880 (5 x 1024 x 1024) 像素的大小变化都适用于大型存储设备,否则为 3145728 像素。
5 兆像素画布(宽 x 高)的示例:
Any total <= 5242880
--------------------
5 x 1048576 ~= 5MP (1048576 = 1024 x 1024)
50 x 104857 ~= 5MP
500 x 10485 ~= 5MP
等等..
最大的 SQUARE 画布是(“MiB”= 1024x1024 字节):
device < 256 MiB device >= 256 MiB iPhone 6 [not confirmed]
----------------- ----------------- ---------------------
<= 3145728 pixels <= 5242880 pixels <= 16 x 1024 x 1024 p
1773 x 1773 2289 x 2289 4096 x 4096
即使画布允许您放置 height=2147483647,但当您开始绘制时,什么都不会发生
仅当我将高度恢复到 32767 时才会绘制
iOS 有不同的限制。
使用 iOS 7 模拟器,我能够证明限制是 5MB,如下所示:
var canvas = document.createElement('canvas');
canvas.width = 1024 * 5;
canvas.height = 1024;
alert(canvas.toDataURL('image/jpeg').length);
// prints "110087" - the expected length of the dataURL
但是如果我将画布大小向上移动一行像素:
var canvas = document.createElement('canvas');
canvas.width = 1024 * 5;
canvas.height = 1025;
alert(canvas.toDataURL('image/jpeg'));
// prints "data:," - a broken dataURL
在 PC 上——我认为没有限制,但是是的,你可以摆脱内存异常。
在移动设备上-以下是移动设备画布的限制:-
对于 RAM 小于 256 MB 的设备,画布元素的最大大小为 3 兆像素,而对于 RAM 大于或等于 256 MB 的设备,画布元素的最大大小为 5 兆像素。
所以举个例子——如果你想支持苹果的旧硬件,你的画布大小不能超过 2048×1464。
希望这些资源能帮助您摆脱困境。
Safari(所有平台)的限制要低得多。
例如,我有一个 6400x6400px 的画布缓冲区,上面绘制了数据。通过跟踪/导出内容并在其他浏览器上进行测试,我能够看到一切都很好。但是在 Safari 上,它会跳过将此特定缓冲区的绘制到我的主要上下文中。
我试图以编程方式找出限制:从 35000 开始设置画布大小,递减 100 直到找到有效大小。在每一步中写入右下像素然后读取它。它有效 - 谨慎。
如果通过以下方式将宽度或高度设置为某个较低的值(例如 10-200),则速度是可以接受的:get_max_canvas_size('height', 20)
。
但是如果像 get_max_canvas_size()
那样不带宽度或高度调用,创建的画布太大以至于读取 SINGLE 像素颜色非常慢,并且在 IE 中会导致严重的挂起。
如果可以在不读取像素值的情况下以某种方式完成类似的测试,那么速度将是可以接受的。
当然,检测最大尺寸的最简单方法是查询最大宽度和高度的一些本地方法。但帆布是“一种生活标准”,所以它可能会在某一天到来。
http://jsfiddle.net/timo2012/tcg6363r/2/(请注意!您的浏览器可能会挂起!)
if (!Date.now)
{
Date.now = function now()
{
return new Date().getTime();
};
}
var t0 = Date.now();
//var size = get_max_canvas_size('width', 200);
var size = get_max_canvas_size('height', 20);
//var size = get_max_canvas_size();
var t1 = Date.now();
var c = size.canvas;
delete size.canvas;
$('body').append('time: ' + (t1 - t0) + '<br>max size:' + JSON.stringify(size) + '<br>');
//$('body').append(c);
function get_max_canvas_size(h_or_w, _size)
{
var c = document.createElement('canvas');
if (h_or_w == 'height') h = _size;
else if (h_or_w == 'width') w = _size;
else if (h_or_w && h_or_w !== 'width' && h_or_w !== 'height' || !window.CanvasRenderingContext2D)
return {
width: null,
height: null
};
var w, h;
var size = 35000;
var cnt = 0;
if (h_or_w == 'height') w = size;
else if (h_or_w == 'width') h = size;
else
{
w = size;
h = size;
}
if (!valid(w, h))
for (; size > 10; size -= 100)
{
cnt++;
if (h_or_w == 'height') w = size;
else if (h_or_w == 'width') h = size;
else
{
w = size;
h = size;
}
if (valid(w, h)) break;
}
return {
width: w,
height: h,
iterations: cnt,
canvas: c
};
function valid(w, h)
{
var t0 = Date.now();
var color, p, ctx;
c.width = w;
c.height = h;
if (c && c.getContext)
ctx = c.getContext("2d");
if (ctx)
{
ctx.fillStyle = "#ff0000";
try
{
ctx.fillRect(w - 1, h - 1, 1, 1);
p = ctx.getImageData(w - 1, h - 1, 1, 1).data;
}
catch (err)
{
console.log('err');
}
if (p)
color = p[0] + '' + p[1] + '' + p[2];
}
var t1 = Date.now();
if (color == '25500')
{
console.log(w, h, true, t1 - t0);
return true;
}
console.log(w, h, false, t1 - t0);
return false;
}
}
当您使用 WebGL 画布时,浏览器(包括桌面浏览器)将对底层缓冲区的大小施加额外的限制。即使您的画布很大,例如 16,000x16,000,大多数浏览器也会渲染更小的(比如 4096x4096)图片,然后将其放大。这可能会导致丑陋的像素化等。
如果有人需要,我已经编写了一些代码来确定使用指数搜索的最大大小。 determineMaxCanvasSize()
是您感兴趣的函数。
function makeGLCanvas()
{
// Get A WebGL context
var canvas = document.createElement('canvas');
var contextNames = ["webgl", "experimental-webgl"];
var gl = null;
for (var i = 0; i < contextNames.length; ++i)
{
try
{
gl = canvas.getContext(contextNames[i], {
// Used so that the buffer contains valid information, and bytes can
// be retrieved from it. Otherwise, WebGL will switch to the back buffer
preserveDrawingBuffer: true
});
}
catch(e) {}
if (gl != null)
{
break;
}
}
if (gl == null)
{
alert("WebGL not supported.\nGlobus won't work\nTry using browsers such as Mozilla " +
"Firefox, Google Chrome or Opera");
// TODO: Expecting that the canvas will be collected. If that is not the case, it will
// need to be destroyed somehow.
return;
}
return [canvas, gl];
}
// From Wikipedia
function gcd(a,b) {
a = Math.abs(a);
b = Math.abs(b);
if (b > a) {var temp = a; a = b; b = temp;}
while (true) {
if (b == 0) return a;
a %= b;
if (a == 0) return b;
b %= a;
}
}
function isGlContextFillingTheCanvas(gl) {
return gl.canvas.width == gl.drawingBufferWidth && gl.canvas.height == gl.drawingBufferHeight;
}
// (See issue #2) All browsers reduce the size of the WebGL draw buffer for large canvases
// (usually over 4096px in width or height). This function uses a varian of binary search to
// find the maximum size for a canvas given the provided x to y size ratio.
//
// To produce exact results, this function expects an integer ratio. The ratio will be equal to:
// xRatio/yRatio.
function determineMaxCanvasSize(xRatio, yRatio) {
// This function works experimentally, by creating an actual canvas and finding the maximum
// value, the browser allows.
[canvas, gl] = makeGLCanvas();
// Reduce the ratio to minimum
gcdOfRatios = gcd(xRatio, yRatio);
[xRatio, yRatio] = [xRatio/gcdOfRatios, yRatio/gcdOfRatios];
// if the browser cannot handle the minimum ratio, there is not much we can do
canvas.width = xRatio;
canvas.height = yRatio;
if (!isGlContextFillingTheCanvas(gl)) {
throw "The browser is unable to use WebGL canvases with the specified ratio: " +
xRatio + ":" + yRatio;
}
// First find an upper bound
var ratioMultiple = 1; // to maintain the exact ratio, we will keep the multiplyer that
// resulted in the upper bound for the canvas size
while (isGlContextFillingTheCanvas(gl)) {
canvas.width *= 2;
canvas.height *= 2;
ratioMultiple *= 2;
}
// Search with minVal inclusive, maxVal exclusive
function binarySearch(minVal, maxVal) {
if (minVal == maxVal) {
return minVal;
}
middle = Math.floor((maxVal - minVal)/2) + minVal;
canvas.width = middle * xRatio;
canvas.height = middle * yRatio;
if (isGlContextFillingTheCanvas(gl)) {
return binarySearch(middle + 1, maxVal);
} else {
return binarySearch(minVal, middle);
}
}
ratioMultiple = binarySearch(1, ratioMultiple);
return [xRatio * ratioMultiple, yRatio * ratioMultiple];
}
同样在 jsfiddle https://jsfiddle.net/1sh47wfk/1/
您可以将其分块并在 javascript 中根据需要自动添加尽可能多的较小画布并在适当的画布上绘制元素。您最终可能仍然会耗尽内存,但会通过单个画布限制来解决。
我不知道如何在没有迭代的情况下检测最大可能大小,但是您可以通过填充像素然后读取颜色来检测给定的画布大小是否有效。如果画布尚未渲染,那么您返回的颜色将不匹配。 W
部分代码:
function rgbToHex(r, g, b) {
if (r > 255 || g > 255 || b > 255)
throw "Invalid color component";
return ((r << 16) | (g << 8) | b).toString(16);
}
var test_colour = '8ed6ff';
working_context.fillStyle = '#' + test_colour;
working_context.fillRect(0,0,1,1);
var colour_data = working_context.getImageData(0, 0, 1, 1).data;
var colour_hex = ("000000" + rgbToHex(colour_data[0], colour_data[1], colour_data[2])).slice(-6);
不定期副业成功案例分享
<canvas>
元素并自动将绘图指令应用于适当的上下文。