Bir <canvas> Ölçeklendirirken Enterpolasyonu Devre Dışı Bırak


126

NOT : Bu nasıl bir ilgisi vardır büyütülüyor zaman mevcut tuval elemanları oluşturulur , değil çizgiler veya grafik render nasıl bir ilgisi bir tuval yüzeyine . Başka bir deyişle, bu işle her şeye sahiptir interpolasyon ait ölçekli elemanları ve alakası yoktur antialiasing grafik bir tuvale çizilmiş olma. Tarayıcının çizgileri nasıl çizdiğiyle ilgilenmiyorum; Tarayıcının tuval öğesinin büyütüldüğünde kendisini nasıl oluşturduğunu önemsiyorum.


<canvas>Öğeleri ölçeklendirirken enterpolasyonu devre dışı bırakmak için programla değiştirebileceğim bir tuval özelliği veya tarayıcı ayarı var mı? Çapraz tarayıcı çözümü idealdir ancak zorunlu değildir; Webkit tabanlı tarayıcılar ana hedefimdir. Performans çok önemlidir.

Bu soru en çok benzerdir ancak sorunu yeterince göstermez. Değeri ne olursa olsun, image-rendering: -webkit-optimize-contrastboşuna uğraşmadım.

Uygulama, neye ihtiyacım olduğunu netleştirmek için HTML5 + JS ile yazılmış "retro" 8-bit tarzlı bir oyun olacak.


Açıklamak için, işte bir örnek. ( canlı sürüm )

21x21 tuvalim olduğunu varsayalım ...

<canvas id='b' width='21' height='21'></canvas>

... elemanı 5 kat daha büyük yapan (105x105) css'e sahip:

canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */

Tuval üzerine şu şekilde basit bir 'X' çiziyorum:

$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

Soldaki resim, Chromium'un (14.0) sunduğu şeydir. Sağdaki resim istediğim şeydir (açıklama amacıyla elle çizilmiş).

Chrome, ölçeklenmiş tuval öğelerini enterpolasyonlu hale getirir Enterpolasyonsuz bir versiyon


1
Bir şekilde ilişkili, ancak aynı olmasa da: stackoverflow.com/questions/195262/…
HostileFork,

1
Bu sorunun, kenarları yumuşatılmış çizgiler çizen çizgi çizme işlevlerine atıfta bulunduğuna inanıyorum. Varsayılan olarak yeniden boyutlandırılan tuval öğelerinin enterpolasyonla nasıl oluşturulduğundan bahsediyorum.
namuol

Evet, özür dilerim ... Önce aynı soruları düşündüm, sonra hemen hatamı fark ettim. : - / Ya jsmanipulate'in pikselleştirme filtresini kullanmayı deneseydiniz? joelb.me/jsmanipulate
HostileFork,

1
Bu daha çok fotoğraflar için tasarlanmış bir görüntü filtresi.
namuol

Evet, ancak sol görüntünüzü sağ görüntünüzün sizi mutlu edecek kadar iyi bir sürümüne dönüştürürse, tarayıcılar arası bir çözüm sağlayabilir (evrensel veya başka bir şekilde bu çizim modu için bir bayrak bulmak için fazla umut verici görünmediğini düşünürsek) , WebKit'te). Uygulanabilir bir yedek olup olmadığı, çözmeye çalıştığınız soruna bağlıdır ... Gerçekten ayrı piksel çizimine ihtiyacınız varsa veya yalnızca sonucun belirli bir ayrıntı düzeyinde pikselleştirilmesini sağlamaya çalışıyorsanız.
HostileFork

Yanıtlar:


126

Son Güncelleme: 2014-09-12

Öğeleri ölçeklendirirken enterpolasyonu devre dışı bırakmak için programla değiştirebileceğim bir tuval özelliği veya tarayıcı ayarı var mı?

Cevap belki bir gün . Şimdilik, istediğinizi elde etmek için etrafta dolaşmak zorunda kalacaksınız.


image-rendering

CSS3'ün çalışma taslağı,image-rendering istediğim şeyi yapması gereken yeni bir mülkün ana hatlarını çiziyor :

