Kích thước tối đa của phần tử <canvas>


112

Tôi đang làm việc với một phần tử canvas có chiều cao 600tới 1000pixel và chiều rộng là vài chục hoặc hàng trăm nghìn pixel. Tuy nhiên, sau một số pixel nhất định (rõ ràng là không xác định), canvas không còn hiển thị các hình dạng tôi vẽ bằng JS nữa.

Có ai biết nếu có một giới hạn?

Đã thử nghiệm cả trong Chrome 12 và Firefox 4.


2
@ Šime Anh ấy nói tens OR hundreds of thousands...
Tadeck

6
Tôi cũng trải qua điều này. Tôi có một canvas 8000x8000 hoạt động tốt, nhưng khi tôi làm cho nó lớn hơn, nội dung sẽ biến mất và nó sẽ không vẽ. Kích thước mà nó không hoạt động thấp hơn rất nhiều trên iPad của tôi. Tôi tự hỏi liệu nó có phải là một giới hạn bộ nhớ của một số loại.
Joshua

28
Thật kỳ lạ khi bạn tìm thấy nhận xét của chính mình từ 2 năm trước và bạn vẫn đang giải quyết cùng một vấn đề tồi tệ.
Joshua

4
@Joshua và một năm sau vẫn vậy!
Eugene Yu

1
Câu hỏi đặt ra là làm cách nào để tôi bắt được những lỗi này, hoặc những cảnh báo tốt hơn, đó là những gì? Tôi không thể phát hiện phần cứng của thiết bị, vì vậy tôi phải xử lý lỗi.
br4nnigan

Câu trả lời:


115

Cập nhật 13/10/2014

Tất cả các trình duyệt được thử nghiệm đều có giới hạn về chiều cao / chiều rộng của phần tử canvas, nhưng nhiều trình duyệt cũng giới hạn tổng diện tích của phần tử canvas. Các giới hạn như sau đối với các trình duyệt mà tôi có thể kiểm tra:

Trình duyệt Chrome:

Chiều cao / chiều rộng tối đa: 32.767 pixel
Diện tích tối đa: 268.435.456 pixel (ví dụ: 16.384 x 16.384)

Firefox:

Chiều cao / chiều rộng tối đa: 32.767 pixel
Diện tích tối đa: 472.907.776 pixel (ví dụ: 22.528 x 20.992)

I E:

Chiều cao / chiều rộng tối đa: 8.192 pixel
Diện tích tối đa: N / A

IE Mobile:

Chiều cao / chiều rộng tối đa: 4.096 pixel
Diện tích tối đa: N / A

Khác:

Tôi không thể kiểm tra các trình duyệt khác vào lúc này. Tham khảo các câu trả lời khác trên trang này để biết thêm các giới hạn.


Vượt quá chiều dài / chiều rộng / diện tích tối đa trên hầu hết các trình duyệt khiến canvas không thể sử dụng được. (Nó sẽ bỏ qua bất kỳ lệnh vẽ nào, ngay cả trong vùng có thể sử dụng.) IE và IE Mobile sẽ tôn trọng tất cả các lệnh vẽ trong vùng có thể sử dụng.


3
Vì vậy, câu hỏi liên quan ... làm thế nào một người làm việc xung quanh giới hạn nếu họ cần một canvas lớn hơn mức tối đa cho phép?
aroth

2
@aroth, tôi đã kết thúc việc viết một trình bao quanh API canvas sử dụng nhiều <canvas>phần tử xếp chồng lên nhau và tự động áp dụng các hướng dẫn vẽ cho ngữ cảnh thích hợp.
Brandon ga

1
Nghe rất hữu ích. Đừng cho rằng nó trên github?
aroth

5
Safari (phiên bản không phải iOS) sử dụng 32K giống như Chrome.Firefox. Ngoài ra, nếu bạn muốn thử tạo lại một số mã trình bao bọc đó, tôi đã bắt đầu một phiên bản mã nguồn mở của riêng mình nhờ vào giới hạn 8K nhỏ bé của IE: github.com/adam-roth/wrapped-canvas
aroth

7
iOS 9.3.1 Safari trên iPhone 6 Plus bị giới hạn trong một vùng là 16777216 pixel (ví dụ: 4096 x 4096). Tôi nghi ngờ đây là một con số phổ biến trên các thiết bị iOS mới hơn
matb33

16

Tôi đã gặp phải lỗi hết bộ nhớ trên Firefox với chiều cao canvas lớn hơn 8000, chrome dường như xử lý cao hơn nhiều, ít nhất là 32000.

