我正在使用一个高度为600
to 1000
像素,宽度为数万或数十万像素的canvas元素。但是,经过一定数量的像素(显然是未知的)之后,画布不再显示我使用JS绘制的形状。
有谁知道是否有限制?
在Chrome 12和Firefox 4中都进行了测试。
我正在使用一个高度为600
to 1000
像素,宽度为数万或数十万像素的canvas元素。但是,经过一定数量的像素(显然是未知的)之后,画布不再显示我使用JS绘制的形状。
有谁知道是否有限制?
在Chrome 12和Firefox 4中都进行了测试。
Answers:
2014年10月13日更新
所有经过测试的浏览器都限制了canvas元素的高度/宽度,但是许多浏览器也限制了canvas元素的总面积。可以测试的浏览器的限制如下:
最大高度/宽度:32,767像素
最大区域:268,435,456像素(例如16,384 x 16,384)
最大高度/宽度:32,767像素
最大面积:472,907,776像素(例如22,528 x 20,992)
最大高度/宽度:8,192像素
最大面积:不适用
最大高度/宽度:4,096像素
最大面积:不适用
我目前无法测试其他浏览器。有关其他限制,请参阅此页面上的其他答案。
在大多数浏览器中,超过最大长度/宽度/面积会使画布无法使用。(即使在可用区域中,它也会忽略任何绘制命令。)IE和IE Mobile将遵守可用空间中的所有绘制命令。
<canvas>
元素,并自动将绘图指令应用于适当的上下文。
在画布高度大于8000的Firefox上,我遇到了内存不足的错误,chrome似乎处理得更高,至少达到32000。
编辑:运行更多测试后,我发现Firefox 16.0.2有一些非常奇怪的错误。
首先,我似乎从内存(在javascript中创建)画布获得了与HTML声明的画布不同的行为。
其次,如果您没有适当的html标记和meta字符集,则画布可能会限制为8196,否则可以增加到32767。
第三,如果您获得了画布的2d上下文,然后更改了画布的大小,那么您也可能会被限制为8196。在获取2d上下文之前,只需设置画布大小即可使您拥有32767,而不会出现内存错误。
我一直无法始终得到内存错误,有时仅在首页加载时出现,然后进行后续的高度更改即可。这是我使用http://pastebin.com/zK8nZxdE测试的html文件。
若要进一步说明@FredericCharette答案:根据safari的内容指南,在“了解iOS资源限制”部分下:
对于RAM小于256 MB的设备,canvas元素的最大大小为3百万像素,对于大于或等于256 MB RAM的设备,canvas的最大大小为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
2018年更新:
随着时间的流逝,画布的局限性发生了变化。可悲的是,没有改变的是,浏览器仍然没有通过Canvas API提供有关画布大小限制的信息。
对于那些希望以编程方式确定浏览器的最大画布尺寸或测试对自定义画布尺寸的支持的用户,请查看canvas-size。
从文档:
HTML canvas元素受到现代和旧版浏览器的广泛支持,但是每种浏览器和平台组合都具有独特的大小限制,当超出限制时,将使画布无法使用。不幸的是,浏览器无法提供确定其局限性的方法,也无法在创建了无法使用的画布后提供任何形式的反馈。这使得处理大型画布元素成为一个挑战,尤其是对于支持各种浏览器和平台的应用程序而言。
该微库提供了浏览器支持的HTML画布元素的最大面积,高度和宽度,以及测试自定义画布尺寸的能力。通过在创建新画布元素之前收集此信息,应用程序能够在每个浏览器/平台的大小限制内可靠地设置画布尺寸。
README中有一个演示链接和测试结果,还有一个有关性能和虚拟机注意事项的已知问题部分。
完全公开,我是图书馆的作者。我在2014年创建了它,最近又重新访问了一个与画布相关的新项目的代码。令我感到惊讶的是,在2018年仍然缺少可用于检测画布大小限制的工具,因此我更新了代码并发布了它,并希望它可以帮助其他遇到类似问题的人。
即使画布允许您放置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的设备,canvas元素的最大大小为3百万像素,对于大于或等于256 MB RAM的设备,canvas的最大大小为5百万像素。
因此,例如-如果您想支持Apple的较早硬件,则画布的大小不能超过2048×1464。
希望这些资源能帮助您将自己拉出来。
Safari(所有平台)的限制要低得多。
例如,我有一个6400x6400px的画布缓冲区,上面绘制了数据。通过跟踪/导出内容并在其他浏览器上进行测试,我发现一切都很好。但是在Safari上,它将跳过此特定缓冲区在我的主要上下文上的绘制。
我试图以编程方式找出限制:设置画布大小从35000开始,递减100直到找到有效大小。在每一步中,写入右下像素,然后读取。它有效-谨慎。
如果宽度或高度被设置为一些低的值(如:10-200)这样的速度是可以接受的:get_max_canvas_size('height', 20)
。
但是,如果调用时不带宽度或高度之类的get_max_canvas_size()
,则创建的画布太大,以致于读取SINGLE像素颜色非常慢,并且在IE中会导致严重的挂起。
如果某种类似的测试可以在不读取像素值的情况下进行,则速度可以接受。
当然,最简单的检测最大尺寸的方法是查询最大宽度和高度的某些本地方法。但是Canvas是“生活水平”,所以也许有一天会到来。
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);
tens OR hundreds of thousands
……