Görüntü oluşturma özelliği, kullanıcı aracısına uygun bir ölçekleme algoritması seçiminde yardımcı olmak için, görüntü ölçeklendiğinde bir görüntünün hangi yönlerinin korunması için en önemli olduğu konusunda kullanıcı aracısına bir ipucu sağlar.

Şartname kabul edilen üç değer özetliyor: auto, crisp-edges, ve pixelated.

pikselleştirilmiş:

Görüntüyü büyütürken, görüntünün basitçe çok büyük piksellerden oluşması için "en yakın komşu" veya benzer algoritma kullanılmalıdır. Ölçeği küçültürken bu otomatik ile aynıdır.

Standart? Çapraz tarayıcı?

Bu yalnızca bir çalışma taslağı olduğundan , bunun standart hale geleceğine dair hiçbir garanti yoktur. Tarayıcı desteği şu anda en iyi ihtimalle yetersiz.

Mozilla Geliştirici Ağı, okumanızı şiddetle tavsiye ettiğim son teknolojiye adanmış oldukça kapsamlı bir sayfaya sahiptir .

Webkit geliştiricileri başlangıçta bunu geçici olarak uygulamayı-webkit-optimize-contrast seçtiler , ancak Chromium / Chrome bunu uygulayan bir Webkit sürümü kullanmıyor gibi görünüyor.

Güncelleme: 2014-09-12

Chrome 38 artık destekliyorimage-rendering: pixelated !

Firefox'un uygulanmaya açık bir hata raporu varimage-rendering: pixelated , ancak -moz-crisp-edgesşimdilik çalışıyor.

Çözüm?

Şimdiye kadarki en çok platformlar arası, yalnızca CSS çözümü şudur:

canvas {
  image-rendering: optimizeSpeed;             /* Older versions of FF          */
  image-rendering: -moz-crisp-edges;          /* FF 6.0+                       */
  image-rendering: -webkit-optimize-contrast; /* Safari                        */
  image-rendering: -o-crisp-edges;            /* OS X & Windows Opera (12.02+) */
  image-rendering: pixelated;                 /* Awesome future-browsers       */
  -ms-interpolation-mode: nearest-neighbor;   /* IE                            */
}

Ne yazık ki bu, tüm büyük HTML5 platformlarında (özellikle Chrome) çalışmayacak.

Elbette, en yakın komşu enterpolasyonunu kullanarak görüntüleri javascript'te yüksek çözünürlüklü tuval yüzeylerine veya hatta sunucu tarafındaki önceden ölçeklendirmeyi kullanarak manuel olarak ölçeklendirilebilir, ancak benim durumumda bu çok maliyetli olacaktır, bu nedenle uygulanabilir bir seçenek değildir.

ImpactJS , tüm bu FUD'yi aşmak için bir doku ön ölçeklendirme tekniği kullanır. Impact'in geliştiricisi Dominic Szablewski bununla ilgili çok derinlemesine bir makale yazdı (hatta araştırmasında bu soruyu dile getirdi).

Özelliğe dayanan tuval tabanlı bir çözüm için Simon'ın cevabına bakın imageSmoothingEnabled(eski tarayıcılarda mevcut değildir, ancak önceden ölçeklendirmeden daha basittir ve oldukça yaygın olarak desteklenir).

Canlı Demo

canvasÖğeler üzerine MDN makalesinde tartışılan CSS özelliklerini test etmek isterseniz, tarayıcınıza bağlı olarak, bu tür bir şeyi bulanık, bulanık göstermesi gereken bu keman oluşturdum: izometrik piksel sanatı stilinde TV'nin 4: 1 (64x64 - 256x256) görüntüsü


Görüntü oluşturma başka bir yerde çalışıyor gibi görünüyor, ancak webkit tarayıcıları. Umarım Chrome / Chromium / Safari personeli "düşük yük durumlarında EPX enterpolasyonuna geç" ne anlama geldiğini iyi okur. Cümleyi ilk okuduğumda, kontrastı optimize etmenin düşük yükte yeni renklerin yaratılmasına izin verdiğini düşündüm, ancak NO: en.wikipedia.org/wiki/…
Timo Kähkönen

2
Mac ve Windows'taki Opera 12.02, görüntü oluşturmayı destekler: -o-net-kenarlar ( jsfiddle.net/VAXrL/21 ), böylece cevabınıza ekleyebilirsiniz.
Timo Kähkönen

