javascript - triangulo - Tamaño máximo de un elemento<canvas>
figuras canvas html5 (13)
Estoy trabajando con un elemento canvas con una altura de 600 a 1000 píxeles y un ancho de varias decenas o cientos de miles de píxeles. Sin embargo, después de un cierto número de píxeles (obviamente desconocido), el lienzo ya no muestra las formas que dibujo con JS.
¿Alguien sabe si hay un límite? Gracias.
Edición : probado tanto en Chrome 12 como en Firefox 4.
Aunque el lienzo le permitirá poner altura = 2147483647, cuando empiece a dibujar, no pasará nada
El dibujo ocurre solo cuando devuelvo la altura a 32767
Cuando utilice lienzos WebGL, los navegadores (incluidos los de escritorio) impondrán límites adicionales al tamaño del búfer subyacente. Incluso si su lienzo es grande, por ejemplo, 16,000x16,000, la mayoría de los navegadores mostrarán una imagen más pequeña (digamos 4096x4096) y la ampliará. Eso podría causar pixelado feo, etc.
He escrito un código para determinar ese tamaño máximo mediante la búsqueda exponencial, si alguien alguna vez lo necesita. determineMaxCanvasSize()
es la función que le interesa.
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];
}
También en un jsfiddle https://jsfiddle.net/1sh47wfk/1/
De acuerdo con las especificaciones de w3 , la interfaz de ancho / alto es una longitud sin signo, por lo que de 0 a 4.294.967.295 (si recuerdo ese número correcto, podría ser un poco).
EDITAR: Extrañamente, dice sin signo largo, pero las pruebas muestran solo un valor largo normal como máximo: 2147483647. Jsfiddle - 47 funciona pero hasta 48 y vuelve a su valor predeterminado.
Intenté calcular programáticamente el límite: establecer el tamaño del lienzo comenzando desde 35000, reduciendo por 100 hasta que se encuentre un tamaño válido. En cada paso, escribe el píxel inferior derecho y luego lo lee. Funciona - con precaución.
La velocidad es aceptable si el ancho o alto se establece en un valor bajo (por ejemplo, 10-200) de esta manera: get_max_canvas_size(''height'', 20)
.
Pero si se llama sin ancho o alto como get_max_canvas_size()
, el lienzo creado es tan grande que leer el color de un píxel SIMPLE es muy lento, y en IE causa un serio problema.
Si esta prueba similar se pudiera realizar de alguna manera sin leer el valor de píxel, la velocidad sería aceptable.
Por supuesto, la manera más fácil de detectar el tamaño máximo sería una forma nativa de consultar el ancho y alto máximos. Pero Canvas es "un estándar de vida", por lo que puede llegar algún día.
http://jsfiddle.net/timo2012/tcg6363r/2/ (¡Tenga en cuenta! ¡Su navegador puede bloquearse!)
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;
}
}
Las limitaciones para Safari (todas las plataformas) son mucho menores.
Limitaciones conocidas de iOS / Safari
Por ejemplo, tenía un buffer de lienzo de 6400x6400px con datos dibujados en él. Al rastrear / exportar el contenido y al probar en otros navegadores, pude ver que todo estaba bien. Pero en Safari, omitiría el dibujo de este búfer específico en mi contexto principal.
Me he encontrado con errores de memoria en Firefox con alturas de lienzo superiores a 8000, Chrome parece manejar mucho más alto, al menos hasta 32000.
EDITAR: Después de ejecutar algunas pruebas más, he encontrado algunos errores muy extraños con Firefox 16.0.2.
En primer lugar, parece que obtengo un comportamiento diferente en el lienzo de memoria (creado en javascript) en comparación con el lienzo declarado en html.
En segundo lugar, si no tiene la etiqueta html y meta charset correctos, el lienzo puede estar restringido a 8196, de lo contrario, puede ir hasta 32767.
En tercer lugar, si obtiene el segundo contexto del lienzo y luego cambia el tamaño del lienzo, también podría estar restringido a 8196. Simplemente establecer el tamaño del lienzo antes de capturar el contexto 2d le permite tener hasta 32767 sin obtener errores de memoria.
No he podido obtener los errores de memoria de forma consistente, a veces solo está en la carga de la primera página, y los siguientes cambios de altura funcionan. Este es el archivo html que estaba probando con http://pastebin.com/zK8nZxdE .
No sé cómo detectar el máximo tamaño posible sin iteración, pero puede detectar si un tamaño de lienzo determinado funciona rellenando un píxel y luego leyendo el color de nuevo. Si el lienzo no se ha renderizado, el color que obtenga no coincidirá. W
código parcial:
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);
Para ampliar un poco la respuesta de @FredericCharette: según la guía de contenido de safari en la sección "Conocer los límites de recursos de iOS":
El tamaño máximo para un elemento de lienzo es de 3 megapíxeles para dispositivos con menos de 256 MB de RAM y 5 megapíxeles para dispositivos con una memoria RAM mayor o igual a 256 MB.
Por lo tanto, cualquier variación de tamaño de 5242880 (5 x 1024 x 1024) píxeles funcionará en dispositivos de memoria grandes; de lo contrario, será 3145728 píxeles.
Ejemplo para lienzo de 5 megapíxeles (ancho x alto):
Any total <= 5242880
--------------------
5 x 1048576 ~= 5MP (1048576 = 1024 x 1024)
50 x 104857 ~= 5MP
500 x 10485 ~= 5MP
y así..
Los lienzos SQUARE más grandes son ("MiB" = 1024x1024 Bytes):
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
Podría dividirlo y en javascript agregar automáticamente tantos lienzos más pequeños como sea necesario y dibujar los elementos en el lienzo correspondiente. Es posible que todavía se quede sin memoria con el tiempo, pero lo alcanzará en el límite de lienzo único.
Tamaño máximo de lienzo de iOS (ancho x alto):
iPod Touch 16GB = 1448x1448
iPad Mini = 2290x2289
iPhone 3 = 1448x1448
iPhone 5 = 2290x2289
probado en marzo de 2014.
iOS tiene diferentes límites.
Usando el simulador iOS 7 pude demostrar que el límite es de 5MB como este:
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
pero si empujo el tamaño del lienzo hacia arriba por una sola fila de píxeles:
var canvas = document.createElement(''canvas'');
canvas.width = 1024 * 5;
canvas.height = 1025;
alert(canvas.toDataURL(''image/jpeg''));
// prints "data:," - a broken dataURL
Actualizado el 13/10/2014
Todos los navegadores probados tienen límites para la altura / ancho de los elementos del lienzo, pero muchos navegadores también limitan el área total del elemento del lienzo. Los límites son los siguientes para los navegadores que puedo probar:
Cromo:
Altura / ancho máximo: 32.767 píxeles
Área máxima: 268,435,456 píxeles (p. Ej., 16,384 x 16,384)
Firefox:
Altura / ancho máximo: 32.767 píxeles
Área máxima: 472,907,776 píxeles (p. Ej., 22,528 x 20,992)
ES DECIR:
Altura / ancho máximo: 8.192 píxeles
Área máxima: N / A
IE Mobile:
Altura / ancho máximo: 4.096 píxeles
Área máxima: N / A
Otro:
No puedo probar otros navegadores en este momento. Consulte las otras respuestas en esta página para conocer los límites adicionales.
Exceder la longitud / ancho / área máxima en la mayoría de los navegadores hace que el lienzo no se pueda usar. (Ignorará los comandos de extracción, incluso en el área utilizable). IE e IE Mobile respetarán todos los comandos de extracción dentro del espacio utilizable.
En PC-
No creo que haya una restricción, pero sí se puede salir de la excepción de memoria.
En dispositivos móviles-
Aquí están las restricciones para el lienzo para dispositivos móviles:
El tamaño máximo para un elemento de lienzo es de 3 megapíxeles para dispositivos con menos de 256 MB de RAM y 5 megapíxeles para dispositivos con una memoria RAM mayor o igual a 256 MB.
Por ejemplo, si desea admitir hardware antiguo de Apple, el tamaño de su lienzo no puede exceder 2048 × 1464.
Espero que estos recursos te ayuden a sacarte.