Dimensione massima di un elemento <canvas>


112

Sto lavorando con un elemento canvas con un'altezza di 600to 1000pixel e una larghezza di diverse decine o centinaia di migliaia di pixel. Tuttavia, dopo un certo numero di pixel (ovviamente sconosciuto), la tela non mostra più le forme che disegno con JS.

Qualcuno sa se c'è un limite?

Testato sia in Chrome 12 che in Firefox 4.


2
@ Šime Ha detto tens OR hundreds of thousands...
Tadeck

6
Anch'io lo vivo. Ho una tela 8000x8000 che funziona bene, ma quando la ingrandisco il contenuto scompare e non si disegna. Le dimensioni a cui non riesce a funzionare sono molto inferiori sul mio iPad. Mi chiedo se sia una limitazione della memoria di qualche tipo.
Joshua

28
È strano quando trovi il tuo commento di 2 anni prima e stai ancora affrontando lo stesso maledetto problema.
Joshua

4
@ Joshua e ancora un anno dopo!
Eugene Yu

1
La domanda è: come faccio a rilevare questi errori, o avvertimenti migliori, quali sono? Non riesco a rilevare l'hardware del dispositivo, quindi devo reagire a un errore.
br4nnigan

Risposte:


115

Aggiornato il 13/10/2014

Tutti i browser testati hanno limiti all'altezza / larghezza degli elementi della tela, ma molti browser limitano anche l'area totale dell'elemento della tela. I limiti sono i seguenti per i browser che posso testare:

Cromo:

Altezza / larghezza massima: 32.767 pixel
Area massima: 268.435.456 pixel (ad es. 16.384 x 16.384)

Firefox:

Altezza / larghezza massima: 32.767 pixel
Area massima: 472.907.776 pixel (ad es. 22.528 x 20.992)

IE:

Altezza / larghezza massima: 8.192 pixel
Area massima: N / A

IE Mobile:

Altezza / larghezza massima: 4.096 pixel
Area massima: N / A

Altro:

Al momento non sono in grado di testare altri browser. Fare riferimento alle altre risposte in questa pagina per ulteriori limiti.


