web-dev-qa-db-fra.com

Taille maximale d'un élément <canvas>

Je travaille avec un élément canvas d'une hauteur de 600 à 1000 pixels et une largeur de plusieurs dizaines ou centaines de milliers de pixels. Cependant, après un certain nombre de pixels (évidemment inconnu), le canevas n'affiche plus les formes que je dessine avec JS.

Est-ce que quelqu'un sait s'il y a une limite?

Testé à la fois dans Chrome 12 et Firefox 4.

103
seriousdev

Mise à jour le 13/10/2014

Tous les navigateurs testés ont des limites en hauteur/largeur des éléments de la toile, mais de nombreux navigateurs limitent également la surface totale de l'élément de la toile. Les limites sont les suivantes pour les navigateurs que je peux tester:

Chrome:

Hauteur/largeur maximale: 32 767 pixels
Surface maximale: 268 435 456 pixels (par exemple, 16 384 x 16 384)

Firefox:

Hauteur/largeur maximale: 32 767 pixels
Surface maximale: 472 907 776 pixels (par exemple, 22 528 x 20 992)

C'EST À DIRE:

Hauteur/largeur maximale: 8 192 pixels
Surface maximale: N/A

IE Mobile:

Hauteur/largeur maximale: 4 096 pixels
Surface maximale: N/A

Autre:

Je ne suis pas en mesure de tester d'autres navigateurs pour le moment. Reportez-vous aux autres réponses sur cette page pour connaître les limites supplémentaires.


Dépasser la longueur/largeur/zone maximale sur la plupart des navigateurs rend le canevas inutilisable. (Il ignorera toutes les commandes de tirage, même dans la zone utilisable.) IE et IE Mobile honorera toutes les commandes de tirage situées dans l'espace utilisable.

107
Brandon Gano

J'ai rencontré des erreurs de mémoire sur Firefox avec des hauteurs de toile supérieures à 8000, chrome semble traiter beaucoup plus haut, au moins jusqu'à 32000.

EDIT: Après avoir exécuté quelques tests supplémentaires, j'ai trouvé des erreurs très étranges avec Firefox 16.0.2.

Premièrement, il semble que je perçois un comportement différent du canevas en mémoire (créé en javascript) par opposition au canevas html déclaré.

Deuxièmement, si vous ne possédez pas les balises html et méta charset appropriés, le canevas peut être limité à 8196, sinon vous pouvez aller jusqu'à 32767.

Troisièmement, si vous obtenez le contexte 2d de la toile et que vous modifiez ensuite la taille de la toile, vous pouvez également être limité à 8196. Le simple fait de définir la taille de la zone de dessin avant de saisir le contexte 2d vous permet d’en avoir jusqu’à 32767 sans erreurs de mémoire.

Je n'ai pas réussi à obtenir systématiquement les erreurs de mémoire. Parfois, ce n'est que lors du chargement de la première page, puis les changements de hauteur ultérieurs fonctionnent. C’est le fichier html avec lequel j’ai testé http://Pastebin.com/zK8nZxdE .

16
Ben Burnett

taille maximale de la toile iOS (largeur x hauteur):

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

testé en mars 2014.

14
Dado

Pour approfondir un peu @FredericCharette, répondez: Voir guide de contenu de safari sous la rubrique "Connaître les limites des ressources iOS":

La taille maximale d'un élément de structure est de 3 mégapixels pour les périphériques de moins de 256 Mo RAM) et de 5 mégapixels pour les périphériques de 256 Mo ou plus.

Par conséquent, toute variation de taille de 5242880 (5 x 1024 x 1024) pixels fonctionnera sur les grands dispositifs de mémoire; sinon, elle correspond à 3145728 pixels.

Exemple pour une toile de 5 mégapixels (largeur x hauteur):

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

etc..