Tarayıcı yakınlaştırmasını artırdığımda çalışması gerekiyor mu? Tarayıcı yakınlaştırması% 150 olduğunda ve sonuç tüm tarayıcılarda bulanık olduğunda Windows 7'de FF 22, Chrome 27 ve IE 10 ile çizim yapmayı test ettim. Tuval genişliğini ve yüksekliğini ikiye katladığımda ve CSS ile orijinal genişliğine ve yüksekliğine geri ayarladığımda keskin çizgiler çiziyor.
pablo

Bu iyi bir soru. Kullanıcı tanımlı ölçekleme davranışı için bir özellik olup olmadığından emin değilim.
namuol

1
Chrome 78'deyim (şimdiki gelecekten!). "Görüntü oluşturma: pikselleştirilmiş" görüyorum. Çalışma. Görünüşe göre bu, 2015 yılında Chrome 41'e eklenmiş: developers.google.com/web/updates/2015/01/pixelated
MrColes

61

Yeni cevap 31.07.2012

Bu nihayet tuval teknik özelliklerinde!

Spesifikasyon kısa süre önce imageSmoothingEnabled, truetamsayı olmayan koordinatlarda çizilen veya ölçeklenmiş olarak çizilen görüntülerin daha yumuşak bir algoritma kullanıp kullanmayacağını belirleyen ve belirleyen bir özellik ekledi . O falsezaman en yakın komşu olarak ayarlanırsa, daha az pürüzsüz bir görüntü üretir ve bunun yerine sadece daha büyük görünen pikseller oluşturur.

Görüntü düzgünleştirme tuval spesifikasyonuna yakın zamanda eklenmiştir ve tüm tarayıcılar tarafından desteklenmemektedir, ancak bazı tarayıcılar bu özelliğin satıcı tarafından önekli sürümlerini uygulamıştır. Bağlamda mozImageSmoothingEnabledFirefox webkitImageSmoothingEnabled, Chrome ve Safari'de var ve bunları false olarak ayarlamak, kenar yumuşatmanın oluşmasını durduracaktır. Ne yazık ki, yazım sırasında, IE9 ve Opera bu özelliği, satıcı tarafından önek olarak veya başka şekilde uygulamamıştır.


Önizleme: JSFiddle

Sonuç:

görüntü açıklamasını buraya girin


1
Maalesef bu da henüz çalışmıyor gibi görünüyor. Belki bir şeyi kaçırıyorum? İşte bir test: jsfiddle.net/VAXrL/187
namuol

12
Çalışması için canvas API'yi kullanarak ölçeklemeniz gerekir, CSS ile asla ölçeklendiremezsiniz ve canvas API'nin onu etkilemesini sağlayamazsınız! Şunun
Simon Sarris

1
Ancak bu sorunun doğası aslında tuvalle ilgili değil. Tarayıcının, <canvas> öğeleri dahil olmak üzere ölçeklenmiş görüntüleri nasıl oluşturduğuyla ilgilidir.
namuol

4
CSS kullanarak ölçeklendirirseniz, namuol'ün çözümü işe yarayacaktır. Görüntüyü manuel olarak Canvas'a ölçeklendirirseniz Simon'ın çözümü çalışır. Her iki durum için de çözümlerin olması güzel, bu yüzden ikinize de teşekkürler!
Shaun Lebron

IE 11 için: msImageSmoothingEnabled benim için çalışıyor! msdn.microsoft.com/en-us/library/dn265062(v=vs.85).aspx
steve

11

31.07.2012 Düzenle - Bu işlevsellik artık tuval özelliklerinde! Burada ayrı yanıta bakın:

https://stackoverflow.com/a/11751817/154112

Gelecek nesil için eski cevap aşağıdadır.


İstediğiniz etkiye bağlı olarak, bunu bir seçenek olarak görürsünüz:

var can = document.getElementById('b');
var ctx = can.getContext('2d');
ctx.scale(5,5);
$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

http://jsfiddle.net/wa95p/

Bunu yaratan:

görüntü açıklamasını buraya girin

Muhtemelen istediğin şey değil. Ama eğer sadece sıfır bulanıklığa sahip olmak istiyorsan, o zaman bu bilet olurdu, bu yüzden her ihtimale karşı teklif edeceğim.