Il superamento della lunghezza / larghezza / area massima sulla maggior parte dei browser rende la tela inutilizzabile. (Ignorerà tutti i comandi di disegno, anche nell'area utilizzabile). IE e IE Mobile rispetteranno tutti i comandi di disegno all'interno dello spazio utilizzabile.


3
Quindi, domanda correlata ... come si fa a aggirare il limite se è necessaria una tela più grande del massimo consentito?
aroth

2
@aroth, ho finito per scrivere un wrapper attorno all'API canvas che utilizzava più <canvas>elementi impilati e applicava automaticamente le istruzioni di disegno al contesto appropriato.
Brandon Gano

1
Sembra molto utile. Non supponi che sia su GitHub?
aroth

5
Safari (versione non iOS) utilizza 32K come Chrome.Firefox. Inoltre, se desideri provare a ricreare un po 'di quel codice wrapper, ho avviato una mia versione open source grazie al misero limite di 8K di IE: github.com/adam-roth/wrapped-canvas
aroth

7
iOS 9.3.1 Safari su iPhone 6 Plus è limitato a un'area di 16777216 pixel (ad esempio, 4096 x 4096). Sospetto che questo sia un numero comune sui dispositivi iOS più recenti
matb33

16

Ho riscontrato errori di memoria insufficiente su Firefox con altezze della tela superiori a 8000, Chrome sembra gestire molto più in alto, almeno fino a 32000.

EDIT: Dopo aver eseguito altri test, ho trovato alcuni errori molto strani con Firefox 16.0.2.

Innanzitutto, mi sembra di ottenere un comportamento diverso dalla tela in memoria (creata in javascript) rispetto alla tela dichiarata html.

Secondo, se non hai il tag html e il meta charset corretti, la tela potrebbe essere limitata a 8196, altrimenti puoi andare fino a 32767.

Terzo, se ottieni il contesto 2d della tela e poi cambi la dimensione della tela, potresti essere limitato anche a 8196. La semplice impostazione della dimensione della tela prima di acquisire il contesto 2d consente di avere fino a 32767 senza ottenere errori di memoria.

Non sono stato in grado di ottenere costantemente gli errori di memoria, a volte è solo al primo caricamento della pagina e quindi i successivi cambiamenti di altezza funzionano. Questo è il file html che stavo testando con http://pastebin.com/zK8nZxdE .


4
"Secondo, se non hai il tag html e il meta charset corretti, il canvas potrebbe essere limitato a 8196, altrimenti puoi arrivare a 32767" - cosa intendi per tag html e meta charset corretti qui?
Jack Aidley

Sicuramente intendi 8192 (2 ^ 13)? 8196 è un numero strano.
jamesdlin

14

Dimensione max canvas iOS (larghezza x altezza):

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

testato a marzo 2014.


Questi valori sono arbitrari. Si prega di consultare il mio post sotto che fa riferimento alla guida ai contenuti del safari
dcbarans

11

Per espandere un po 'la risposta di @FredericCharette: come da guida ai contenuti di safari nella sezione "Conosci i limiti delle risorse iOS":

La dimensione massima di un elemento canvas è di 3 megapixel per i dispositivi con meno di 256 MB di RAM e 5 megapixel per i dispositivi con maggiore o uguale a 256 MB di RAM

Pertanto, qualsiasi variazione di dimensione di 5242880 (5 x 1024 x 1024) pixel funzionerà su dispositivi di memoria di grandi dimensioni, altrimenti è 3145728 pixel.

Esempio per una tela da 5 megapixel (larghezza x altezza):

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

e così via..

Le tele SQUARE più grandi sono ("MiB" = 1024x1024 byte):

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

1
Per essere più precisi, il limite di iPhone5 è 3 * 1024 * 1024 = 3145728 pixel. (Dopo chiedendo perché la mia tela andava bene su Android, ma in bianco su iOS, ho trovato questa risposta, e anche stackoverflow.com/questions/12556198/... e ottenuto il mio PhoneGap app di lavoro.)
Magnus Smith

Cordiali saluti, Apple ha rimosso le informazioni sulle dimensioni specifiche da "Safari / Conosci i limiti delle risorse iOS". Ora è solo un consiglio generico su come ridurre al minimo la larghezza di banda utilizzando immagini di piccole dimensioni.
ToolmakerSteve

@ matb33 ha riportato in un commento alla domanda che iPhone 6 sembra avere un limite di 16 * 1024 * 1024.
ToolmakerSteve

11

Aggiornamento per il 2018:

Con il passare del tempo, i limiti della tela sono cambiati. Purtroppo, ciò che non è cambiato è il fatto che i browser non forniscono ancora informazioni sui limiti delle dimensioni della tela tramite l'API Canvas.

Per coloro che desiderano determinare in modo programmatico la dimensione massima della tela del browser o testare il supporto per le dimensioni della tela personalizzate, controlla le dimensioni della tela .

Dai documenti:

L'elemento HTML canvas è ampiamente supportato dai browser moderni e legacy, ma ogni combinazione di browser e piattaforma impone limiti di dimensione univoci che renderanno inutilizzabile una tela quando superata. Sfortunatamente, i browser non forniscono un modo per determinare quali sono i loro limiti, né forniscono alcun tipo di feedback dopo che è stata creata una tela inutilizzabile. Ciò rende il lavoro con elementi canvas di grandi dimensioni una sfida, soprattutto per le applicazioni che supportano una varietà di browser e piattaforme.

Questa micro-libreria fornisce l'area, l'altezza e la larghezza massime di un elemento canvas HTML supportato dal browser, nonché la possibilità di testare le dimensioni della tela personalizzate. Raccogliendo queste informazioni prima che venga creato un nuovo elemento della tela, le applicazioni sono in grado di impostare in modo affidabile le dimensioni della tela entro i limiti di dimensione di ciascun browser / piattaforma.

Un collegamento demo e i risultati dei test sono disponibili nel README , così come una sezione dei problemi noti che tocca le prestazioni e considerazioni sulla macchina virtuale.

Divulgazione completa, sono l'autore della biblioteca. L'ho creato nel 2014 e recentemente ho rivisitato il codice per un nuovo progetto relativo alla tela. Sono stato sorpreso di trovare la stessa mancanza di strumenti disponibili per rilevare i limiti delle dimensioni della tela nel 2018, quindi ho aggiornato il codice, l'ho rilasciato e spero che aiuti altri a riscontrare problemi simili.


8

Secondo le specifiche w3 , l'interfaccia larghezza / altezza è un long senza segno, quindi da 0 a 4.294.967.295 (se ricordo bene quel numero - potrebbe essere diverso da alcuni).

EDIT: Stranamente, dice unsigned long, ma il test mostra solo un valore lungo normale come il massimo: 2147483647. Jsfiddle - 47 funziona ma fino a 48 e torna al valore predefinito.


Hmm. Interessante, ma non arrivo nemmeno a 1,5 miliardi.
gravidev

Modificato, mi dispiace (questo è quello che ottengo per non aver testato prima) - aggiunto un jsfiddle da mostrare.
WSkid

7

Anche se la tela ti permetterà di mettere altezza = 2147483647, quando inizi a disegnare, non succederà nulla

Il disegno avviene solo quando riporto l'altezza a 32767


7

iOS ha limiti diversi.

Utilizzando il simulatore iOS 7 sono stato in grado di dimostrare che il limite è di 5 MB in questo modo:

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

ma se spingo la dimensione della tela di una singola riga di pixel:

var canvas = document.createElement('canvas');
canvas.width = 1024 * 5;
canvas.height = 1025;
alert(canvas.toDataURL('image/jpeg'));
// prints "data:," - a broken dataURL

2
Non basare tali dati sul simulatore iOS.
Zoltán

5

Su PC
: non penso che ci sia una restrizione ma sì, puoi uscire dall'eccezione della memoria.

Su dispositivi mobili:
ecco le limitazioni per la tela per i dispositivi mobili: -

La dimensione massima per un elemento canvas è di 3 megapixel per i dispositivi con meno di 256 MB di RAM e 5 megapixel per i dispositivi con maggiore o uguale a 256 MB di RAM.

Quindi, ad esempio, se desideri supportare l'hardware precedente di Apple, le dimensioni della tua tela non possono superare 2048 × 1464.

Spero che queste risorse ti aiutino a tirarti fuori.


3

Le limitazioni per Safari (tutte le piattaforme) sono molto inferiori.

Limitazioni note di iOS / Safari

Ad esempio, avevo un buffer canvas 6400x6400px con i dati disegnati su di esso. Tracciando / esportando il contenuto e testando su altri browser, ho potuto vedere che tutto andava bene. Ma su Safari, salterebbe il disegno di questo buffer specifico nel mio contesto principale.


YEEP! Safari salta il disegno della tua tela perché usi una tela più grande come "consentito". Vedi le dimensioni massime che ho pubblicato sopra! È max. canvas su questo safari / dispositivi.
Dado

Le tue dimensioni sono piuttosto arbitrarie, non è vero? Hai qualche documentazione? Qual è stato il tuo processo di test?
NodeNodeNode

3

Ho provato a capire a livello di codice il limite: impostare la dimensione della tela a partire da 35000, scendere di 100 fino a trovare una dimensione valida. In ogni passaggio scrivendo il pixel in basso a destra e poi leggendolo. Funziona con cautela.

La velocità è accettabile se la larghezza o altezza è impostata su un valore basso (ad esempio 10-200.) In questo modo: get_max_canvas_size('height', 20).

Ma se chiamato senza larghezza o altezza come get_max_canvas_size(), la tela creata è così grande che la lettura del colore di un SINGOLO pixel è molto lenta e in IE causa un grave blocco.

Se questo test simile potesse essere eseguito in qualche modo senza leggere il valore dei pixel, la velocità sarebbe accettabile.

Ovviamente il modo più semplice per rilevare la dimensione massima sarebbe un modo nativo per interrogare la larghezza e l'altezza massime. Ma Canvas è "uno standard di vita", quindi potrebbe essere un giorno.

http://jsfiddle.net/timo2012/tcg6363r/2/ (Attenzione! Il tuo browser potrebbe bloccarsi!)

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

2
Ciò sarebbe notevolmente ottimizzato utilizzando en.wikipedia.org/wiki/Exponential_search
Brendan Annable,

1
È davvero folle che il fallimento nel creare una tela così grande sia silenzioso, quindi non c'è modo di rilevarlo ... non è affatto male da parte tua, è solo una cosa folle che i browser ci
saltino

@ColinD Sono d'accordo. Sarebbe solo una piccola informazione da qualche parte. Sarebbe. E dovrebbe.
Timo Kähkönen

3

Quando si utilizzano le tele WebGL, i browser (inclusi quelli desktop) impongono limiti aggiuntivi alla dimensione del buffer sottostante. Anche se la tua tela è grande, ad esempio 16.000x16.000, la maggior parte dei browser renderizza un'immagine più piccola (diciamo 4096x4096) e la ingrandisce. Ciò potrebbe causare brutti pixel, ecc.

Ho scritto del codice per determinare la dimensione massima utilizzando la ricerca esponenziale, se qualcuno ne avesse bisogno. determineMaxCanvasSize()è la funzione che ti interessa.

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

Anche in un jsfiddle https://jsfiddle.net/1sh47wfk/1/


Esiste una documentazione ufficiale sul comportamento di scalabilità verticale?
Magnus Lind Oxlund il

1
@MagnusLindOxlund Le informazioni dalla risposta sono state determinate sperimentalmente. La cosa più vicina che ho trovato dopo una rapida ricerca è questa: khronos.org/registry/webgl/specs/latest/1.0/#2.2 , che dice: "Il vincolo sopra non cambia la quantità di spazio che l'elemento canvas consuma sulla pagina web "quando si parla di limitare la dimensione del buffer di disegno. Sembra che lo standard WebGL non entri nei dettagli folli su come l'elemento canvas dovrebbe visualizzare il buffer di disegno.
Michał

1

Potresti dividerlo e in javascript aggiungere automaticamente tutte le tele più piccole necessarie e disegnare gli elementi sulla tela appropriata. Potresti ancora esaurire la memoria alla fine, ma potresti ottenere il limite di una singola tela.


0

Non so come rilevare la dimensione massima possibile senza itterazione, ma puoi rilevare se una determinata dimensione della tela funziona riempiendo un pixel e quindi rileggendo il colore. Se la tela non è stata renderizzata, il colore restituito non corrisponderà. W

codice parziale:

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.