Bir <canvas> öğesinin maksimum boyutu


112

Ben yüksekliğindeki bir tuval eleman ile çalışıyorum 600için 1000piksel ve onlarca veya piksel yüzbinlerce genişliğinde. Bununla birlikte, belirli sayıda pikselden sonra (açıkça bilinmeyen), tuval artık JS ile çizdiğim şekilleri göstermiyor.

Bir sınır olup olmadığını bilen var mı?

Hem Chrome 12 hem de Firefox 4'te test edilmiştir.


2
@ Šime dedi ki tens OR hundreds of thousands...
Tadeck

6
Ben de bunu yaşıyorum. İyi çalışan bir 8000x8000 kanvasım var, ancak büyüttüğümde içerik kayboluyor ve çizilmiyor. İPad'imde çalışamadığı boyut çok daha düşük. Merak ediyorum, bu bir tür hafıza sınırlaması mı?
Joshua

28
2 yıl öncesinden kendi yorumunuzu bulmanız ve hala aynı lanet problemle uğraşmanız garip.
Joshua

4
@Joshua ve hala bir yıl sonra!
Eugene Yu

1
Soru şu ki, bu hataları veya daha iyi uyarıları nasıl yakalayabilirim, bunlar nedir? Cihaz donanımını tespit edemiyorum, bu yüzden bir hataya tepki vermem gerekiyor.
br4nnigan

Yanıtlar:


115

Güncelleme tarihi 10/13/2014

Test edilen tüm tarayıcıların tuval öğelerinin yüksekliği / genişliği için sınırları vardır, ancak birçok tarayıcı aynı zamanda tuval öğesinin toplam alanını da sınırlar. Test edebileceğim tarayıcılar için sınırlar aşağıdaki gibidir:

Krom:

Maksimum yükseklik / genişlik: 32.767 piksel
Maksimum alan: 268.435.456 piksel (örneğin, 16.384 x 16.384)

Firefox:

Maksimum yükseklik / genişlik: 32.767 piksel
Maksimum alan: 472.907.776 piksel (ör. 22.528 x 20.992)

IE:

Maksimum yükseklik / genişlik: 8.192 piksel
Maksimum alan: Yok

IE Mobile:

Maksimum yükseklik / genişlik: 4.096 piksel
Maksimum alan: Yok

Diğer:

Şu anda diğer tarayıcıları test edemiyorum. Ek sınırlar için bu sayfadaki diğer yanıtlara bakın.


Çoğu tarayıcıda maksimum uzunluk / genişlik / alanın aşılması tuvali kullanılamaz hale getirir. (Kullanılabilir alanda bile herhangi bir çizim komutunu göz ardı eder.) IE ve IE Mobile, kullanılabilir alan içindeki tüm çizim komutlarını yerine getirir.


3
Öyleyse, ilgili soru ... İzin verilen maksimum değerden daha büyük bir tuvale ihtiyaç duyarlarsa, sınırı nasıl aşabiliriz?
2014

2
@aroth, tuval API'sinin etrafında birden fazla yığılmış <canvas>öğe kullanan ve uygun bağlama göre çizim talimatlarını otomatik olarak uygulayan bir sarmalayıcı yazdım .
Brandon Gano

1
Kulağa çok kullanışlı geliyor. Github'da olduğunu sanmıyorum?
2014, 1

5
Safari (iOS olmayan sürüm), Chrome.Firefox gibi 32K kullanır. Ayrıca, bu sarmalayıcı kodunun bir kısmını yeniden oluşturmayı denemek isterseniz, IE'nin
aroth

7
iPhone 6 Plus'ta iOS 9.3.1 Safari, 16777216 piksellik bir alanla sınırlıdır (örneğin, 4096 x 4096). Bunun daha yeni iOS cihazlarında yaygın bir sayı olduğundan şüpheleniyorum
matb33

16

Firefox'ta tuval yüksekliği 8000'den büyük olan bellek yetersizliği ile karşılaştım, krom çok daha yüksek, en azından 32000'e kadar işliyor gibi görünüyor.

DÜZENLEME: Birkaç test daha çalıştırdıktan sonra, Firefox 16.0.2 ile bazı çok garip hatalar buldum.

