Canvas From Scratch Pixel Manipulation

Nell'ultimo articolo, hai imparato tutto su trasformazioni, ombre e sfumature. Oggi, ti mostrerò come manipolare i pixel nella tela; dal semplice accesso ai valori dei colori, alla modifica delle immagini all'interno della tela come un editor di foto.

Questa è facilmente una delle funzionalità più potenti incorporate direttamente nella tela e, una volta appresa, garantisco che avrai una vasta gamma di idee interessanti.


Impostare

Utilizzerai lo stesso modello HTML degli articoli precedenti, quindi apri il tuo editor preferito e copia il seguente codice:

   Tela da zero          

Questo non è altro che una semplice pagina HTML con a tela elemento e alcuni JavaScript che vengono eseguiti dopo il caricamento del DOM. Niente di pazzo.


Posizionare un'immagine sulla tela

Puoi manipolare i pixel con qualsiasi cosa disegnata sulla tela, ma per il bene di questo tutorial, utilizzerai le immagini. Ciò è in parte dovuto al fatto che è importante mostrare come caricare le immagini nella tela, ma anche perché la possibilità di eseguire la manipolazione delle immagini (ad esempio la modifica delle foto) è un enorme punto di forza di questa tecnologia.

Prima di mostrarti come accedere ai valori dei pixel, posizioniamo un'immagine sulla tela. Sentiti libero di usare qualsiasi immagine che desideri, ma per il gusto di questo esempio, userò una delle mie foto da Flickr.

Hai il permesso di utilizzare questa foto se lo desideri, che puoi scaricare in una varietà di formati.

Il caricamento di un'immagine in una tela richiede due passaggi. Il primo è caricare l'immagine in un HTML Immagine elemento, che può essere fatto usando HTML o creando un nuovo elemento DOM direttamente all'interno di JavaScript. In questo esempio, creerai un nuovo elemento DOM: è semplice:

var image = new Image (); image.src = "sample.jpg"; $ (image) .load (function () );

Tutto quello che stai facendo qui è creare un nuovo Immagine Elemento DOM e assegnarlo a una variabile. Quindi usi quella variabile per caricare la tua immagine impostando il src attributo dell'immagine al percorso corretto. Vale la pena notare che è possibile caricare un'immagine remota usando questa tecnica, ma ciò solleva alcuni problemi per noi ulteriormente lungo la linea, quindi per ora rimarremo con un'immagine memorizzata localmente. Il passo finale è ascoltare il caricare evento che verrà attivato non appena l'immagine ha terminato il caricamento ed è disponibile per l'uso.

Una volta caricata l'immagine, puoi posizionarla sulla tela in un solo passaggio. Tutto quello che devi fare è passare il Immagine variabile che hai appena creato in una chiamata al drawImage metodo del contesto di rendering 2D. Mettilo dentro Immagine carica evento, in questo modo:

$ (image) .load (function () ctx.drawImage (image, 0, 0););

In questo caso, il drawImage il metodo accetta tre argomenti; un elemento immagine, così come il X e y coordinare i valori per posizionare l'immagine sulla tela. Questo disegnerà l'immagine a grandezza originale (500px per questa immagine) e nella posizione specificata:

però, drawImage in realtà può prendere altri due argomenti che definiscono la larghezza e l'altezza per disegnare l'immagine, in questo modo:

ctx.drawImage (immagine, 0, 0, 250, 166);

Questo disegnerebbe l'immagine a metà della dimensione originale (250 px per questa immagine):

Puoi anche fare un passo in più e usare i nove argomenti completi per drawImage per disegnare solo una piccola parte dell'immagine originale, in questo modo:

ctx.drawImage (immagine, 0, 0, 200, 200, 0, 0, 500, 500);

Ciò richiederebbe un quadrato di 200 px dall'angolo in alto a sinistra dell'immagine e lo disegnerebbe sulla tela a 500px quadrati:

In pseudo-codice, i nove completi drawImage gli argomenti possono essere descritti in questo modo (s significa sorgente, e d significa destinazione):

ctx.drawImage (immagine, sx, sy, sw, sh, dx, dy, dw, dh);

E il risultato è visualizzato nella seguente illustrazione:

Semplice, vero? In tutta onestà, niente nella tela è così complicato una volta che lo abbatti e guardi i pezzi individualmente.


Accesso ai valori dei pixel

Ora che hai un'immagine sulla tela, è ora di accedere ai pixel in modo da poterli manipolare. Tuttavia, dimentichiamoci di manipolarli per ora e concentrarci esclusivamente sull'accesso a loro mentre il concetto impiega un po 'di tempo a darti la testa.

Problemi di sicurezza

Se si desidera accedere ai pixel utilizzando la tela, è necessario essere consapevoli dei limiti di sicurezza che sono coinvolti. Queste limitazioni consentono solo di accedere ai dati dalle immagini caricate sullo stesso dominio come il JavaScript. Questo ti impedisce di accedere a un'immagine da un server remoto e quindi di analizzare i suoi pixel, anche se c'è un modo per aggirarlo, in un certo senso. Sfortunatamente non tutti i browser trattano JavaScript e immagini eseguite localmente dal file system (cioè, senza un nome di dominio) come sotto lo stesso dominio, quindi potresti ricevere errori di sicurezza. Per ovviare a questo è necessario eseguire il resto di questo tutorial su un ambiente di sviluppo locale (come MAMP, WAMP o XAMPP) o un server Web remoto e accedere ai file utilizzando un nome di dominio (come esempio.com).

