Максимальный размер элемента


Я работаю с элементом canvas высотой от 600 до 1000 пикселей и шириной в несколько десятков или сотен тысяч пикселей. Однако после определенного количества пикселей (очевидно, неизвестных) холст больше не отображает фигуры, которые я рисую с помощью JS.

кто-нибудь знает, есть ли предел? Спасибо.

Edit: протестировано как в Chrome 12, так и в Firefox 4.

13 93

13 ответов:

Обновлено 13.10.2014

все проверенные браузеры имеют ограничения по высоте / ширине элементов canvas, но многие браузеры также ограничивают общую площадь элемента canvas. Ограничения следующие для браузеров, которые я могу проверить:

Chrome:

максимальная высота / ширина: 32 767 пикселей
Максимальная площадь: 268,435,456 пикселей (например, 16,384 x 16,384)

Firefox:

максимальная высота/ширина: 32,767 пиксели
Максимальная площадь: 472,907,776 пикселей (например, 22,528 x 20,992)

IE:

максимальная высота/ширина: 8,192 пикселей
Максимальная площадь: N / A

IE Mobile:

максимальная высота/ширина: 4096 пикселов
Максимальная площадь: N / A

другое:

Я не могу проверить другие браузеры в это время. Дополнительные ограничения см. в других ответах на этой странице.


превышение максимального значения длина / ширина / область в большинстве браузеров делает холст непригодным для использования. (Он будет игнорировать любые команды рисования, даже в полезной области.) IE и IE Mobile будут соблюдать все команды рисования в пределах полезного пространства.

Я столкнулся с ошибками памяти в Firefox с высотой холста более 8000, chrome, похоже, обрабатывает гораздо выше, по крайней мере, до 32000.

EDIT: после запуска еще нескольких тестов, я нашел некоторые очень странные ошибки с Firefox 16.0.2.

во-первых, я, кажется, получаю другое поведение из памяти (созданной в javascript) canvas в отличие от объявленного HTML canvas.

во-вторых, если у вас нет соответствующего тега html и meta charset, то холст может быть ограничено до 8196, в противном случае вы можете перейти к 32767.

В-третьих, если вы получите 2d-контекст холста, а затем измените размер холста, вы также можете быть ограничены 8196. Простая установка размера холста перед захватом 2d-контекста позволяет вам иметь до 32767 без ошибок памяти.

Я не смог последовательно получить ошибки памяти, иногда это только на первой странице загрузки, а затем последующие изменения высоты работы. Это html-файл, который я тестировал сhttp://pastebin.com/zK8nZxdE.

iOS максимальный размер холста (ширина х высота):

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

протестировано в марте 2014 года.

чтобы немного расширить ответ @FredericCharette: Согласно руководство по контенту safari в разделе "знать ограничения ресурсов iOS":

максимальный размер элемента canvas составляет 3 мегапикселя для устройств с оперативной памятью менее 256 МБ и 5 мегапикселей для устройств с оперативной памятью более или равной 256 МБ

пример для 5-мегапиксельного холста (ширина х высота):

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

и так далее..

самые большие квадратные холсты ("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

по данным W3 технические характеристики, интерфейс width/height является беззнаковым длинным - так что от 0 до 4,294,967,295 (если я правильно помню это число-может быть несколько).

EDIT: как ни странно, он говорит unsigned long, но это тестирование показывает только нормальное значение long как max: 2147483647. Jsfiddle - 47 работает, но до 48 и он возвращается к дефолту.

даже если холст позволит вам поставить height=2147483647, когда вы начнете рисовать, ничего не произойдет

рисование происходит только тогда, когда я возвращаю высоту до 32767

iOS имеет различные ограничения.

С помощью симулятора iOS 7 я смог продемонстрировать предел 5 Мб вот так:

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-
Я не думаю, что есть ограничение, Но да, вы можете получить исключение из памяти.

на мобильных устройствах-
Вот ограничения для холста для мобильных устройств: -

максимальный размер элемента canvas составляет 3 мегапикселя для устройств с оперативной памятью менее 256 МБ и 5 мегапикселей для устройств с оперативной памятью более 256 МБ.

Так, например, если вы хотите поддержки Apple старше оборудование, размер вашего холста не может превышать 2048×1464.

надеюсь, что эти ресурсы помогут вам вытащить вас.

ограничения для Safari (все платформы) намного ниже.

известные ограничения iOS / Safari

например, у меня был буфер холста 6400x6400px с данными, нарисованными на нем. Отслеживая / экспортируя контент и тестируя его в других браузерах, я смог увидеть, что все в порядке. Но в Safari он пропустил бы рисование этого конкретного буфера в мой основной контекст.

Я попытался программно выяснить предел: установка размера холста, начиная с 35000, шаг вниз на 100, пока не будет найден допустимый размер. На каждом шаге пишем правый нижний пиксель и затем читаем его. Это работает-с осторожностью.

скорость приемлема, если ширина или высота установлена на некоторое низкое значение (например. 10-200) таким образом: get_max_canvas_size('height', 20).

но если вызывается без ширины или высоты, как get_max_canvas_size(), созданный холст настолько большой, что чтение одного пиксельного цвета очень медленно, и в IE вызывает серьезное зависание.

Если это как тест может быть сделано каким-то образом без чтения значения пикселя, скорость будет приемлемой.

конечно, самый простой способ определить максимальный размер - это какой-то собственный способ запроса максимальной ширины и высоты. Но холст-это "уровень жизни", так что, возможно, когда-нибудь он придет.

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 автоматически добавить столько небольших холстов, сколько необходимо, и нарисовать элементы на соответствующем холсте. В конечном итоге вы все равно можете исчерпать память, но получите вас по одному пределу холста.

Я не знаю, как определить максимальный возможный размер без itteration, но вы можете определить, работает ли данный размер холста, заполнив пиксель, а затем прочитав цвет обратно. Если холст не отображается, то цвет, который вы получите обратно, не будет соответствовать. Вт

частичное код:

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