CHỈNH SỬA: Sau khi chạy thêm một số bài kiểm tra, tôi đã tìm thấy một số lỗi rất lạ với Firefox 16.0.2.

Đầu tiên, tôi dường như nhận được hành vi khác với canvas trong bộ nhớ (được tạo bằng javascript) trái ngược với canvas được khai báo html.

Thứ hai, nếu bạn không có thẻ html và bộ mã meta thích hợp, canvas có thể bị hạn chế ở 8196, nếu không, bạn có thể lên đến 32767.

Thứ ba, nếu bạn lấy bối cảnh 2d của canvas và sau đó thay đổi kích thước canvas, bạn cũng có thể bị hạn chế ở 8196. Đơn giản chỉ cần đặt kích thước canvas trước khi lấy bối cảnh 2d cho phép bạn có tối đa 32767 mà không bị lỗi bộ nhớ.

Tôi đã không thể liên tục gặp lỗi bộ nhớ, đôi khi nó chỉ xảy ra ở lần tải trang đầu tiên và sau đó các thay đổi chiều cao tiếp theo hoạt động. Đây là tệp html mà tôi đang thử nghiệm với http://pastebin.com/zK8nZxdE .


4
"Thứ hai, nếu bạn không có thẻ html và bộ mã meta phù hợp, canvas có thể bị hạn chế ở 8196, nếu không, bạn có thể lên đến 32767" - ý bạn là gì khi dùng thẻ html và bộ mã meta phù hợp ở đây?
Jack Aidley,

Chắc chắn ý bạn là 8192 (2 ^ 13)? 8196 là một con số kỳ lạ.
jamesdlin

14

Kích thước canvas tối đa của iOS (chiều rộng x chiều cao):

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

thử nghiệm vào tháng 3 năm 2014.


Các giá trị này là tùy ý. Xin xem bài của tôi dưới đây mà tham khảo nội dung hướng dẫn của Safari
dcbarans

11

Để mở rộng một chút về câu trả lời @FredericCharette: Theo hướng dẫn nội dung của safari trong phần "Biết giới hạn tài nguyên iOS":

Kích thước tối đa cho phần tử canvas là 3 megapixel đối với thiết bị có RAM dưới 256 MB và 5 megapixel đối với thiết bị có RAM lớn hơn hoặc bằng 256 MB

Do đó, bất kỳ biến thể kích thước nào của 5242880 (5 x 1024 x 1024) pixel sẽ hoạt động trên các thiết bị bộ nhớ lớn, nếu không thì đó là 3145728 pixel.

Ví dụ cho canvas 5 megapixel (rộng x cao):

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

và như thế..