Les plus grandes toiles SQUARE sont ("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
11
dcbarans

iOS a des limites différentes.

En utilisant le simulateur iOS 7, j'ai pu démontrer que la limite est de 5 Mo comme ceci:

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

mais si je décale la taille de la toile d'une rangée unique de pixels:

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

Même si la toile vous permet de mettre une hauteur = 2147483647, lorsque vous commencez à dessiner, rien ne se passe

Le dessin ne se produit que lorsque je ramène la hauteur à 32767

7
avikaza123

Selon w3 specs , l'interface largeur/hauteur est un long non signé - donc 0 à 4 294 967 295 (si je me souviens bien de ce nombre - pourrait en être un petit peu).

EDIT: Étrangement, le mot non signé est long, mais les tests montrent une valeur longue normale, le maximum: 2147483647. Jsfiddle - 47 fonctionne mais jusqu'à 48 et revient à la valeur par défaut.

7
WSkid

sur PC -
Je ne pense pas qu'il y ait une restriction mais oui, vous pouvez avoir une exception de mémoire insuffisante.

Sur les appareils mobiles -
Voici les restrictions applicables au canevas pour appareils mobiles: -

La taille maximale d'un élément de structure est de 3 mégapixels pour les périphériques de moins de 256 Mo RAM) et de 5 mégapixels pour les périphériques de 256 Mo ou plus.

Ainsi, par exemple, si vous souhaitez prendre en charge le matériel ancien d’Apple, la taille de votre canevas ne peut pas dépasser 2048 × 1464.

J'espère que ces ressources vous aideront à vous sortir.

5
Manish Gupta

Mise à jour pour 2018:

Au fil du temps, les limites de la toile ont changé. Malheureusement, ce qui n'a pas changé, c'est le fait que le navigateur ne fournit toujours pas d'informations sur les limitations de taille de la toile à travers l'API Canvas.

Pour ceux qui cherchent à déterminer par programme la taille maximale de la toile du navigateur ou à tester la prise en charge des dimensions de toile personnalisées, consultez canvas-size .

De la docs:

L'élément canvas HTML est largement pris en charge par les navigateurs modernes et traditionnels, mais chaque combinaison de navigateur et de plate-forme impose des limitations de taille uniques qui rendront un canevas inutilisable en cas de dépassement. Malheureusement, les navigateurs ne permettent pas de déterminer quelles sont leurs limites, et ils ne fournissent aucun type de retour après la création d’un canevas inutilisable. Cela rend le travail avec de grands éléments de canevas un défi, en particulier pour les applications prenant en charge une variété de navigateurs et de plates-formes.

Cette micro-bibliothèque fournit la surface, la hauteur et la largeur maximales d'un élément de canevas HTML pris en charge par le navigateur, ainsi que la possibilité de tester les dimensions personnalisées du canevas. En collectant ces informations avant la création d'un nouvel élément de zone de dessin, les applications peuvent définir de manière fiable les dimensions de la zone de travail dans les limites de taille de chaque navigateur/plate-forme.

Un lien de démonstration et résultats des tests sont disponibles dans le fichier README , ainsi qu'une section problèmes connus qui touche aux performances et aux considérations de machine virtuelle.

Divulgation complète, je suis l'auteur de la bibliothèque. Je l'ai créé en 2014 et j'ai récemment revu le code d'un nouveau projet lié à la toile. J'ai été surpris de constater le même manque d'outils disponibles pour détecter les limitations de taille de la zone de travail en 2018; j'ai donc mis à jour et publié le code, et j'espère que cela aidera les autres à rencontrer des problèmes similaires.

5
jhildenbiddle

Les limitations pour Safari (toutes les plateformes) sont beaucoup plus basses.

Limitations connues iOS/Safari

Par exemple, j'avais un tampon canevas de 6400x6400px avec des données dessinées dessus. En traçant/exportant le contenu et en testant sur d'autres navigateurs, j'ai pu constater que tout allait bien. Mais sur Safari, le dessin de ce tampon spécifique serait ignoré dans mon contexte principal.

3
Frederic Charette

Lorsque vous utilisez des toiles WebGL, les navigateurs (y compris ceux du bureau) imposent des limites supplémentaires à la taille du tampon sous-jacent. Même si votre toile est grande, par exemple 16 000 x 16 000, la plupart des navigateurs affichent une image plus petite (par exemple, 4096 x 4096) et l’agrandissent. Cela pourrait causer la pixelisation laide, etc.

J'ai écrit du code pour déterminer cette taille maximale à l'aide d'une recherche exponentielle, si jamais quelqu'un en avait besoin. determineMaxCanvasSize() est la fonction qui vous intéresse.

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

Aussi dans un jsfiddle https://jsfiddle.net/1sh47wfk/1/

3
Michał

J'ai essayé de déterminer par programme la limite: définir la taille de la zone de travail à partir de 35 000, en diminuant de 100 jusqu'à ce qu'une taille valide soit trouvée. A chaque étape, écrivez le pixel en bas à droite, puis lisez-le. Cela fonctionne - avec prudence.

La vitesse est acceptable si largeur ou hauteur est réglé sur une valeur faible (par exemple 10-200) de cette façon: get_max_canvas_size('height', 20).

Mais si elle est appelée sans largeur ni hauteur comme get_max_canvas_size(), la zone de travail créée est si grande que la lecture d'une couleur de pixel SINGLE est très lente et que IE provoque un blocage important.

Si ce test similaire pouvait être effectué sans lire la valeur de pixel, la vitesse serait acceptable.

Bien sûr, le moyen le plus simple de détecter la taille maximale serait un moyen natif d'interroger la largeur et la hauteur maximales. Mais Canvas est un "standard de vie", il se peut donc qu’il arrive un jour.

http://jsfiddle.net/timo2012/tcg6363r/2/ (Attention! Votre navigateur peut se bloquer!)

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;
  }
}
3
Timo Kähkönen

Vous pouvez le découper et ajouter automatiquement dans javascript autant de petites toiles que nécessaire et dessiner les éléments sur le canevas approprié. Il se peut que vous manquiez toujours de mémoire, mais vous ne rencontriez qu'une seule limite.

1
JJ_Coder4Hire

Je ne sais pas comment détecter la taille maximale possible sans itérer, mais vous pouvez déterminer si une taille de toile donnée fonctionne en remplissant un pixel, puis en relisant la couleur. Si le canevas n'a pas rendu, la couleur que vous récupérez ne correspondra pas. W

code partiel:

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);
0
SystemicPlural