Daha zor bir seçenek, piksel manipülasyonunu kullanmak ve iş için kendiniz bir algoritma yazmaktır. İlk görüntünün her pikseli, yeni görüntüde 5x5'lik bir piksel bloğu haline gelir. Görüntü verileriyle yapmak çok zor olmazdı.

Ancak, burada tek başına Canvas ve CSS, istediğiniz efektle birini diğerine ölçeklendirmede size yardımcı olmaz.


Evet, korktuğum şey buydu. Görünüşe göre image-rendering: -webkit-optimize-contrasthile yapmalı ama hiçbir şey yapmıyor. En yakın komşu enterpolasyonunu kullanarak bir tuvalin içeriğini ölçeklendirmek için bir işlevi döndürmeye bakabilirim.
namuol

Cevabınızı başlangıçta kabul ettim; Şimdilik iptal ettim çünkü bunun bir kopya olup olmadığı konusunda kafa karışıklığı var gibi görünüyor.
namuol

Biraz araştırma yaptıktan sonra daha eksiksiz bir cevabım var ve cevabımı sağlamak için soruyu yeniden açmak istiyorum.
namuol

3

Google chrome'da, tuval görüntü desenleri enterpolasyonlu değildir.

Burada http://jsfiddle.net/pGs4f/ namuol yanıtından düzenlenmiş bir çalışma örneği verilmiştir.

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);

Bu şimdiye kadar gördüğüm en çekici çözüm. Henüz performanstan emin değilim, ancak tamamen araştırmaya değer. Ben bunu deneyeceğim.
namuol

tekrarsız yerine tekrar kullanmak daha hızlıdır. Neden bilmiyorum. Ayrıca oldukça hızlı, three.js bunu CanvasRenderer'da kullanın
saviski

6
güncelleme: artık (nedeniyle katma retina ekran desteği?) krom 21 ile çalışan yeni versiyonu jsfiddle.net/saviski/pGs4f/12 imageSmoothingEnabled kullanarak Simon tarafından işaret
saviski

Retina çözünürlüğü genelleştiğinde, işler büyük ölçüde değişir. İPhone4-5 stili 326dpi (128dpcm) Retina ekran, 24 inç (52x32cm) monitörlere geldiğinde, ekran boyutu 6656 x 4096 piksel olacaktır. Bu durumda kenar yumuşatma kötüdür ve tüm tarayıcı satıcıları (Webkit tabanlı olsa bile) kenar yumuşatmanın devre dışı bırakılmasına izin vermek zorunda kalır. Antialiasing, işlemci yoğun bir işlemdir ve 6656 x 4096 piksellik görüntüyü düzgünleştirme çok yavaş olur, ancak neyse ki bu tür bir ekranda gereksizdir.
Timo Kähkönen

1
Bir yan not olarak, işte kalıplara karşı görüntü hakkında iyi bir kıyaslama: jsperf.com/drawimage-vs-canvaspattern/9
yckart

1

Saviski'nin burada açıklanan geçici çözümü umut vericidir, çünkü şunlarda çalışır:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 m Windows 7
  • Chromium 18.0.1025.168 (Geliştirici Derlemesi 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

Ancak aşağıda çalışmaz, ancak aynı efekt CSS görüntü oluşturma kullanılarak elde edilebilir:

  • Firefox 15.0.1 Mac OS X 10.6.8 (görüntü-işleme yer: -moz-net-kenarlar eserler bu )
  • Opera 12.02 Mac OS X 10.6.8 (görüntü-işleme yer: -o-net-kenarlar eserler bu )
  • Opera 12.02, Windows 7 (görüntü-işleme yer: -o-net-kenarlar eserler bu )

Sorunlu olanlar bunlar, çünkü ctx.XXXImageSmoothingEnabled çalışmıyor ve görüntü oluşturma çalışmıyor:

  • Safari 5.1.7 Mac OS X 10.6.8. (görüntü işleme: -webkit-optimize-kontrast çalışmaz)
  • Safari 5.1.7 Windows 7 (görüntü işleme: -webkit-optimize-kontrast ÇALIŞMAZ)
  • IE 9 Windows 7 (-ms-enterpolasyon modu: en yakın komşu ÇALIŞMAZ)
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.