Các tấm bạt SQUARE lớn nhất là ("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
Cụ thể hơn, giới hạn của iPhone5 là 3 * 1024 * 1024 = 3145728 pixel. (Sau khi tự hỏi tại sao vải của tôi vẫn ổn trên Android nhưng trống trên iOS, tôi thấy câu trả lời này, và cũng stackoverflow.com/questions/12556198/... và có ứng dụng làm việc PhoneGap của tôi.)
Magnus Smith

FYI, Apple đã xóa thông tin kích thước cụ thể khỏi "Giới hạn tài nguyên Safari / Biết iOS". Bây giờ nó chỉ là lời khuyên chung chung về việc giảm thiểu băng thông bằng cách sử dụng các hình ảnh nhỏ.
ToolmakerSteve

@ matb33 báo cáo trong một chú thích về vấn đề rằng iPhone 6 sẽ xuất hiện để hạn chế 16 * 1024 * 1024.
ToolmakerSteve

11

Cập nhật cho năm 2018:

Khi thời gian trôi qua, các giới hạn về canvas đã thay đổi. Đáng buồn thay, điều không thay đổi là thực tế là trình duyệt vẫn không cung cấp thông tin về giới hạn kích thước canvas thông qua API Canvas.

Đối với những người muốn xác định theo chương trình kích thước canvas tối đa của trình duyệt hoặc hỗ trợ thử nghiệm cho kích thước canvas tùy chỉnh, hãy xem canvas-size .

Từ các tài liệu:

Phần tử canvas HTML được hỗ trợ rộng rãi bởi các trình duyệt hiện đại và kế thừa, nhưng mỗi kết hợp trình duyệt và nền tảng áp đặt các giới hạn kích thước duy nhất sẽ khiến canvas không thể sử dụng được khi vượt quá. Thật không may, các trình duyệt không cung cấp cách xác định giới hạn của chúng, cũng như không cung cấp bất kỳ loại phản hồi nào sau khi một canvas không sử dụng được đã được tạo. Điều này khiến việc làm việc với các phần tử canvas lớn trở thành một thách thức, đặc biệt là đối với các ứng dụng hỗ trợ nhiều trình duyệt và nền tảng khác nhau.

Thư viện vi mô này cung cấp diện tích, chiều cao và chiều rộng tối đa của phần tử canvas HTML được trình duyệt hỗ trợ cũng như khả năng kiểm tra kích thước canvas tùy chỉnh. Bằng cách thu thập thông tin này trước khi phần tử canvas mới được tạo, các ứng dụng có thể đặt kích thước canvas một cách đáng tin cậy trong giới hạn kích thước của từng trình duyệt / nền tảng.

Liên kết demo và kết quả kiểm tra có sẵn trong README , cũng như phần các vấn đề đã biết liên quan đến các cân nhắc về hiệu suất và máy ảo.

Tiết lộ đầy đủ, tôi là tác giả của thư viện. Tôi đã tạo nó vào năm 2014 và gần đây đã xem lại mã cho một dự án mới liên quan đến canvas. Tôi rất ngạc nhiên khi thấy thiếu các công cụ có sẵn tương tự để phát hiện giới hạn kích thước canvas vào năm 2018, vì vậy tôi đã cập nhật mã, phát hành mã và hy vọng nó sẽ giúp những người khác đang gặp sự cố tương tự.


8

Theo thông số kỹ thuật của w3 , giao diện chiều rộng / chiều cao là một giao diện dài không dấu - do đó 0 đến 4,294,967,295 (nếu tôi nhớ đúng con số đó - có thể bị lệch một vài).

CHỈNH SỬA: Thật kỳ lạ, nó nói là unsigned long, nhưng nó thử nghiệm chỉ hiển thị một giá trị dài bình thường là max: 2147483647. Jsfiddle - 47 hoạt động nhưng lên đến 48 và nó trở lại mặc định.


Hừ! Thật thú vị, nhưng tôi thậm chí không nhận được đến 1,5 tỷ.
nghiêm túc

Đã chỉnh sửa, xin lỗi (đó là những gì tôi nhận được vì không thử nghiệm trước) - đã thêm một jsfiddle để hiển thị.
WSkid

7

Mặc dù canvas sẽ cho phép bạn đặt height = 2147483647, nhưng khi bạn bắt đầu vẽ, sẽ không có gì xảy ra

Việc vẽ chỉ xảy ra khi tôi đưa chiều cao trở lại 32767


7

iOS có các giới hạn khác nhau.

Sử dụng trình mô phỏng iOS 7, tôi có thể chứng minh giới hạn là 5MB như thế này:

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

nhưng nếu tôi tăng kích thước canvas lên một hàng pixel:

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

2
Bạn không nên dựa trên dữ liệu đó trên trình mô phỏng iOS.
Zoltán

5

Trên PC-
Tôi không nghĩ rằng có hạn chế nhưng có, bạn có thể thoát khỏi ngoại lệ bộ nhớ.

Trên thiết bị di động-
Dưới đây là các hạn chế cho canvas dành cho thiết bị di động: -

Kích thước tối đa cho phần tử canvas là 3 megapixel đối với thiết bị có RAM dưới 256 MB và 5 megapixel đối với thiết bị có RAM lớn hơn hoặc bằng 256 MB.

Vì vậy, ví dụ: nếu bạn muốn hỗ trợ phần cứng cũ hơn của Apple, kích thước của canvas của bạn không được vượt quá 2048 × 1464.

Hy vọng những nguồn này sẽ giúp bạn để kéo bạn ra.


3

Các hạn chế đối với Safari (tất cả các nền tảng) thấp hơn nhiều.

Giới hạn iOS / Safari đã biết

Ví dụ: tôi có một bộ đệm canvas 6400x6400px với dữ liệu được vẽ trên đó. Bằng cách truy tìm / xuất nội dung và bằng cách thử nghiệm trên các trình duyệt khác, tôi có thể thấy rằng mọi thứ đều ổn. Nhưng trên Safari, nó sẽ bỏ qua việc vẽ vùng đệm cụ thể này vào ngữ cảnh chính của tôi.


Đúng! Safari bỏ qua việc vẽ canvas của bạn vì bạn sử dụng canvas lớn hơn là "được phép". Xem kích thước tối đa mà tôi đã đăng ở trên! Đó là tối đa. canvas trên safari / thiết bị này.
Dado

Kích thước của bạn là khá tùy ý, phải không? Bạn có tài liệu nào không? Quá trình thử nghiệm của bạn là gì?
NodeNodeNode

3

Tôi đã cố gắng lập trình để tìm ra giới hạn: đặt kích thước canvas bắt đầu từ 35000, giảm dần 100 cho đến khi tìm thấy kích thước hợp lệ. Trong mỗi bước, viết pixel dưới cùng bên phải và sau đó đọc nó. Nó hoạt động - một cách thận trọng.

Tốc độ có thể chấp nhận nếu một trong hai chiều rộng hoặc chiều cao được thiết lập để một số giá trị thấp (ví dụ 10-200.) Theo cách này: get_max_canvas_size('height', 20).

Nhưng nếu được gọi mà không có chiều rộng hoặc chiều cao như trên get_max_canvas_size(), canvas được tạo quá lớn nên việc đọc màu pixel SINGLE rất chậm và trong IE gây ra hiện tượng treo nghiêm trọng.

Nếu thử nghiệm tương tự này có thể được thực hiện bằng cách nào đó mà không cần đọc giá trị pixel, thì tốc độ có thể chấp nhận được.

Tất nhiên, cách dễ nhất để phát hiện kích thước tối đa là một số cách gốc để truy vấn chiều rộng và chiều cao tối đa. Nhưng Canvas là 'một tiêu chuẩn sống', vì vậy có thể nó sẽ đến vào một ngày nào đó.

http://jsfiddle.net/timo2012/tcg6363r/2/ (Hãy lưu ý! Trình duyệt của bạn có thể bị treo!)

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
Điều này sẽ được tối ưu hóa rất nhiều bằng cách sử dụng en.wikipedia.org/wiki/Exponential_search
Brendan Annable 23/09/16

1
Thực sự là điên rồ khi thất bại trong việc tạo một canvas lớn như thế này là im lặng nên không có cách nào để phát hiện ... không tệ về phía bạn, đó chỉ là một điều điên rồ khi các trình duyệt bắt đầu tấn công chúng ta
Colin D

@ColinD Tôi đồng ý. Nó sẽ chỉ là một mẩu thông tin nhỏ ở đâu đó. Nó sẽ. Và nên.
Timo Kähkönen

3

Khi bạn đang sử dụng bạt WebGL, các trình duyệt (bao gồm cả các trình duyệt dành cho máy tính để bàn) sẽ áp đặt thêm giới hạn về kích thước của bộ đệm bên dưới. Ngay cả khi canvas của bạn lớn, ví dụ: 16.000x16.000, hầu hết các trình duyệt sẽ hiển thị hình ảnh nhỏ hơn (giả sử 4096x4096) và tăng tỷ lệ. Điều đó có thể gây ra hiện tượng tạo pixel xấu xí, v.v.

Tôi đã viết một số mã để xác định kích thước tối đa đó bằng cách sử dụng tìm kiếm theo cấp số nhân, nếu có ai cần nó. determineMaxCanvasSize()là chức năng bạn quan tâm.

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

Cũng trong một jsfiddle https://jsfiddle.net/1sh47wfk/1/


Có tài liệu chính thức nào về hành vi mở rộng quy mô không?
Magnus Lind Oxlund

1
@MagnusLindOxlund Thông tin từ câu trả lời đã được xác định bằng thực nghiệm. Điều gần nhất tôi tìm thấy sau khi tìm kiếm nhanh là: khronos.org/registry/webgl/specs/latest/1.0/#2.2 , nói rằng: "Ràng buộc ở trên không thay đổi dung lượng phần tử canvas sử dụng trên trang web "khi nó nói về việc giới hạn kích thước của bộ đệm bản vẽ. Có vẻ như tiêu chuẩn WebGL không đi sâu chi tiết về cách phần tử canvas được cho là hiển thị bộ đệm bản vẽ.
Michał

1

Bạn có thể chia nhỏ nó và trong javascript tự động thêm nhiều bức tranh nhỏ hơn nếu cần và vẽ các phần tử trên canvas thích hợp. Cuối cùng bạn vẫn có thể hết bộ nhớ nhưng sẽ giúp bạn vượt qua giới hạn canvas duy nhất.


0

Tôi không biết làm thế nào để phát hiện kích thước tối đa có thể mà không bị nhiễu, nhưng bạn có thể phát hiện xem kích thước canvas đã cho có hoạt động hay không bằng cách điền vào một pixel và sau đó đọc lại màu. Nếu canvas chưa hiển thị thì màu bạn nhận được sẽ không khớp. W

mã một phần:

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.