Canvas From Scratch Manipulation de pixels

Dans le dernier article, vous avez tout appris sur les transformations, les ombres et les dégradés. Aujourd'hui, je vais vous montrer comment manipuler des pixels dans un canevas. de simplement accéder aux valeurs de couleur, à l'édition d'images dans le canevas comme un éditeur de photos.

C’est facilement l’une des fonctionnalités les plus puissantes intégrées directement dans la toile, et une fois que vous l’avez apprise, je vous garantis que vous aurez toute une gamme d’idées excitantes..


Mise en place

Vous allez utiliser le même modèle HTML des articles précédents, ouvrez votre éditeur favori et copiez-le dans le code suivant:

   Toile à partir de zéro          

Ce n’est rien de plus qu’une page HTML de base avec un Toile élément et du code JavaScript exécuté après le chargement du DOM. Rien de fou.


Placer une image sur la toile

Vous pouvez manipuler des pixels avec n'importe quoi dessiné sur la toile, mais pour les besoins de ce didacticiel, vous utiliserez des images. Ceci est en partie dû au fait qu'il est important de vous montrer comment charger des images dans le canevas, mais également au fait que la possibilité de manipuler des images (par exemple, l'édition de photos) est un avantage considérable de cette technologie..

Avant de vous montrer comment accéder aux valeurs en pixels, plaçons une image sur le canevas. N'hésitez pas à utiliser l'image de votre choix, mais pour cet exemple, je vais utiliser l'une de mes propres photos à partir de Flickr..

Vous avez la permission d'utiliser cette photo si vous le souhaitez, que vous pouvez télécharger en différentes tailles.

Le chargement d'une image dans la zone de dessin nécessite deux étapes. La première consiste à charger l'image dans un fichier HTML image élément, ce qui peut être fait en utilisant HTML ou en créant un nouvel élément DOM directement dans JavaScript. Dans cet exemple, vous allez créer un nouvel élément DOM. C'est simple:

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

Tout ce que vous faites ici est de créer un nouveau Image Élément DOM et l'assignation à une variable. Vous utilisez ensuite cette variable pour charger votre image en définissant la src attribut de l'image au bon chemin. Il est intéressant de noter que vous pouvez charger une image distante en utilisant cette technique, mais cela pose quelques problèmes pour nous plus tard et nous allons donc nous en tenir à une image stockée localement pour le moment. La dernière étape consiste à écouter pour le charge événement qui sera déclenché dès que le chargement de l'image sera terminé et qu'il sera disponible.

Une fois l'image chargée, vous pouvez la placer facilement sur le canevas. Tout ce que vous avez à faire est de passer le image variable que vous venez de créer dans un appel à la drawImage méthode du contexte de rendu 2D. Placez-le à l'intérieur du image événement de chargement, comme suit:

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

Dans ce cas, le drawImage méthode prend trois arguments; un élément d'image, ainsi que le X et y coordonner les valeurs pour placer l'image sur la toile. Cela va dessiner l'image en taille réelle (500px pour cette image) et à la position spécifiée:

toutefois, drawImage peut prendre deux autres arguments qui définissent la largeur et la hauteur pour dessiner l’image, comme ceci:

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

Cela dessinerait l’image à la moitié de la taille originale (250px pour cette image):

Vous pouvez même aller un peu plus loin et utiliser les neuf arguments pour drawImage pour ne dessiner qu'une petite partie de l'image originale, comme ceci:

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

Cela prendrait un carré de 200 pixels en haut à gauche de l'image et le dessinait sur la toile au carré de 500 pixels:

En pseudo-code, le neuf complet drawImage les arguments peuvent être décrits comme suit (s signifiant source et d signifiant destination):

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

Et le résultat est visualisé dans l'illustration suivante:

Simple, non? En toute honnêteté, rien dans la toile n'est aussi compliqué une fois que vous l'avez décomposée et regardée les pièces individuellement.


Accéder aux valeurs de pixels

Maintenant que vous avez une image sur la toile, il est temps d'accéder aux pixels pour pouvoir les manipuler. Cependant, oublions de les manipuler pour le moment et concentrons-nous uniquement sur leur accès, car le concept met un peu de temps à vous faire comprendre..

Les problèmes de sécurité

Si vous souhaitez accéder aux pixels à l'aide de la zone de dessin, vous devez connaître les limites de sécurité associées. Ces limitations vous permettent uniquement d’accéder aux données des images chargées sur le même domaine comme le JavaScript. Cela vous empêche d'accéder à une image d'un serveur distant et d'analyser ses pixels, bien qu'il existe un moyen de la contourner, en quelque sorte. Malheureusement, tous les navigateurs ne traitent pas JavaScript et les images s'exécutant localement à partir du système de fichiers (c'est-à-dire sans nom de domaine) comme appartenant au même domaine. Vous risquez donc de recevoir des erreurs de sécurité. Pour résoudre ce problème, vous devez exécuter le reste de ce didacticiel sur un environnement de développement local (tel que MAMP, WAMP ou XAMPP) ou un serveur Web distant et accéder aux fichiers à l'aide d'un nom de domaine (tel que exemple.com)..

Avec ça, passons à l'action et obtenons-nous des pixels!

Accéder aux pixels est un peu étrange

Comme je l'ai mentionné au début de cette section, accéder aux valeurs de pixels dans le canevas prend un peu de temps pour comprendre. Cela est dû à la manière dont les pixels sont stockés par canvas. ils ne sont pas stockés sous forme de pixels entiers! Au lieu de cela, les pixels sont chacun divisés en quatre valeurs distinctes (rouge, vert, bleu et alpha) et ces valeurs sont stockées dans un tableau unidimensionnel avec toutes les valeurs de couleur pour les autres pixels. Pour cette raison, vous ne pouvez pas simplement demander les données d'un pixel particulier, du moins pas par défaut. Laisse-moi expliquer.

Pour accéder aux pixels de la toile, vous devez appeler le getImageData méthode du contexte de rendu 2D, comme suit:

var imageData = ctx.getImageData (x, y, largeur, hauteur);

Cette méthode prend quatre arguments qui décrivent une zone rectangulaire de la toile à partir de laquelle vous voulez que les données de pixel soient; un X et y origine, suivi d'un largeur et la taille. Il retourne un CanvasPixelArray qui contient toutes les valeurs de couleur pour les pixels de la zone définie. La première chose à remarquer avec le CanvasPixelArray est que chaque pixel a quatre valeurs de couleur, donc l'indice de la première valeur de couleur pour chaque pixel de la matrice sera un multiple de 4 (0 pour la première valeur du premier pixel, 4 pour la première valeur de la seconde, etc. ):

Ce qui est intéressant à propos de ce tableau (ou énervant, selon votre apparence) est qu’il n’existe pas de concept de position de coordonnées (x, y), ce qui signifie que récupérer des valeurs de couleur pour un pixel spécifique est un peu plus difficile que d’accéder à deux pixels). tableau dimensionnel (par exemple, en utilisant pixelArray [0] [3] pour accéder au pixel en (1, 4)). Au lieu de cela, vous devez utiliser une petite formule très facile à comprendre une fois expliquée correctement:

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

Pouvez-vous comprendre ce qui se passe ici? Décrivons-le et supposons que nous voulons obtenir les valeurs de couleur de pixel du pixel le plus interne dans une grille de 3x3 pixels - le pixel situé en (2, 2)..

Si vous regardez les deux images précédentes, vous pouvez voir que les valeurs de couleur de ce pixel commencent à l’index 16, mais pour résoudre ce problème avec du code, vous devez effectuer deux opérations: calculez d’abord l’indice au début de la ligne sur laquelle se trouve le pixel (le y position), puis ajoutez à cet index le nombre de valeurs de couleur existant entre le pixel et le début de la ligne (le X position). C'est un peu un esprit-bender, mais supporte avec ça.

La première partie est facile, vous savez déjà qu'il y a quatre valeurs de couleur par pixel et vous connaissez déjà la largeur de la grille (3 pixels). Pour calculer l'index du pixel à la ligne y (2) vous transmettez ces valeurs dans la première partie de la formule, qui ressemble à ceci:

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

Cela vous donne un indice de 12, que vous verrez correspondre au premier pixel de la deuxième ligne des images précédentes. Jusqu'ici tout va bien.

L'étape suivante consiste à calculer le nombre de valeurs de couleur existant avant le pixel souhaité sur cette ligne. Pour ce faire, il vous suffit de multiplier par quatre le nombre de pixels précédant celui que vous souhaitez. Simple. Dans ce cas, la deuxième partie de la formule ressemblerait à ceci:

((2 - 1) * 4)

Vous pouvez résoudre le problème si vous le souhaitez, mais la réponse est 4, ce qui, ajouté à la valeur précédente, vous donne un indice de 16. Cool, ey?

Je ne m'inquiéterais pas trop de la comprendre complètement, sachez simplement que cette étonnante petite formule existe pour que vous puissiez facilement obtenir l'index de la valeur de couleur rouge pour n'importe quel pixel. Pour obtenir l'index des autres valeurs de couleur d'un pixel (vert, bleu ou alpha), il vous suffit d'ajouter 1, 2 ou 3 à l'indice calculé, respectivement..

Mettre cela en pratique

Maintenant que vous savez comment saisir le pixel de votre choix, mettons-nous en pratique et saisissons les valeurs de couleur d'une image pour modifier la couleur de l'arrière-plan d'un site Web. Ce type de technique fonctionnerait très bien comme sélecteur de couleur pour une application Web de retouche photo.

Le code de cet exemple est assez simple, alors attaquons-le d'un coup:

var image = new Image (); image.src = "sample.jpg"; $ (image) .load (fonction () ctx.drawImage (image, 0, 0);); $ (canvas) .click (fonction (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 (" + pixels [pixelRedIndex] + "," + pixels [pixelRedIndex + 1] + "," + pixels [pixelRedIndex + 2] + "," + pixels [pixelRedIndex + 3] + ")"; $ ("corps"). css ("backgroundColor", pixelcolor););

Vous reconnaîtrez les premières lignes des exemples précédents. Toutes les nouveautés se trouvent dans le gestionnaire de clics sur le Toile élément, qui utilise un tout petit peu de jQuery pour vous dire quand la toile a été cliquée.

Dans le gestionnaire de clics, vous souhaitez définir le pixel sur lequel la souris a cliqué sur le fond. Pour ce faire, vous devez d’abord calculer le décalage en pixels de la position en haut à gauche du canevas à partir du bord supérieur gauche de la fenêtre du navigateur. Vous pouvez utiliser jQuery. décalage méthode pour cela. Vous pouvez alors déduire le pixel cliqué sur la toile en soustrayant le décalage de la position de la souris de l'événement click (pageX et pageY). Vous devriez certainement passer un peu de temps à lire l'événement click de JavaScript si vous voulez comprendre davantage.

Les quatre lignes suivantes saisissent la CanvasPixelArray pour la toile (getImageData), stockez-le dans une variable, recherchez l'index de la valeur de couleur rouge pour le pixel cliqué en le calculant à l'aide de la formule que vous avez vue précédemment, puis stockez les valeurs de couleur de pixel en tant que CSS rgba chaîne. Enfin, la dernière étape consiste à définir la couleur d’arrière-plan du corps élément à celui du pixel cliqué.

Et avec ça vous avez fini. Essayez vous-même; Cliquez sur l'image sur la toile et regardez le fond du site changer de couleur. Si cela ne fonctionne pas, assurez-vous que vous exécutez la démo sur un serveur avec un nom de domaine, comme décrit dans la section relative aux problèmes de sécurité..

La route a été longue, mais vous pouvez maintenant récupérer rapidement et facilement les valeurs de couleur de n’importe quel pixel de la toile. Vous ai-je dit que vous pouvez également modifier les valeurs de couleur des pixels sur le canevas? Je n'ai pas? Oops! Jetons un coup d'oeil à cela maintenant alors, c'est cool cool.


Appliquer des effets aux images

Maintenant que vous pouvez accéder aux valeurs de couleur en pixels du canevas, la modification de ces valeurs est un jeu d'enfant. En fait, changer ces valeurs de couleur est aussi simple que de changer les valeurs dans le CanvasPixelArray puis le dessiner sur la toile. Voyons comment faire.

La première étape consiste à configurer le code comme vous l'avez fait dans la section précédente. Ce code charge une image, la dessine sur le canevas, puis récupère les données en pixels:

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

Jusqu'ici tout va bien. L'étape suivante consiste à parcourir en boucle chaque pixel de la toile et à modifier ses valeurs de couleur. Dans cet exemple, vous allez inverser les couleurs en déduisant la valeur de couleur actuelle (0 à 255) de 255:

pour (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 ;

Il n'y a rien de fou ici; vous multipliez simplement le nombre de pixels (je) par 4 pour obtenir l'index de la valeur de couleur rouge pour ce pixel dans la CanvasPixelArray. En ajoutant 1 ou 2 à ce nombre, vous pouvez obtenir et modifier les valeurs de couleur verte et bleue respectivement.

Enfin, tout ce que vous avez à faire maintenant est de vider le fond (pour vous débarrasser de l’image normale), puis d’utiliser la commande putImageData méthode du contexte de rendu 2D pour dessiner la sauvegarde CanvasPixelArray à la toile:

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

Et c’est tout ce qu’il ya à faire; Rechargez votre navigateur et jetez un coup d'oeil par vous-même. Cool, n'est ce pas?


Envelopper les choses

Il y a tellement plus à manipuler les pixels dans la toile, mais j'espère que vous avez suffisamment expérimenté cet article pour que votre jus coule à flot. Je vous encourage à explorer davantage cette zone et à voir ce que vous pouvez faire d'autre avec les pixels. Pourquoi? Toutes les techniques que vous avez utilisées concernant la manipulation des pixels peuvent être utilisées pour la vidéo HTML5 ainsi que pour les images. Maintenant c'est cool!

Dans le prochain article, le dernier de cette série, nous examinerons la toile différemment. Cette fois, vous apprendrez à animer sur la toile, ce qui vous donnera les bases nécessaires à la création de dessins animés, d’animations et de jeux. Ceci est sans aucun doute mon utilisation préférée de la toile.