Tamanho máximo de um elemento <canvas>

112

Estou trabalhando com um elemento de tela com altura de 600a 1000pixels e largura de várias dezenas ou centenas de milhares de pixels. No entanto, após um certo número de pixels (obviamente desconhecido), a tela não exibe mais as formas que desenho com JS.

Alguém sabe se existe um limite?

Testado no Chrome 12 e Firefox 4.

seriousdev
fonte
2
@ Šime Ele disse tens OR hundreds of thousands...
Tadeck
6
Eu também experimento isso. Eu tenho uma tela de 8000x8000 que funciona bem, mas quando eu a aumento, o conteúdo desaparece e simplesmente não desenha. O tamanho que ele deixa de funcionar é muito menor no meu iPad. Eu me pergunto se é algum tipo de limitação de memória.
Joshua
28
É estranho quando você encontra seu próprio comentário de 2 anos antes e ainda está lidando com o mesmo problema.
Josué
4
@Joshua e ainda um ano depois!
Eugene Yu
1
A questão é como faço para detectar esses erros, ou melhor, avisos, quais são eles? Não consigo detectar o hardware do dispositivo, então tenho que reagir a um erro.
br4nnigan 01 de

Respostas:

115

Atualizado em 13/10/2014

Todos os navegadores testados têm limites para a altura / largura dos elementos da tela, mas muitos navegadores também limitam a área total do elemento da tela. Os limites são os seguintes para os navegadores que posso testar:

Cromada:

Altura / largura máxima: 32.767 pixels
Área máxima: 268.435.456 pixels (por exemplo, 16.384 x 16.384)

Raposa de fogo:

Altura / largura máxima: 32.767 pixels
Área máxima: 472.907.776 pixels (por exemplo, 22.528 x 20.992)

IE:

Altura / largura máxima: 8.192 pixels
Área máxima: N / A

IE Mobile:

Altura / largura máxima: 4.096 pixels
Área máxima: N / A

De outros:

Não consigo testar outros navegadores neste momento. Consulte as outras respostas nesta página para limites adicionais.


Exceder o comprimento / largura / área máxima na maioria dos navegadores torna a tela inutilizável. (Ele irá ignorar todos os comandos de desenho, mesmo na área utilizável.) O IE e o IE Mobile honrarão todos os comandos de desenho dentro do espaço utilizável.

Brandon Gano
fonte
3
Então, questão relacionada ... como alguém contorna o limite se precisa de uma tela maior do que o máximo permitido?
aroth
2
@aroth, acabei escrevendo um wrapper em torno da API do canvas que usava vários <canvas>elementos empilhados e aplicava automaticamente as instruções de desenho ao contexto apropriado.
Brandon Gano,
1
Parece muito útil. Não acho que está no github?
aroth
5
Safari (versão não iOS) usa 32K como Chrome.Firefox. Além disso, se você quiser tentar recriar parte do código do wrapper, comecei uma versão de código aberto minha, graças ao limitado limite de 8K do IE: github.com/adam-roth/wrapped-canvas
aroth
7
O iOS 9.3.1 Safari em um iPhone 6 Plus está limitado a uma área de 16777216 pixels (por exemplo, 4096 x 4096). Suspeito que este seja um número comum em dispositivos iOS mais recentes
matb33
16

Encontrei erros de falta de memória no Firefox com alturas de tela superiores a 8000, o cromo parece lidar com muito mais, pelo menos até 32000.

EDIT: Depois de executar mais alguns testes, encontrei alguns erros muito estranhos com o Firefox 16.0.2.

Primeiro, parece que obtenho um comportamento diferente da tela na memória (criada em javascript) em oposição à tela declarada em html.

Em segundo lugar, se você não tiver a tag html e o meta charset adequados, a tela pode ser restrita a 8196, caso contrário, você pode ir até 32767.

Terceiro, se você obtiver o contexto 2d da tela e, em seguida, alterar o tamanho da tela, poderá ficar restrito a 8196 também. Simplesmente definir o tamanho da tela antes de pegar o contexto 2d permite que você tenha até 32767 sem obter erros de memória.

Não tenho conseguido obter consistentemente os erros de memória, às vezes é apenas no carregamento da primeira página e, em seguida, as alterações de altura subsequentes funcionam. Este é o arquivo html que estava testando com http://pastebin.com/zK8nZxdE .

Ben Burnett
fonte
4
"Em segundo lugar, se você não tiver a tag html e o meta charset adequados, a tela pode ser restrita a 8196, caso contrário, você pode ir até 32767" - o que você quer dizer com tag html e meta charset adequados aqui?
Jack Aidley de
Certamente você quer dizer 8192 (2 ^ 13)? 8196 é um número estranho.
Jamesdlin de
14

Tamanho máximo da tela do iOS (largura x altura):

 iPod Touch 16GB = 1448x1448
 iPad Mini       = 2290x2289
 iPhone 3        = 1448x1448
 iPhone 5        = 2290x2289

