Ukuran maksimum dari sebuah elemen <canvas>


112

Saya bekerja dengan elemen kanvas dengan tinggi 600hingga 1000piksel dan lebar beberapa puluh atau ratusan ribu piksel. Namun, setelah sejumlah piksel (jelas tidak diketahui), kanvas tidak lagi menampilkan bentuk yang saya gambar dengan JS.

Adakah yang tahu jika ada batasan?

Telah diuji di Chrome 12 dan Firefox 4.


2
@ Šime Dia berkata tens OR hundreds of thousands...
Tadeck

6
Saya mengalami ini juga. Saya memiliki kanvas berukuran 8000x8000 yang berfungsi dengan baik, tetapi ketika saya membuatnya lebih besar, konten menghilang dan tidak bisa digambar. Ukuran yang gagal berfungsi jauh lebih rendah di iPad saya. Aku ingin tahu apakah itu semacam batasan memori.
Joshua

28
Aneh ketika Anda menemukan komentar Anda sendiri dari 2 tahun sebelumnya dan Anda masih berurusan dengan masalah sialan yang sama.
Joshua

4
@Joshua dan masih setahun kemudian!
Eugene Yu

1
Pertanyaannya adalah bagaimana cara menangkap kesalahan ini, atau peringatan yang lebih baik, yang mana itu? Saya tidak dapat mendeteksi perangkat keras perangkat, jadi saya harus bereaksi terhadap kesalahan.
br4nnigan

Jawaban:


115

Diperbarui 13/10/2014

Semua browser yang diuji memiliki batasan tinggi / lebar elemen kanvas, tetapi banyak browser juga membatasi total area elemen kanvas. Batasannya adalah sebagai berikut untuk browser yang dapat saya uji:

Chrome:

Tinggi / lebar maksimum: 32.767 piksel
Area maksimum: 268.435.456 piksel (mis., 16.384 x 16.384)

Firefox:

Tinggi / lebar maksimum: 32.767 piksel
Area maksimum: 472.907.776 piksel (mis., 22.528 x 20.992)

YAITU:

Tinggi / lebar maksimum: 8.192 piksel
Area maksimum: N / A

IE Mobile:

Tinggi / lebar maksimum: 4.096 piksel
Area maksimum: N / A

Lain:

Saya tidak dapat menguji browser lain saat ini. Lihat jawaban lain di halaman ini untuk batasan tambahan.


Melebihi panjang / lebar / area maksimum pada kebanyakan browser membuat kanvas tidak dapat digunakan. (Ini akan mengabaikan perintah gambar apa pun, bahkan di area yang dapat digunakan.) IE dan IE Mobile akan menghormati semua perintah gambar dalam ruang yang dapat digunakan.


3
Jadi, pertanyaan terkait ... bagaimana seseorang mengatasi batas jika mereka membutuhkan kanvas yang lebih besar dari batas maksimum yang diizinkan?
aroth

2
@aroth, saya akhirnya menulis pembungkus di sekitar API kanvas yang menggunakan beberapa <canvas>elemen yang ditumpuk dan secara otomatis menerapkan instruksi gambar ke konteks yang sesuai.
Brandon Gano

1
Kedengarannya sangat berguna. Jangan kira itu ada di github?
Aroth

5
Safari (versi non-iOS) menggunakan 32K seperti Chrome.Firefox. Selain itu, jika Anda ingin mencoba membuat ulang beberapa kode pembungkus itu, saya memulai versi sumber terbuka saya sendiri berkat batas 8K IE yang sederhana
aroth

7
iOS 9.3.1 Safari pada iPhone 6 Plus terbatas pada area seluas 16777216 piksel (misalnya, 4096 x 4096). Saya menduga ini adalah nomor umum di perangkat iOS yang lebih baru
matb33

16

Saya mengalami kesalahan memori di Firefox dengan tinggi kanvas lebih dari 8000, chrome tampaknya menangani jauh lebih tinggi, setidaknya hingga 32000.

EDIT: Setelah menjalankan beberapa tes lagi, saya menemukan beberapa kesalahan yang sangat aneh dengan Firefox 16.0.2.

