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

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

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

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

Ответ 1

Обновлено 10/13/2014

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

Chrome:

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

Firefox:

Максимальная высота/ширина: 32 767 пикселей

IE:

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

IE Mobile:

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

Другое:

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


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

Ответ 2

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

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

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

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

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

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

Ответ 3

Размер холста iOS max (ширина x высота):

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

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

Ответ 4

Чтобы немного расширить ответ @FredericCharette: По руководство по содержанию сафари в разделе "Знать ограничения ресурсов iOS":

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

Поэтому любое изменение размера пикселей 5242880 (5 x 1024 x 1024) будет работать на больших устройствах памяти, в противном случае это 3145728 пикселей.

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

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

и т.д.

Крупнейшие холсты CQUARE ( "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

Ответ 5

В соответствии с спецификациями w3 интерфейс ширины/высоты является unsigned long - так от 0 до 4,294,967,295 (если я помню, что число справа - может быть от нескольких).

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

На ПК -
Я не думаю, что есть ограничение, но да, вы можете получить исключение из памяти.

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

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

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

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

Ответ 9

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

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

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

Ответ 10

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

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

Но если вызывается без ширины или высоты, например, get_max_canvas_size(), созданный холст настолько велик, что чтение SINGLE пиксельного цвета происходит очень медленно, а в 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;
  }
}

Ответ 11

Когда вы используете полотна WebGL, браузеры (включая настольные) будут накладывать дополнительные ограничения на размер нижележащего буфера. Даже если ваш холст большой, например, 16 000 x 16 000, большинство браузеров отрисовывают картинку меньшего размера (скажем, 4096 x 4096) и масштабируют ее. Это может вызвать уродливое пикселирование и т.д.

Я написал некоторый код для определения этого максимального размера с помощью экспоненциального поиска, если кому-то это понадобится. 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/

Ответ 12

Обновление для 2018 года:

С течением времени ограничения холста изменились. К сожалению, что не изменилось, так это то, что браузер по-прежнему не предоставляет информацию об ограничениях размера холста через Canvas API.

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

Из документов:

Элемент HTML-холста широко поддерживается современными и устаревшими браузерами, но каждая комбинация браузера и платформы накладывает уникальные ограничения по размеру, что делает холст непригодным для использования при превышении. К сожалению, браузеры не обеспечивают способ определения их ограничений, а также не предоставляют никакой обратной связи после создания непригодного холста. Это затрудняет работу с большими элементами canvas, особенно для приложений, которые поддерживают различные браузеры и платформы.

Эта микробиблиотека предоставляет максимальную площадь, высоту и ширину элемента холста HTML, поддерживаемого браузером, а также возможность проверки пользовательских размеров холста. Собирая эту информацию перед созданием нового элемента canvas, приложения могут надежно устанавливать размеры холста в пределах ограничений размера каждого браузера/платформы.

Демонстрационная ссылка и результаты тестирования доступны в README, а также в разделе об известных проблемах, который затрагивает вопросы производительности и виртуальной машины.

Полное раскрытие, я автор библиотеки. Я создал его в 2014 году и недавно пересмотрел код для нового проекта, связанного с холстом. Я был удивлен, обнаружив то же отсутствие доступных инструментов для определения ограничений размера холста в 2018 году, поэтому я обновил код, выпустил его и надеюсь, что он поможет другим столкнуться с подобными проблемами.

Ответ 13

Вы можете его обрезать, а в javascript автоматически добавить столько маленьких холстов, сколько необходимо, и нарисовать элементы на соответствующем холсте. В конечном итоге у вас может быть нехватка памяти, но вы получите единственный предел холста.

Ответ 14

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

частичный код:

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