testado em março de 2014.

Dado
fonte
Esses valores são arbitrários. Por favor, veja minha postagem abaixo, que faz referência ao guia de conteúdo do safari
dcbarans
11

Para expandir um pouco a resposta de @FredericCharette: De acordo com o guia de conteúdo do safari na seção "Conheça os limites de recursos do iOS":

O tamanho máximo para um elemento de tela é de 3 megapixels para dispositivos com menos de 256 MB de RAM e 5 megapixels para dispositivos com mais ou igual a 256 MB de RAM

Portanto, qualquer variação de tamanho de 5242880 (5 x 1024 x 1024) pixels funcionará em dispositivos de memória grande, caso contrário, são 3145728 pixels.

Exemplo para tela de 5 megapixels (largura x altura):

Any total <= 5242880
--------------------
5 x 1048576 ~= 5MP   (1048576 = 1024 x 1024)
50 x 104857 ~= 5MP
500 x 10485 ~= 5MP

e assim por diante..

As maiores telas SQUARE são ("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
dcbarans
fonte
1
Para ser mais específico, o limite do iPhone5 é 3 * 1024 * 1024 = 3145728 pixels. (Depois de me perguntar por que minha tela estava boa no Android, mas em branco no iOS, encontrei esta resposta, e também stackoverflow.com/questions/12556198/… e fiz meu aplicativo Phonegap funcionar.)
Magnus Smith
Para sua informação, a Apple removeu informações de tamanho específico de "Safari / Know iOS Resource Limits". Agora, é apenas um conselho genérico sobre como minimizar a largura de banda usando imagens pequenas.
Toolmaker Steve
@ matb33 relatou em um comentário sobre a questão que o iPhone 6 parece ter o limite de 16 * 1024 * 1024.
ToolmakerSteve
11

Atualização para 2018:

Conforme o tempo passa, as limitações do canvas mudaram. Infelizmente, o que não mudou é o fato de que o navegador ainda não fornece informações sobre as limitações de tamanho da tela por meio da API Canvas.

Para aqueles que procuram determinar programaticamente o tamanho máximo da tela do navegador ou testar o suporte para dimensões personalizadas da tela, verifique o tamanho da tela .

Dos documentos:

O elemento canvas HTML é amplamente suportado por navegadores modernos e legados, mas cada combinação de navegador e plataforma impõe limitações de tamanho exclusivas que tornarão uma tela inutilizável quando excedida. Infelizmente, os navegadores não fornecem uma maneira de determinar quais são suas limitações, nem fornecem qualquer tipo de feedback após a criação de uma tela inutilizável. Isso torna o trabalho com grandes elementos de tela um desafio, especialmente para aplicativos que oferecem suporte a uma variedade de navegadores e plataformas.

Esta microbiblioteca fornece a área, altura e largura máximas de um elemento de tela HTML suportado pelo navegador, bem como a capacidade de testar dimensões de tela personalizadas. Ao coletar essas informações antes de um novo elemento de tela ser criado, os aplicativos são capazes de definir as dimensões da tela de forma confiável dentro das limitações de tamanho de cada navegador / plataforma.

Um link de demonstração e resultados de teste estão disponíveis no README , bem como uma seção de problemas conhecidos que aborda o desempenho e as considerações da máquina virtual.

Divulgação completa, sou o autor da biblioteca. Eu o criei em 2014 e recentemente revisitei o código de um novo projeto relacionado ao canvas. Fiquei surpreso ao descobrir a mesma falta de ferramentas disponíveis para detectar limitações de tamanho da tela em 2018, então atualizei o código, lancei-o e espero que ajude outras pessoas que enfrentam problemas semelhantes.

jhildenbiddle
fonte
8

De acordo com as especificações do w3 , a interface de largura / altura é um longo sem sinal - portanto, de 0 a 4.294.967.295 (se bem me lembro desse número - pode estar um pouco diferente).

EDIT: Estranhamente, diz sem sinal longo, mas o teste mostra apenas um valor longo normal como o máximo: 2147483647. Jsfiddle - 47 funciona, mas até 48 e ele reverte para o padrão.

WSkid
fonte
Hmm. Interessante, mas não chego nem a 1,5 bilhão.
seriousdev
Editado, desculpe (isso é o que eu ganho por não testar primeiro) - adicionado um jsfiddle para mostrar.
WSkid
7

Mesmo que a tela permita que você coloque height = 2147483647, quando você começar a desenhar, nada acontecerá

O desenho só acontece quando eu trago a altura de volta para 32.767

avikaza123
fonte
7

iOS tem limites diferentes.

Usando o simulador iOS 7, consegui demonstrar que o limite é de 5 MB assim:

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

mas se eu aumentar o tamanho da tela em uma única linha de pixels:

var canvas = document.createElement('canvas');
canvas.width = 1024 * 5;
canvas.height = 1025;
alert(canvas.toDataURL('image/jpeg'));
// prints "data:," - a broken dataURL
matt burns
fonte
2
Você não deve basear esses dados no simulador iOS.
Zoltán
5

No PC
- não acho que haja uma restrição, mas sim, você pode obter exceção de memória insuficiente.

Em dispositivos móveis -
Aqui estão as restrições para a tela para dispositivos móveis: -

O tamanho máximo de um elemento de tela é de 3 megapixels para dispositivos com menos de 256 MB de RAM e 5 megapixels para dispositivos com mais ou igual a 256 MB de RAM.

Então, por exemplo - se você deseja oferecer suporte ao hardware mais antigo da Apple, o tamanho da sua tela não pode exceder 2048 × 1464.

Espero que esses recursos ajudem você a se destacar.

Manish Gupta
fonte
3

As limitações do Safari (todas as plataformas) são muito menores.

Limitações conhecidas de iOS / Safari

Por exemplo, eu tinha um buffer de tela de 6400x6400px com dados desenhados nele. Rastreando / exportando o conteúdo e testando em outros navegadores, pude ver que tudo estava bem. Mas no Safari, ele pularia o desenho desse buffer específico no meu contexto principal.

NodeNodeNode
fonte
Sim! O Safari pula o desenho da tela porque você usa telas maiores como "permitido". Veja as dimensões máximas que postei acima! Isso é max. tela neste safari / dispositivos.
Dado
Seus tamanhos são bastante arbitrários, não são? Você tem alguma documentação? Qual foi o seu processo de teste?
NodeNodeNode
3

Tentei descobrir o limite de forma programática: definir o tamanho da tela a partir de 35000, diminuindo em 100 até que o tamanho válido seja encontrado. Em cada etapa, escreva o pixel inferior direito e depois o leia. Funciona - com cautela.

A velocidade é aceitável se qualquer largura ou altura é ajustado para um valor baixo (por exemplo, 10-200.) Desta maneira: get_max_canvas_size('height', 20).

Mas se chamado sem largura ou altura como get_max_canvas_size(), a tela criada é tão grande que ler a cor de UM ÚNICO pixel é muito lento, e no IE causa sérios travamentos.

Se esse teste pudesse ser feito de alguma forma sem ler o valor do pixel, a velocidade seria aceitável.

É claro que a maneira mais fácil de detectar o tamanho máximo seria alguma forma nativa de consultar a largura e altura máximas. Mas o Canvas é 'um padrão de vida', então pode ser que venha algum dia.

http://jsfiddle.net/timo2012/tcg6363r/2/ (Cuidado! Seu navegador pode travar!)

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;
  }
}
Timo Kähkönen
fonte
2
Isso seria bastante otimizado usando en.wikipedia.org/wiki/Exponential_search
Brendan Annable
1
É realmente insano que o fracasso em criar uma tela tão grande seja silencioso, então não há como detectar ... nada mal de sua parte, é simplesmente uma loucura os navegadores saltarem sobre nós
Colin D
@ColinD eu concordo. Seria apenas um pequeno pedaço de informação em algum lugar. Seria. E deveria.
Timo Kähkönen
3