Pertama, saya tampaknya mendapatkan perilaku yang berbeda dari dalam kanvas memori (dibuat dalam javascript) sebagai lawan dari kanvas yang dinyatakan html.

Kedua, jika Anda tidak memiliki tag html dan meta charset yang tepat, kanvas mungkin dibatasi ke 8196, jika tidak, Anda bisa naik ke 32767.

Ketiga, jika Anda mendapatkan konteks kanvas 2d dan kemudian mengubah ukuran kanvas, Anda mungkin dibatasi ke 8196 juga. Cukup mengatur ukuran kanvas sebelum mengambil konteks 2d memungkinkan Anda memiliki hingga 32767 tanpa mendapatkan kesalahan memori.

Saya belum bisa mendapatkan kesalahan memori secara konsisten, terkadang hanya pada pemuatan halaman pertama, dan kemudian perubahan tinggi berikutnya berfungsi. Ini adalah file html yang saya uji dengan http://pastebin.com/zK8nZxdE .


4
"Kedua, jika Anda tidak memiliki tag html dan meta charset yang tepat, kanvas mungkin dibatasi ke 8196, jika tidak, Anda dapat naik ke 32767" - apa yang Anda maksud dengan tag html dan meta charset yang tepat di sini?
Jack Aidley

Tentunya yang Anda maksud 8192 (2 ^ 13)? 8196 adalah angka yang aneh.
jamesdlin

14

Ukuran kanvas maksimal iOS (lebar x tinggi):

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

diuji pada Maret 2014.


Nilai-nilai ini sewenang-wenang. Silakan lihat posting saya di bawah ini yang mereferensikan panduan konten safari
dcbarans

11

Untuk memperluas sedikit tentang jawaban @FredericCharette: Sesuai panduan konten safari di bawah bagian "Ketahui Batas Sumber Daya iOS":

Ukuran maksimum elemen kanvas adalah 3 megapiksel untuk perangkat dengan RAM kurang dari 256 MB dan 5 megapiksel untuk perangkat dengan RAM lebih besar atau sama dari 256 MB

Oleh karena itu, variasi ukuran apa pun dari 5242880 (5 x 1024 x 1024) piksel akan berfungsi pada perangkat memori besar, jika tidak maka 3145728 piksel.

Contoh untuk kanvas 5 megapiksel (lebar x tinggi):

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

dan seterusnya..

