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

112

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

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

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

серьезный дев
источник
2
@ Šime Он сказал tens OR hundreds of thousands...
Тадек
6
Я тоже это переживаю. У меня есть холст размером 8000x8000, который работает нормально, но когда я увеличиваю его, контент исчезает, и он просто не отображается. Размер, с которым он не работает, на моем iPad намного меньше. Интересно, это какое-то ограничение памяти.
Джошуа
28
Странно, когда вы находите свой собственный комментарий, сделанный двумя годами ранее, и все еще сталкиваетесь с той же чертовой проблемой.
Джошуа
4
@Joshua и еще год спустя!
Eugene Yu
1
Вопрос в том, как мне отловить эти ошибки или, лучше сказать, предупреждения, что это такое? Я не могу обнаружить оборудование устройства, поэтому должен реагировать на ошибку.
br4nnigan 01

Ответы:

115

Обновлено 13.10.2014

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

Хром:

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

Fire Fox:

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

IE:

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

IE Mobile:

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

Другой:

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


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

Брэндон Гано
источник
3
Итак, связанный вопрос ... как можно обойти ограничение, если им нужен холст, размер которого превышает допустимый максимум?
aroth 03
2
@aroth, я закончил тем, что написал оболочку вокруг API холста, которая использовала несколько составных <canvas>элементов и автоматически применяла инструкции рисования к соответствующему контексту.
Брэндон Гано
1
Звучит очень полезно. Не думаете, что это на гитхабе?
aroth 07
5
Safari (версия не для iOS) использует 32K, как Chrome.Firefox. Кроме того, если вы хотите попытаться воссоздать часть этого кода оболочки, я запустил собственную версию с открытым исходным кодом благодаря ничтожному ограничению IE 8K: github.com/adam-roth/wrapped-canvas
aroth
7
iOS 9.3.1 Safari на iPhone 6 Plus ограничена областью 16777216 пикселей (например, 4096 x 4096). Я подозреваю, что это обычное число для новых устройств iOS
matb33
16

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

РЕДАКТИРОВАТЬ: Проведя еще несколько тестов, я обнаружил очень странные ошибки в Firefox 16.0.2.

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

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

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

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

Бен Бернетт
источник
4
«Во-вторых, если у вас нет правильного тега html и мета-кодировки, холст может быть ограничен до 8196, иначе вы можете подняться до 32767» - что вы имеете в виду под правильным тегом html и мета-кодировкой здесь?
Джек Эйдли,
Неужто вы имеете ввиду 8192 (2 ^ 13)? 8196 - странное число.
jamesdlin
14

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

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

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

Дадо
источник
Эти значения произвольны. Пожалуйста, посмотрите мой пост, который ссылается на руководство по сафари,
dcbarans
11

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

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

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

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

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
dcbarans
источник
1
Чтобы быть более конкретным, ограничение iPhone5 составляет 3 * 1024 * 1024 = 3145728 пикселей. (После того, как я поинтересовался, почему мой холст в порядке на Android, но пуст на iOS, я нашел этот ответ, а также stackoverflow.com/questions/12556198/… и заставил мое приложение Phonegap работать.)
Магнус Смит
К вашему сведению, Apple удалила информацию о конкретном размере из «Safari / Know iOS Resource Limits». Теперь это просто общий совет по минимизации пропускной способности за счет использования небольших изображений.
ToolmakerSteve
@ matb33 сообщил в комментарии по этому вопросу , что iPhone 6 по- видимому, предел 16 * 1024 * 1024.
ToolmakerSteve
11

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

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

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

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

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

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

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

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

jhildenbiddle
источник
8

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

РЕДАКТИРОВАТЬ: Как ни странно, он говорит, что unsigned long, но тестирование показывает только нормальное длинное значение как max: 2147483647. Jsfiddle - 47 работает, но до 48, и он возвращается к значению по умолчанию.

WSkid
источник
Хм. Интересно, но я даже не добрался до 1,5 миллиарда.
серьезный дев
Отредактировано, извините (это то, что я получил, что сначала не тестировал) - добавил jsfiddle для отображения.
WSkid
7

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

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

avikaza123
источник
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
Мэтт Бернс
источник
2
Вы не должны основывать такие данные на симуляторе iOS.
Золтан
5

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

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

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

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

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

Маниш Гупта
источник
3

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

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

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

Узел Узел
источник
Ага! Safari пропускает рисование вашего холста, потому что вы используете больший холст как «разрешенный». Смотрите максимальные размеры, которые я опубликовал выше! Это макс. холст на этом сафари / устройствах.
Дадо
Ваши размеры довольно произвольны, не так ли? У вас есть документация? Каков был ваш процесс тестирования?
NodeNodeNode
3

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

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

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

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

Конечно, самый простой способ определить максимальный размер - это какой-нибудь собственный способ запросить максимальную ширину и высоту. Но Canvas - это «уровень жизни», так что может быть, когда-нибудь он появится.

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;
  }
}
Тимо Кяхконен
источник
2
Это можно было бы значительно оптимизировать, используя en.wikipedia.org/wiki/Exponential_search
Брендан Эннэйбл,
1
Это действительно безумие, что неудача при создании такого большого холста молчит, поэтому нет никакого способа обнаружить ... неплохо с вашей стороны, это просто безумие для браузеров, которые нападают на нас
Колин Д.
@ColinD Я согласен. Это была бы всего лишь небольшая часть информации. Было бы. И должен.
Timo Kähkönen
3

Когда вы используете полотна 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/

Михал
источник
Есть ли официальная документация по поведению при масштабировании?
Магнус Линд Оклунд,
1
@MagnusLindOxlund Информация из ответа была определена экспериментально. Ближайшее, что я нашел после быстрого поиска, это: khronos.org/registry/webgl/specs/latest/1.0/#2.2 , в котором говорится: «Указанное выше ограничение не меняет количество места, которое элемент холста занимает на веб-странице. "когда речь идет об ограничении размера буфера рисования. Кажется, что стандарт WebGL не вдавался в сумасшедшие подробности того, как элемент холста должен отображать буфер рисования.
Michał
1

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

JJ_Coder4Hire
источник
0

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

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

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);
Системный
источник