İlk olarak, html tarafından beyan edilen tuvalin aksine, bellekte (javascript'te oluşturulmuş) tuvalden farklı davranışlar elde ediyorum.

İkinci olarak, uygun html etiketine ve meta karakter kümesine sahip değilseniz, tuval 8196 ile sınırlı olabilir, aksi takdirde 32767'ye kadar çıkabilirsiniz.

Üçüncüsü, tuvalin 2d içeriğini alır ve ardından tuval boyutunu değiştirirseniz, 8196 ile de sınırlı olabilirsiniz. 2D bağlamı yakalamadan önce tuval boyutunu ayarlamak, bellek hatası almadan 32767'ye kadar sahip olmanızı sağlar.

Sürekli olarak bellek hatalarını alamadım, bazen sadece ilk sayfa yüklemesinde ve ardından sonraki yükseklik değişiklikleri işe yarıyor. Bu, http://pastebin.com/zK8nZxdE ile test ettiğim html dosyası .


4
"İkinci olarak, uygun html etiketine ve meta karakter kümesine sahip değilseniz, tuval 8196 ile sınırlı olabilir, aksi takdirde 32767'ye kadar çıkabilirsiniz" - buradaki uygun html etiketi ve meta karakter kümesiyle ne demek istiyorsunuz?
Jack Aidley

Şüphesiz 8192 (2 ^ 13) demek istiyorsun? 8196 garip bir sayı.
jamesdlin

14

iOS maksimum tuval boyutu (genişlik x yükseklik):

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

Mart 2014'te test edildi.


Bu değerler keyfidir. Lütfen safari içerik kılavuzuna atıfta bulunan aşağıdaki yazıma bakın
dcbarans

11

@FredericCharette cevabını biraz genişletmek için: Safari'nin "iOS Kaynak Sınırlarını Öğrenin" bölümü altındaki içerik kılavuzuna göre:

Bir tuval öğesinin maksimum boyutu, 256 MB'den daha az RAM'e sahip cihazlar için 3 megapiksel ve 256 MB'den büyük veya daha büyük RAM'e sahip cihazlar için 5 megapikseldir.

Bu nedenle, 5242880 (5 x 1024 x 1024) piksellik herhangi bir boyut varyasyonu büyük bellek aygıtlarında çalışacaktır, aksi takdirde 3145728 pikseldir.

5 megapiksel tuval örneği (genişlik x yükseklik):

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

ve bunun gibi..

En büyük KARE tuvaller ("MiB" = 1024x1024 Bayt):

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
Daha spesifik olmak gerekirse, iPhone5 sınırı 3 * 1024 * 1024 = 3145728 pikseldir. ( Kanvasımın neden Android'de iyi ancak iOS'ta boş olduğunu merak ettikten sonra, bu yanıtı buldum ve ayrıca stackoverflow.com/questions/12556198/… ve Phonegap uygulamamı çalıştırdım.)
Magnus Smith

Bilginize, Apple belirli boyut bilgilerini "Safari / Know iOS Resource Limitits" bölümünden kaldırdı. Şimdi, küçük resimler kullanarak bant genişliğini en aza indirmek için yalnızca genel bir tavsiye.
ToolmakerSteve

@ matb33 iPhone 6 görünür sınırı 16 * 1024 * 1024 olması bu soruya yaptığı yorumda bildirdi
ToolmakerSteve

11

2018 Güncellemesi:

Zaman geçtikçe tuval sınırlamaları değişti. Ne yazık ki değişmeyen şey, tarayıcının hala Canvas API aracılığıyla tuval boyutu sınırlamaları hakkında bilgi sağlamadığı gerçeğidir.

Tarayıcının maksimum tuval boyutunu programlı olarak belirlemek veya özel tuval boyutları için desteği test etmek isteyenler için tuval boyutuna bakın .

Dokümanlardan:

HTML tuval öğesi, modern ve eski tarayıcılar tarafından geniş çapta desteklenir, ancak her tarayıcı ve platform kombinasyonu, bir tuvali aşıldığında kullanılamaz hale getirecek benzersiz boyut sınırlamaları getirir. Ne yazık ki, tarayıcılar sınırlamalarının ne olduğunu belirlemenin bir yolunu sağlamaz veya kullanılamaz bir tuval oluşturulduktan sonra herhangi bir geri bildirim sağlamaz. Bu, özellikle çeşitli tarayıcıları ve platformları destekleyen uygulamalar için büyük tuval öğeleriyle çalışmayı zorlaştırır.

Bu mikro kitaplık, tarayıcı tarafından desteklenen bir HTML tuval öğesinin maksimum alanını, yüksekliğini ve genişliğini ve ayrıca özel tuval boyutlarını test etme becerisini sağlar. Uygulamalar, yeni bir tuval öğesi oluşturulmadan önce bu bilgileri toplayarak, her tarayıcının / platformun boyut sınırlamaları dahilinde güvenilir bir şekilde tuval boyutlarını ayarlayabilir.

Bir demo bağlantısı ve test sonuçları mevcuttur README yanı sıra bir bilinen sorunlar performans ve sanal makine değerlendirmelere dokunur bölümü.

Tam açıklama, ben kütüphanenin yazarıyım. Bunu 2014'te yeniden oluşturdum ve kısa süre önce tuvalle ilgili yeni bir projenin kodunu yeniden gözden geçirdim. 2018'de tuval boyutu sınırlamalarını tespit etmek için mevcut araçların eksikliğini bulduğumda şaşırdım, bu yüzden kodu güncelledim, yayınladım ve diğerlerinin benzer sorunlarla karşılaşmasına yardımcı olacağını umuyorum.


8

W3 özelliklerine göre , genişlik / yükseklik arabirimi işaretsiz bir uzunluktur - yani 0 - 4,294,967,295 (bu sayıyı doğru hatırlıyorsam - birkaçı olabilir).

DÜZENLEME: Garip bir şekilde, işaretsiz uzun diyor, ancak test, maksimum: 2147483647 olarak sadece normal bir uzun değer gösteriyor. Jsfiddle - 47, 48'e kadar çalışıyor ve varsayılana geri dönüyor.


Hmm. İlginç ama 1,5 milyara bile ulaşamıyorum.
ciddidev

Düzenlendi, üzgünüm (ilk önce test etmediğim için aldığım şey bu) - göstermek için bir jsfiddle eklendi.
WSkid

7

Kanvas yükseklik = 2147483647 koymanıza izin verse de çizmeye başladığınızda hiçbir şey olmayacak

Çizim sadece yüksekliği 32767'ye geri getirdiğimde oluyor


7

iOS'un farklı sınırları vardır.

İOS 7 simülatörünü kullanarak sınırın 5MB olduğunu şu şekilde gösterebildim:

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

ancak tuval boyutunu tek bir piksel satırı yukarı itersem:

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

2
Bu tür verileri iOS simülatörüne dayandırmamalısınız.
Zoltán

5

PC'de -
Bir kısıtlama olduğunu sanmıyorum ama evet, hafıza dışında istisna yapabilirsiniz.


Mobil cihazlarda - Mobil cihazlar için kanvas için kısıtlamalar şunlardır : -

Bir kanvas öğesinin maksimum boyutu, 256 MB'den daha az RAM'e sahip cihazlar için 3 megapiksel ve 256 MB RAM'e eşit veya daha büyük olan cihazlar için 5 megapikseldir.

Örneğin, Apple'ın eski donanımını desteklemek istiyorsanız, tuvalinizin boyutu 2048 × 1464'ü geçemez.

Umarım bu kaynaklar sizi dışarı çekmenize yardımcı olur.


3

Safari (tüm platformlar) için sınırlamalar çok daha düşüktür.

Bilinen iOS / Safari Sınırlamaları

Örneğin, üzerine çizilmiş verilerin bulunduğu 6400x6400px bir tuval arabelleğim vardı. İçeriği izleyerek / dışa aktararak ve diğer tarayıcılarda test ederek, her şeyin yolunda olduğunu görebildim. Ancak Safari'de, bu özel tamponun çizimini ana bağlamıma atlar.


Yeep! Safari, "izin verilen" olarak daha büyük bir tuval kullandığınız için tuvalinizi çizmeyi atlar. Yukarıda yayınladığım maksimum boyutlara bakın! Bu maks. bu safari / cihazlarda tuval.
Dado

Boyutlarınız oldukça gelişigüzel, değil mi? Herhangi bir belgeniz var mı? Test süreciniz nasıldı?
NodeNodeNode

3

Sınırı programlı bir şekilde anlamaya çalıştım: 35000'den başlayarak tuval boyutunu ayarlama, geçerli boyut bulunana kadar 100 azaltma. Her adımda sağ alttaki pikseli yazıp sonra okuyoruz. Çalışır - dikkatli.

Her iki genişlik veya yükseklik bir düşük değeri (örn. 10-200) bu şekilde ayarlanırsa, hızı kabul edilebilir: get_max_canvas_size('height', 20).

Ancak, genişlik veya yükseklik olmadan çağrılırsa get_max_canvas_size(), oluşturulan tuval o kadar büyüktür ki TEK piksel rengini okumak çok yavaştır ve IE'de ciddi takılmalara neden olur.

Bu gibi bir test piksel değeri okunmadan bir şekilde yapılabilirse, hız kabul edilebilir olacaktır.

Elbette maksimum boyutu tespit etmenin en kolay yolu, maksimum genişliği ve yüksekliği sorgulamanın yerel bir yolu olacaktır. Ancak tuval 'bir yaşam standardıdır', bu yüzden bir gün gelecek olabilir.

http://jsfiddle.net/timo2012/tcg6363r/2/ (Dikkat edin! Tarayıcınız kilitlenebilir!)

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


1
Bu kadar büyük bir tuval yaratmadaki başarısızlığın sessiz olması gerçekten delice, bu yüzden tespit etmenin bir yolu yok ... sizin açınızdan hiç de fena değil, tarayıcıların bize saldırması çılgınca bir şey
Colin D

@ColinD Katılıyorum. Bir yerlerde sadece küçük bir bilgi parçası olabilir. Olurdu. Yapmalı.
Timo Kähkönen

3

WebGL tuvallerini kullandığınızda, tarayıcılar (masaüstü olanlar dahil) temeldeki arabelleğin boyutuna ekstra sınırlar getirecektir. Tuvaliniz büyük olsa bile, örneğin 16.000x16.000, çoğu tarayıcı daha küçük (diyelim ki 4096x4096) bir resim oluşturur ve onu ölçeklendirir. Bu, çirkin pikselleşmeye vb. Neden olabilir.

Herhangi birinin ihtiyacı olursa, üstel arama kullanarak bu maksimum boyutu belirlemek için bazı kodlar yazdım. determineMaxCanvasSize()ilgilendiğiniz işlevdir.

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

Ayrıca bir jsfiddle'da https://jsfiddle.net/1sh47wfk/1/


Ölçek büyütme davranışıyla ilgili herhangi bir resmi belge var mı?
Magnus Lind Oxlund

1
@MagnusLindOxlund Cevaptan elde edilen bilgiler deneysel olarak belirlenmiştir. Hızlı bir aramadan sonra bulduğum en yakın şey şudur: khronos.org/registry/webgl/specs/latest/1.0/#2.2 : "Yukarıdaki kısıtlama, web sayfasında tuval öğesinin tükettiği alan miktarını değiştirmez "çizim arabelleğinin boyutunu sınırlamaktan bahsederken. Görünüşe göre WebGL standardı, tuval öğesinin çizim arabelleğini nasıl görüntülemesi gerektiği konusunda çılgın ayrıntılara girmiyor.
Michał

1

Parçalara ayırabilir ve javascript otomatik olarak gerektiği kadar küçük tuvaller ekleyebilir ve öğeleri uygun tuval üzerine çizebilirsiniz. Sonunda hala belleğiniz tükenebilir, ancak sizi tek tuval sınırına göre alırsınız.


0

Mümkün olan maksimum boyutu terleme olmadan nasıl tespit edeceğimi bilmiyorum, ancak belirli bir tuval boyutunun çalışıp çalışmadığını bir pikseli doldurup ardından rengi tekrar okuyarak tespit edebilirsiniz. Tuval oluşturulmamışsa, geri aldığınız renk eşleşmeyecektir. W

kısmi kod:

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);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.