Il faut le rappeler : Canvas est une surface de pixels. D'un point de vue de l'accessibilité (et par rapport à SVG) c'est un gros inconvénient car sans alternative c'est un véritable trou noir sans contenu propre. Si l'on place cet inconvénient de coté et que l'on fait appel à Canvas en conscience de cause, tous les pixels sont "accessibles" avec les méthodes createImageData
(création ex-nihilo), putImageData
(écriture) et getImageData
(lecture).
Cela signifie que l'on peut opérer des traitements sur l'image, ou générer un tableau de pixels à partir d'un quelconque algorithme pour ensuite l'injecter sur la totalité ou une partie du dessin.
createImageData(x,y)
crée un tableau de pixels RGBa de dimension (x * y). En revanche, il faut bien comprendre son fonctionnement vis-à-vis des pixels qui sont définis par 4 composantes et ne sont pas stockés un à un dans chacune des "cases" du tableau. Ce sont leurs valeurs Rouge, Vert, Bleu et Alpha qui remplissent individuellement et une à une ces "cases".
Au premier index [0] on retrouvera donc la valeur Rouge du premier pixel, puis dans [1] la valeur Vert, puis dans [2] la valeur Bleu et dans [3] la valeur Alpha (transparence). On retrouvera la valeur Rouge du second pixel à l'index [4], et ainsi de suite. Par exemple, createImageData(100,100)
devra stocker l'information de 1000 pixels ce qui produira un tableau à 4000 valeurs.
- [0] : R pixel 1
- [1] : G pixel 1
- [2] : B pixel 1
- [3] : A pixel 1
- [4] : R pixel 2
- [5] : G pixel 2
- [6] : B pixel 2
- [7] : A pixel 2
- ...
Pour parcourir l'ensemble des valeurs, pixel par pixel, il faudra sauter de 4 en 4 !
var imageData = ctx.createImageData(100,100);
var mapPixel = imageData.data; // Récupération du tableau de pixels dans la propriété data
// Accès à au premier pixels du tableau
mapPixel[0]; // valeur rouge du premier pixel
mapPixel[1]; // valeur verte du premier pixel
mapPixel[2]; // valeur bleue du premier pixel
mapPixel[3]; // valeur de transparence(alpha) du premier pixel
Le code ci-dessus est une simple représentation pour montrer que l'on peut facilement accéder aux valeurs de chaque pixel avec une boucle, tel que while
ou for
. La fonction createImageData(ImageData)
peut aussi recevoir en argument une image source ce qui amène ensuite à la possibilité de faire des traitements et améliorations sur celle-ci.
Les deux autres méthodes vont récupérer ou injecter les valeurs dans le canvas, à partir des données manipulées :
-
getImageData(x,y,width,height)
: création d'un objet ImageData à partir d'une zone du contexte de dessin (portion du Canvas dont le coin supérieur gauche est défini par x,y et les dimensions par width et height). -
putImageData(x,y)
est la méthode de restitution/aposition de l'ImageData dans Canvas. Une fois tous les traitements finis, c'est cette fonction qu'il faudra appeler.
var imageData = ctx.createImageData(100,100);
var mapPixel = imageData.data; // Récupération du tableau de pixels
// On va rendre tout ça tout bleu avec une opacité de 50%
for(var i=0 ; i < mapPixel.length ;i+=4){
mapPixel[i+2] = 200; // Bleu
mapPixel[i+3] = 128; // Alpha
}
// On injecte les données au point 50,50
ctx.putImageData( imageData , 50 , 50 );
Retouche des pixels
Voici un traitement de l'image pour appliquer un "filtre" sur les différents canaux de couleurs.
var img_chat = new Image();
img_chat.src = "img/lyra.png";
img_chat.onload = function(){
ctx.drawImage(img_chat, 75, 15);
var copie_img_chat = ctx.getImageData( 75, 15, img_chat.width, img_chat.height);
var data = copie_img_chat.data;
for(var i = 0; i < data.length; i += 4) {
var b = 0.3 * data[i] + 0.3 * data[i + 1] + 0.3 * data[i + 2];
data[i] = b; // Rouge
data[i + 1] = b; // Vert
data[i + 2] = b; // Bleu
// data[i+3] // Alpha (non modifié)
}
// copie le résultat 10px en-dessous de l'original
ctx.putImageData( copie_img_chat, 75, 35 + img_chat.height );
}
Commentaires
C'est en effet une restriction de sécurité : il faut utiliser les ressources du domaine qui héberge déjà la page (afin de ne pas extraire les informations d'un domaine tiers). Donc localhost peut fonctionner pour les tests (plutôt qu'une adresse IP, ou un accès via file:// qui ne permet pas d'appliquer une règle de sécurité propre à un domaine).
Merci pour ce tuto qui va à l'essentiel.
Même 6 ans après sa création, il me semble toujours d'actualité.
Peut-être une petite coquille dans la partie 7 :
"...createImageData(100,100) devra stocker l'information de 1000 pixels ce qui produira un tableau à 4000 valeurs."
100 * 100 = 10 000, donc 40 000 valeurs