Disabilita interpolazione quando ridimensiona un

NOTA : questo ha a che fare con il modo in cui gli elementi canvas esistenti vengono renderizzati quando vengono ridimensionati , non con il modo in cui le linee o la grafica vengono renderizzate su una superficie di canvas . In altre parole, tutto ciò ha a che fare con l’ interpolazione di elementi in scala e nulla con l’ antialiasing della grafica disegnata su una canvas. Non mi interessa come il browser disegna le linee; Mi interessa come il browser esegue il rendering dell’elemento Canvas quando viene ridimensionato.


Esiste una proprietà canvas o un’impostazione del browser che posso modificare a livello di codice per disabilitare l’interpolazione quando ridimensiona gli elementi ? Una soluzione cross-browser è ideale ma non essenziale; I browser basati su Webkit sono il mio objective principale. Le prestazioni sono molto importanti.

Questa domanda è molto simile ma non illustra sufficientemente il problema. Per quello che vale, ho provato il image-rendering: -webkit-optimize-contrast senza successo.

L’applicazione sarà un gioco in stile “retro” a 8 bit scritto in HTML5 + JS per chiarire ciò di cui ho bisogno.


Per illustrare, ecco un esempio. ( versione live )

Supponiamo che abbia una canvas 21×21 …

  

… che ha css che rende l’elemento 5 volte più grande (105×105):

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

Disegno una semplice “X” sulla canvas in questo modo:

 $('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(); }); 

L’immagine a sinistra è ciò che rende Chromium (14.0). L’immagine a destra è ciò che voglio (disegnato a mano a scopo illustrativo).

Chrome interpola elementi di canvas in scalaUna versione non interpolata

Ultimo aggiornamento: 2014-09-12

Esiste una proprietà canvas o un’impostazione del browser che posso modificare a livello di codice per disabilitare l’interpolazione durante il ridimensionamento degli elementi?

La risposta è forse un giorno . Per ora, dovrai ricorrere a hack-around per ottenere ciò che desideri.


image-rendering

La bozza di lavoro del CSS3 delinea una nuova proprietà, il image-rendering che dovrebbe fare ciò che voglio:

La proprietà di rendering delle immagini fornisce un suggerimento all’agente utente su quali aspetti di un’immagine sono più importanti da conservare quando l’immagine viene ridimensionata, per aiutare l’utente-agente nella scelta di un algoritmo di ridimensionamento appropriato.

La specifica delinea tre valori accettati: auto , crisp-edges e pixelated .

pixel:

Quando si ridimensiona l’immagine, è necessario utilizzare il “prossimo più vicino” o un algoritmo simile, in modo che l’immagine appaia semplicemente composta di pixel molto grandi. Quando si ridimensiona, questo è lo stesso di auto.

Standard? Cross-browser?

Poiché si tratta solo di una bozza di lavoro , non vi è alcuna garanzia che ciò diventi standard. Il supporto del browser è attualmente discutibile, nel migliore dei casi.

Mozilla Developer Network ha una pagina piuttosto approfondita dedicata allo stato dell’arte che consiglio vivamente di leggere.

Inizialmente, gli sviluppatori di Webkit hanno scelto di implementare provvisoriamente questo come -webkit-optimize-contrast , ma Chromium / Chrome non sembrano utilizzare una versione di Webkit che implementa questo.

Aggiornamento: 2014-09-12

Chrome 38 ora supporta il image-rendering: pixelated !

Firefox ha un bug report aperto per ottenere il image-rendering: pixelated implementato in image-rendering: pixelated , ma per ora -moz-crisp-edges funziona.

Soluzione?

La soluzione cross-platform, CSS-only, finora è così:

 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 */ } 

Purtroppo questo non funzionerà ancora su tutte le principali piattaforms HTML5 (Chrome, in particolare).

Ovviamente, è ansible ridimensionare manualmente le immagini utilizzando l’interpolazione più vicina al prossimo su superfici di canvas ad alta risoluzione in javascript, o anche immagini di pre-scala sul lato server, ma nel mio caso questo sarà eccessivamente costoso quindi non è un’opzione praticabile.