Kanvas SQUARE terbesar adalah ("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

1
Untuk lebih spesifik, batas iPhone5 adalah 3 * 1024 * 1024 = 3145728 piksel. (Setelah bertanya-tanya mengapa kanvas saya baik-baik saja di Android tetapi kosong di iOS, saya menemukan jawaban ini, dan juga stackoverflow.com/questions/12556198/… dan membuat aplikasi Phonegap saya berfungsi.)
Magnus Smith

FYI, Apple telah menghapus info ukuran tertentu dari "Safari / Ketahui Batas Sumber Daya iOS". Sekarang ini hanyalah saran umum tentang meminimalkan bandwidth dengan menggunakan gambar kecil.
ToolmakerSteve

@ matb33 melaporkan dalam komentar pada pertanyaan bahwa iPhone 6 tampaknya memiliki batas 16 * 1024 * 1024.
ToolmakerSteve

11

Pembaruan untuk 2018:

Seiring berjalannya waktu, batasan kanvas telah berubah. Sayangnya, yang tidak berubah adalah fakta bahwa browser masih belum memberikan informasi mengenai batasan ukuran canvas melalui Canvas API.

Bagi mereka yang ingin menentukan secara terprogram ukuran kanvas maksimum browser atau menguji dukungan untuk dimensi kanvas khusus, lihat ukuran kanvas .

Dari dokumen:

Elemen kanvas HTML didukung secara luas oleh browser modern dan lama, tetapi setiap kombinasi browser dan platform memberlakukan batasan ukuran unik yang akan membuat kanvas tidak dapat digunakan jika terlampaui. Sayangnya, browser tidak menyediakan cara untuk menentukan batasannya, juga tidak memberikan umpan balik apa pun setelah kanvas yang tidak dapat digunakan dibuat. Hal ini membuat bekerja dengan elemen kanvas besar menjadi tantangan, terutama untuk aplikasi yang mendukung berbagai browser dan platform.

Pustaka mikro ini menyediakan area, tinggi, dan lebar maksimum dari elemen kanvas HTML yang didukung oleh browser serta kemampuan untuk menguji dimensi kanvas khusus. Dengan mengumpulkan informasi ini sebelum elemen kanvas baru dibuat, aplikasi dapat dengan andal menyetel dimensi kanvas dalam batasan ukuran setiap browser / platform.

Tautan demo dan hasil pengujian tersedia di README , serta bagian masalah umum yang menyentuh pertimbangan kinerja dan mesin virtual.

Pengungkapan penuh, saya penulis perpustakaan. Saya membuatnya kembali pada tahun 2014 dan baru-baru ini mengunjungi kembali kode untuk proyek terkait kanvas baru. Saya terkejut menemukan kekurangan alat yang sama untuk mendeteksi batasan ukuran kanvas pada tahun 2018 jadi saya memperbarui kode, merilisnya, dan berharap ini membantu orang lain mengalami masalah serupa.


8

Menurut spesifikasi w3 , antarmuka lebar / tinggi adalah panjang tanpa tanda tangan - jadi 0 hingga 4.294.967.295 (jika saya ingat nomor itu dengan benar - mungkin ada beberapa).

EDIT: Anehnya, dikatakan unsigned long, tetapi pengujiannya hanya menunjukkan nilai long normal sebagai max: 2147483647. Jsfiddle - 47 berfungsi tetapi hingga 48 dan kembali ke default.


Hmm. Menarik, tapi saya bahkan tidak sampai 1,5 miliar.
seriusdev

Diedit, maaf (itulah yang saya dapatkan karena tidak menguji terlebih dahulu) - menambahkan jsfiddle untuk ditampilkan.
WSkid

7

Meskipun kanvas memungkinkan Anda untuk meletakkan height = 2147483647, ketika Anda mulai menggambar, tidak akan terjadi apa-apa

Menggambar terjadi hanya jika saya mengembalikan tinggi ke 32767


7

iOS memiliki batasan yang berbeda.

Dengan menggunakan simulator iOS 7 saya dapat menunjukkan batasnya adalah 5MB seperti ini:

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

tetapi jika saya mendorong ukuran kanvas hingga satu baris piksel:

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

2
Anda tidak boleh mendasarkan data tersebut pada simulator iOS.
Zoltán

5

Di PC-
Saya tidak berpikir ada batasan tetapi ya Anda bisa keluar dari pengecualian memori.

Di perangkat Seluler-
Berikut adalah batasan kanvas untuk perangkat seluler: -

Ukuran maksimum elemen kanvas adalah 3 megapiksel untuk perangkat dengan RAM kurang dari 256 MB dan 5 megapiksel untuk perangkat dengan RAM lebih besar atau sama dari 256 MB.

Jadi misalnya - jika Anda ingin mendukung perangkat keras Apple yang lebih lama, ukuran kanvas Anda tidak boleh melebihi 2048 × 1464.

Semoga sumber daya ini akan membantu Anda menarik diri.


3

Batasan untuk Safari (semua platform) jauh lebih rendah.

Batasan iOS / Safari yang Diketahui

Misalnya, saya memiliki buffer kanvas 6400x6400px dengan data yang ditarik ke dalamnya. Dengan menelusuri / mengekspor konten dan dengan mengujinya di browser lain, saya dapat melihat bahwa semuanya baik-baik saja. Tapi di Safari, itu akan melewatkan gambar buffer khusus ini ke konteks utama saya.


Yaa! Safari melewatkan menggambar kanvas Anda karena Anda menggunakan kanvas yang lebih besar sebagai "diizinkan". Lihat dimensi maksimal yang telah saya posting di atas! Itu maks. kanvas di safari / perangkat ini.
Dado

Ukuran Anda cukup sewenang-wenang, bukan? Apakah Anda punya dokumentasi? Apa proses pengujian Anda?
NodeNodeNode

3

Saya mencoba untuk secara terprogram mencari tahu batasnya: mengatur ukuran kanvas mulai dari 35000, turun 100 hingga ukuran yang valid ditemukan. Di setiap langkah tulis piksel kanan bawah dan kemudian membacanya. Ini bekerja - dengan hati-hati.

Kecepatan diterima jika salah lebar atau tinggi diatur untuk beberapa nilai rendah (misalnya 10-200.) Dengan cara ini: get_max_canvas_size('height', 20).

Tetapi jika disebut tanpa lebar atau tinggi seperti get_max_canvas_size(), kanvas yang dibuat sangat besar sehingga pembacaan warna piksel TUNGGAL sangat lambat, dan di IE menyebabkan hang yang serius.

Jika tes seperti ini dapat dilakukan bagaimanapun tanpa membaca nilai piksel, kecepatannya akan dapat diterima.

Tentu saja cara termudah untuk mendeteksi ukuran maksimum adalah dengan cara asli untuk menanyakan lebar dan tinggi maksimum. Tapi Canvas adalah 'standar hidup', jadi mungkin itu akan datang suatu hari nanti.

http://jsfiddle.net/timo2012/tcg6363r/2/ (Hati-hati! Browser Anda mungkin macet!)

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
Ini akan sangat dioptimalkan dengan menggunakan en.wikipedia.org/wiki/Exponential_search
Brendan Annable

1
Benar-benar gila bahwa kegagalan membuat kanvas sebesar ini tidak terdengar sehingga tidak ada cara untuk mendeteksi ... tidak buruk dengan cara apa pun di pihak Anda, hanya hal gila untuk browser yang muncul pada kita
Colin D

@ColinD Saya setuju. Ini hanya akan menjadi satu informasi kecil di suatu tempat. Itu akan. Dan seharusnya.
Timo Kähkönen

3

Saat Anda menggunakan kanvas WebGL, browser (termasuk yang desktop) akan memberlakukan batasan ekstra pada ukuran buffer yang mendasarinya. Meskipun kanvas Anda besar, misalnya 16.000x16.000, sebagian besar browser akan membuat gambar yang lebih kecil (katakanlah 4096x4096), dan memperbesarnya. Itu mungkin menyebabkan pixelating jelek, dll.

Saya telah menulis beberapa kode untuk menentukan ukuran maksimum menggunakan pencarian eksponensial, jika ada yang membutuhkannya. determineMaxCanvasSize()adalah fungsi yang Anda minati.

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

Juga di jsfiddle https://jsfiddle.net/1sh47wfk/1/


Apakah ada dokumentasi resmi tentang perilaku peningkatan skala?
Magnus Lind Oxlund

1
@MagnusLindOxlund Informasi dari jawaban telah ditentukan secara eksperimental. Hal terdekat yang saya temukan setelah pencarian cepat adalah: khronos.org/registry/webgl/specs/latest/1.0/#2.2 , mengatakan: "Batasan di atas tidak mengubah jumlah ruang yang digunakan elemen kanvas di halaman web "ketika berbicara tentang membatasi ukuran buffer gambar. Tampaknya standar WebGL tidak menjelaskan secara mendetail tentang bagaimana elemen kanvas seharusnya menampilkan buffering gambar.
Michał

1

Anda dapat memotongnya dan dalam javascript otomatis menambahkan kanvas kecil sebanyak yang diperlukan dan menggambar elemen di kanvas yang sesuai. Anda mungkin masih akan kehabisan memori pada akhirnya, tetapi Anda akan mendapatkan batas kanvas tunggal.


0

Saya tidak tahu cara mendeteksi ukuran maksimum yang mungkin tanpa itterasi, tetapi Anda dapat mendeteksi apakah ukuran kanvas tertentu berfungsi dengan mengisi piksel dan kemudian membaca warnanya kembali. Jika kanvas belum di-render maka warna yang Anda dapatkan tidak akan cocok. W

kode parsial:

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);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.