Con quello fuori mano, andiamo avanti e portaci dei pixel!

Accedere a Pixel è un po 'strano

Come accennato all'inizio di questa sezione, l'accesso ai valori dei pixel nella tela richiede un po 'di tempo per capire. Ciò è dovuto al modo in cui i pixel vengono memorizzati dalla tela; non sono memorizzati come pixel interi! Invece, i pixel sono suddivisi ciascuno in quattro valori separati (rosso, verde, blu e alfa) e questi valori sono memorizzati in una matrice unidimensionale con tutti i valori di colore per gli altri pixel. Per questo motivo non puoi semplicemente richiedere i dati da un particolare pixel, almeno non di default. Lasciatemi spiegare.

Per accedere ai pixel nella tela devi chiamare il getImageData metodo del contesto di rendering 2D, in questo modo:

var imageData = ctx.getImageData (x, y, width, height);

Questo metodo accetta quattro argomenti che descrivono un'area rettangolare della tela da cui si desidera ottenere i dati dei pixel; un X e y origine, seguita da a larghezza e altezza. Restituisce a CanvasPixelArray che contiene tutti i valori di colore per i pixel all'interno dell'area definita. La prima cosa da notare con CanvasPixelArray è che ogni pixel ha quattro valori di colore, quindi l'indice del primo valore di colore per ciascun pixel all'interno dell'array sarà un multiplo di 4 (0 per il primo valore del primo pixel, 4 per il primo valore del secondo, ecc. ):

La cosa interessante di questo array (o fastidiosa, a seconda di come la si guarda) è che non esiste alcun concetto di posizione delle coordinate (x, y), il che significa che il recupero dei valori di colore per un pixel specifico è un po 'più difficile dell'accesso a due array dimensionale (ad esempio usando pixelArray [0] [3] per accedere al pixel in (1, 4)). Invece, è necessario utilizzare una piccola formula che è in realtà molto facile da capire, una volta spiegata correttamente:

var redValueForPixel = ((y - 1) * (larghezza * 4)) + ((x - 1) * 4);

Puoi capire cosa sta succedendo qui? Scopriamolo e fingiamo di voler ottenere i valori del colore dei pixel per il pixel più interno in una griglia di 3x3 pixel: il pixel a (2, 2).

Se guardi le due immagini precedenti puoi vedere che i valori di colore per questo pixel inizieranno all'indice 16, ma per risolvere il problema con il codice devi fare due cose; per prima cosa calcola l'indice all'inizio della riga in cui si trova il pixel (il y posizione), quindi aggiungere a quell'indice il numero di valori di colore esistenti tra il pixel e l'inizio della riga (il X posizione). È un po 'ingannevole, ma sopportalo.

La prima parte è facile, sai già che ci sono quattro valori di colore per pixel e conosci già la larghezza della griglia (3 pixel). Per calcolare l'indice del pixel alla riga y (2) tu passi questi valori attraverso la prima parte della formula, che assomiglierebbe così:

((2 - 1) * (3 * 4))

Questo ti dà un indice di 12, che vedrai corrispondere con il primo pixel della seconda riga nelle immagini precedenti. Fin qui tutto bene.

Il passaggio successivo consiste nel calcolare il numero di valori di colore esistenti prima del pixel che si desidera su questa riga. Per farlo basta moltiplicare il numero di pixel prima di quello desiderato per quattro. Semplice. In questo caso la seconda parte della formula sarà simile a questa:

((2 - 1) * 4)

Puoi lavorare tutto se vuoi, ma la risposta è 4, che quando aggiunto al valore precedente ti dà un indice di 16. Cool, ey?

Non mi preoccuperei troppo di comprenderlo appieno, so solo che questa formidabile formula esiste in modo che tu possa facilmente ottenere l'indice del valore del colore rosso per ogni pixel. Per ottenere l'indice degli altri valori di colore di un pixel (verde, blu o alfa), basta aggiungere 1, 2 o 3 all'indice calcolato rispettivamente.

Mettendo questo in pratica

Ora che sai come catturare i pixel che vuoi, mettiamoli in pratica e prendi i valori di colore da un'immagine per cambiare il colore di uno sfondo di un sito web. Questo tipo di tecnica funzionerebbe perfettamente come selettore di colori per un'applicazione Web di fotoritocco.

Il codice per questo esempio è abbastanza semplice, quindi attacciamolo tutto in un colpo solo:

var image = new Image (); image.src = "sample.jpg"; $ (image) .load (function () ctx.drawImage (image, 0, 0);); $ (tela) .click (function (e) var canvasOffset = $ (canvas) .offset (); var canvasX = Math.floor (e.pageX-canvasOffset.left); var canvasY = Math.floor (e.pageY -canvasOffset.top); var imageData = ctx.getImageData (0, 0, canvas.width, canvas.height); var pixels = imageData.data; var pixelRedIndex = ((canvasY - 1) * (imageData.width * 4) ) + ((canvasX - 1) * 4); var pixelcolor = "rgba (" + pixel [pixelRedIndex] + "," + pixel [pixelRedIndex + 1] + "," + pixel [pixelRedIndex + 2] + "," + pixel [pixelRedIndex + 3] + ")"; $ ("body"). css ("backgroundColor", pixelcolor););

Riconoscerai le prime poche righe degli esempi precedenti. Tutte le novità sono all'interno del gestore di clic sul tela elemento, che usa un po 'di jQuery per dirti quando il canvas è stato cliccato.

All'interno del gestore di clic, si desidera calcolare il pixel su cui il mouse ha fatto clic sulla tela. Per fare questo devi prima calcolare l'offset in pixel della posizione in alto a sinistra della tela dal bordo in alto a sinistra della finestra del browser, puoi usare il jQuery compensare metodo per questo. È quindi possibile dedurre il pixel cliccato sulla tela sottraendo l'offset dalla posizione del mouse dell'evento click (pageX e pagey). Dovresti dedicare un po 'di tempo a leggere l'evento click JavaScript se vuoi capirlo ulteriormente.

Le seguenti quattro linee afferrano il CanvasPixelArray per la tela (getImageData), memorizzarlo in una variabile, trovare l'indice del valore del colore rosso per il pixel cliccato calcolandolo usando la formula che hai visto in precedenza e quindi memorizza i valori del colore dei pixel come CSS RGBA stringa. Infine, l'ultimo passo è impostare il colore di sfondo del corpo elemento a quello del pixel cliccato.

E con questo hai finito. Provalo per te stesso; clicca sull'immagine sulla tela e guarda lo sfondo del sito cambiare colore. Se non funziona, assicurati di eseguire la demo su un server con un nome di dominio, come descritto nella sezione relativa ai problemi di sicurezza.

È stato un lungo viaggio, ma ora puoi recuperare rapidamente e facilmente i valori di colore di qualsiasi pixel sulla tela. Ti ho detto che puoi anche cambiare i valori dei colori dei pixel sulla tela? Non l'ho fatto? Oops! Diamo un'occhiata a questo ora, è fighissimo.


Applicazione di effetti alle immagini

Ora che sei in grado di accedere ai valori dei colori dei pixel della tela, cambiare questi valori è un gioco da ragazzi. In effetti, la modifica di questi valori cromatici è semplice quanto la modifica dei valori nel CanvasPixelArray e quindi disegnandolo nuovamente sulla tela. Diamo un'occhiata a come farlo.

Il primo passo è impostare il codice come hai fatto nella sezione precedente. Questo codice carica un'immagine, la disegna sulla tela e quindi acquisisce i dati dei pixel:

var image = new Image (); image.src = "sample.jpg"; $ (image) .load (function () ctx.drawImage (image, 0, 0); var imageData = ctx.getImageData (0, 0, canvas.width, canvas.height); var pixels = imageData.data; var numPixels = imageData.width * imageData.height;);

Fin qui tutto bene. Il prossimo passo è quello di scorrere ogni pixel sulla tela e cambiarne i valori cromatici. In questo esempio invertirai i colori deducendo il valore del colore corrente (da 0 a 255) da 255:

per (var i = 0; i < numPixels; i++)  pixels[i*4] = 255-pixels[i*4]; // Red pixels[i*4+1] = 255-pixels[i*4+1]; // Green pixels[i*4+2] = 255-pixels[i*4+2]; // Blue ;

Qui non c'è niente di pazzo; stai semplicemente moltiplicando il numero di pixel (io) per 4 per ottenere l'indice del valore del colore rosso per quel pixel nel CanvasPixelArray. Aggiungendo 1 o 2 a quel numero è possibile ottenere e modificare rispettivamente i valori di colore verde e blu.

Infine, tutto ciò che devi fare ora è cancellare la tela (per eliminare l'immagine normale), e quindi usare il putImageData metodo del contesto di rendering 2D per disegnare il salvataggio CanvasPixelArray alla tela:

ctx.clearRect (0, 0, canvas.width, canvas.height); ctx.putImageData (imageData, 0, 0);

E questo è onestamente tutto quello che c'è da fare; ricarica il tuo browser e dai un'occhiata a te stesso. Cool, non è vero??


Avvolgere le cose

C'è molto di più nella manipolazione dei pixel nella tela, ma spero che tu abbia già sperimentato abbastanza in questo articolo per far fluire i tuoi succhi. Vi incoraggio ad esplorare ulteriormente quest'area e vedere cos'altro potete fare con i pixel. Perché? Perché tutte le tecniche che ti piacciono sulla manipolazione dei pixel possono essere utilizzate per video HTML5 e immagini. Ora è bello!

Nel prossimo articolo, l'ultimo di questa serie, daremo uno sguardo diverso alla tela. Questa volta imparerai come animare sulla tela, che ti fornirà le basi necessarie per creare cartoni animati, animazioni e giochi. Questo è indubbiamente il mio uso preferito della tela.