ImpactJS utilizza una tecnica di pre-ridimensionamento delle texture per aggirare tutto questo FUD. Lo sviluppatore di Impact, Dominic Szablewski, ha scritto un articolo molto approfondito su questo (ha persino finito col citare questa domanda nella sua ricerca).

Vedi la risposta di Simon per una soluzione basata su canvas che si basa sulla proprietà imageSmoothingEnabled (non disponibile nei browser più vecchi, ma più semplice del pre-ridimensionamento e ampiamente supportata).

Dimostrazione dal vivo

Se desideri testare le proprietà CSS discusse nell’articolo MDN sugli elementi canvas , ho creato questo violino che dovrebbe mostrare qualcosa di simile, sfocato o meno, a seconda del browser: un'immagine 4: 1 (64x64 a 256x256) di una TV isometrica in stile pixel art

Nuova risposta 31/07/2012

Questo è finalmente nella specifica della canvas!

La specifica ha recentemente aggiunto una proprietà denominata imageSmoothingEnabled , che ha come valore predefinito true e determina se le immagini disegnate su coordinate non interi o disegnate in scala utilizzeranno un algoritmo più fluido. Se è impostato su false , viene utilizzato il neighbor-neighbor più vicino, producendo un’immagine meno liscia e invece creando solo pixel dall’aspetto più grande.

Il livellamento dell’immagine è stato aggiunto solo di recente alle specifiche del canvas e non è supportato da tutti i browser, ma alcuni browser hanno implementato versioni con prefisso del produttore di questa proprietà. Nel contesto esiste mozImageSmoothingEnabled in Firefox e webkitImageSmoothingEnabled in Chrome e Safari, e impostandoli su false fermerà l’anti-aliasing. Sfortunatamente, al momento della stesura di questo documento, IE9 e Opera non hanno implementato questa proprietà, il venditore ha prefisso o altro.


Anteprima: JSFiddle

Risultato:

inserisci la descrizione dell'immagine qui

Modifica 31/07/2012 – Questa funzionalità è ora nella specifica della canvas! Vedi la risposta separata qui:

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

La vecchia risposta è sotto per i posteri.


A seconda dell’effetto desiderato, hai questa opzione come una:

 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/

Che crea questo:

inserisci la descrizione dell'immagine qui

Probabilmente non è quello che vuoi. Ma se tu stavi semplicemente cercando di avere zero sfocatura, allora quello sarebbe il biglietto quindi lo offrirò per ogni evenienza.

Un’opzione più difficile è usare la manipolazione dei pixel e scrivere un algoritmo per il lavoro. Ogni pixel della prima immagine diventa un blocco 5×5 di pixel sulla nuova immagine. Non sarebbe troppo difficile da fare con imagedata.

Ma Canvas e CSS da soli non ti aiuteranno qui per ridimensionare l’uno con l’altro con l’effetto esatto che desideri.

In google chrome, i pattern delle immagini su canvas non sono interpolati.

Ecco un esempio funzionante modificato dalla risposta namuol http://jsfiddle.net/pGs4f/

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

La soluzione di Saviski illustrata qui è promettente, perché funziona su:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 m Windows 7
  • Chromium 18.0.1025.168 (Developer Build 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

Ma non funziona nel modo seguente, ma lo stesso effetto può essere ottenuto usando il rendering delle immagini CSS:

  • Firefox 15.0.1 Mac OS X 10.6.8 (image-rendering: -moz-crisp-edges funziona in questo )
  • Opera 12.02 Mac OS X 10.6.8 (rendering dell’immagine: -o-crisp-edges funziona in questo )
  • Opera 12.02 Windows 7 (rendering delle immagini: -o-crisp-edges funziona in questo )

Le problematiche sono queste, perché ctx.XXXImageSmoothingEnabled non funziona e il rendering delle immagini non funziona:

  • Safari 5.1.7 Mac OS X 10.6.8. (image-rendering: -webkit-optimize-contrast NON funziona)
  • Safari 5.1.7 Windows 7 (image-rendering: -webkit-optimize-contrast NON funziona)
  • IE 9 Windows 7 (-ms-interpolation-mode: il più vicino-vicino NON funziona)