Quando você usa telas WebGL, os navegadores (incluindo os de desktop) impõem limites extras ao tamanho do buffer subjacente. Mesmo se sua tela for grande, por exemplo, 16.000 x 16.000, a maioria dos navegadores renderizará uma imagem menor (digamos 4096x4096) e aumentará sua escala. Isso pode causar pixelização feia, etc.

Eu escrevi um código para determinar o tamanho máximo usando a pesquisa exponencial, se alguém precisar. determineMaxCanvasSize()é a função na qual você está interessado.

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];
}

Também em um jsfiddle https://jsfiddle.net/1sh47wfk/1/

Michał
fonte
Existe alguma documentação oficial sobre o comportamento de aumento de escala?
Magnus Lind Oxlund
1
@MagnusLindOxlund A informação da resposta foi determinada experimentalmente. A coisa mais próxima que encontrei depois de uma pesquisa rápida é: khronos.org/registry/webgl/specs/latest/1.0/#2.2 , dizendo: "A restrição acima não altera a quantidade de espaço que o elemento canvas consome na página da web "quando se fala em limitar o tamanho do buffer de desenho. Parece que o padrão WebGL não entra em detalhes malucos sobre como o elemento canvas deve exibir o buffer de desenho.
Michał
1

Você pode fragmentá-lo e, em javascript, adicionar automaticamente quantas telas menores forem necessárias e desenhar os elementos na tela apropriada. Você ainda pode ficar sem memória eventualmente, mas o levaria pelo limite de tela única.

JJ_Coder4Hire
fonte
0

Não sei como detectar o tamanho máximo possível sem itteração, mas você pode detectar se um determinado tamanho de tela funciona preenchendo um pixel e, em seguida, lendo a cor de volta. Se a tela não foi renderizada, a cor que você receber não será compatível. 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);
SystemicPlural
fonte