MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

Cette traduction est incomplète. Aidez à traduire cet article depuis l'anglais.

Jusqu'à présent, nous n'avons pas examiné dans le détail les pixels réels de notre canevas. Avec l'objet ImageData, vous pouvez directement lire et écrire dans le tableau de données de l'image pour manipuler les pixels un par un. Nous verrons également comment le lissage (anticrénelage) de l'image peut être contrôlé et comment sauvegarder des images depuis votre canevas.

L'objet ImageData

L'objet ImageData représente les données de pixels sous-jacentes à une zone d'un objet canevas. Il contient les attributs (en lecture seule) suivants :

width
La largeur de l'image en pixels.
height
La hauteur de l'image en pixels.
data
Un Uint8ClampedArray représentant un tableau monodimensionnel contenant les données dans l'ordre RGBA, ayant des valeurs entières entre 0 et  255 (inclus).

La propriété data retourne un tableau Uint8ClampedArray auquel on peut accéder pour voir plus en détail les données brutes des pixels ; chaque pixel est représenté par quatre valeurs sur un octet (rouuge, vert, bleu, et alpha, dans cet ordre ; c'est-à-dire, le format "RGBA").  Chaque composante de couleur est représentée par un entier entre 0 et 255. Chaque composante reçoit un indice à l'intérieur du tableau, la composante rouge du pixel supérieur gauche étant à l'indice 0 à l'intérieur du tableau. Les pixels continuent ensuite de gauche à droite, puis vers le bas, jusqu'au bout du tableau.

Le Uint8ClampedArray contient height × width × 4 octets, dont les valeurs d'indices vont de 0 à (height×width×4)-1.

Par exemple, pour lire la valeur de la composante bleue d'un pixel situé en colonne 200, ligne 50  de l'image, vous pouvez faire ce qui suit :

composanteBleue = imageData.data[((50 * (imageData.width * 4)) + (200 * 4)) + 2];

Vous pouvez accéder à la taille en octets du tableau de pixels en lisant l'attribut Uint8ClampedArray.length :

var nbOctets = imageData.data.length;

Création d'un objet ImageData

Pour créer un nouvel objet ImageData vierge, vous pouvez utiliser la méthode createImageData(). Il existe deux versions de la méthode createImageData() :

var monImageData = ctx.createImageData(largeur, hauteur);

Cela crée un nouvel objet ImageData avec les dimensions spécifiées. Tous les pixels sont prédéfinis comme étant noirs transparents.

Vous pouvez aussi créer un nouvel objet ImageData ayant les mêmes dimensions que celles de l'objet indiqué par autreImageData. Les pixels du nouvel objet sont tous prédéfinis comme étant noirs transparents. Cela ne copie pas les données d'image !

var monImageData = ctx.createImageData(autreImageData);

Obtention des données pixel pour un contexte

Pour obtenir un objet  ImageData contenant une copie des données pixel pour un contexte de canevas, vous pouvez utiliser la méthode getImageData() :

var monImageData = ctx.getImageData(gauche, haut, largeur, hauteur);

Cette méthode retourne un objet ImageData représentant les données pixel pour la zone du canevas dont les coins sont représentés par les points (gauche,haut), (gauche+largeur, haut), (gauche, haut+hauteur), et (gauche+largeur, haut+hauteur). Les coordonnées sont spécifiées en unités d'espace de coordonnées de canevas.

Note : Tous les pixels en dehors du canevas seront retournés comme noirs transparents dans l'objet ImageData résultant.

Cette méthode est aussi présentée dans l'article Manipulation vidéo utilisant canvas.

Une pipette à couleur

Dans cet exemple, nous utilisons la méthode getImageData() pour afficher la couleur en dessous du curseur de la souris. Pour cela, nous avons besoin de la position en cours de la souris donnée par layerX et layerY, nous recherchons ensuite les données pixel à cette position dans le tableau de pixels que getImageData() nous fournit. Finalement, nous utilisons les données du tableau pour définir une couleur d'arrière-plan et un texte dans le <div> pour afficher la couleur.

var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
};
var color = document.getElementById('color');
function pick(event) {
  var x = event.layerX;
  var y = event.layerY;
  var pixel = ctx.getImageData(x, y, 1, 1);
  var data = pixel.data;
  var rgba = 'rgba(' + data[0] + ', ' + data[1] +
             ', ' + data[2] + ', ' + (data[3] / 255) + ')';
  color.style.background =  rgba;
  color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);

Peindre les données pixel dans un contexte

Vous pouvez utiliser la méthode putImageData() pour peindre les données pixel dans un contexte :

ctx.putImageData(monImageData, dx, dy);

Les paramètres dx et dy indiquent les coordonnées système dans le contexte auxquelles doit être peint le coin supérieur gauche des données pixel que vous souhaitez dessiner.

Par exemple, pour peindre l'image entière représentée par monImageData dans le coin supérieur gauche du contexte, vous pouvez simplement faire ce qui suit :

ctx.putImageData(monImageData, 0, 0);

Niveau de gris et inversion des couleurs

Dans cet exemple, nous itérons sur tous les pixels pour changer leurs valeurs, puis nous remettons le tableau de pixels modifié sur le canevas à l'aide de putImageData(). La fonction inversion soustrait simplement chaque couleur de la valeur maximale 255. La fonction niveaudegris fait simplement la moyenne du rouge, du vert et du bleu. Vous pouvez également utiliser une moyenne pondérée, donnée par la formule x = 0.299r + 0.587v + 0.114b, par exemple. Voir Niveau de gris sur Wikipedia pour plus d'informations.

var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
img.onload = function() {
  dessiner(this);
};

function dessiner(img) {
  var canevas = document.getElementById('canevas');
  var ctx = canevas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
  var imageData = ctx.getImageData(0, 0, canevas.width, canevas.height);
  var data = imageData.data;
    
  var inversion = function() {
    for (var i = 0; i < data.length; i += 4) {
      data[i]     = 255 - data[i];     // rouge
      data[i + 1] = 255 - data[i + 1]; // vert
      data[i + 2] = 255 - data[i + 2]; // bleu
    }
    ctx.putImageData(imageData, 0, 0);
  };

  var niveaudegris = function() {
    for (var i = 0; i < data.length; i += 4) {
      var moy = (data[i] + data[i + 1] + data[i + 2]) / 3;
      data[i]     = moy; // rouge
      data[i + 1] = moy; // vert
      data[i + 2] = moy; // bleu
    }
    ctx.putImageData(imageData, 0, 0);
  };

  var btninversion = document.getElementById('btninversion');
  btninversion.addEventListener('click', inversion);
  var btnniveaudegris = document.getElementById('btnniveaudegris');
  btnniveaudegris.addEventListener('click', niveaudegris);
}

Zooming and anti-aliasing

With the help of the drawImage() method, a second canvas and the imageSmoothingEnabled property, we are able to zoom into our picture and see the details.

We get the position of the mouse and crop an image of 5 pixels left and above to 5 pixels right and below. Then we copy that one over to another canvas and resize the image to the size we want it to. In the zoom canvas we resize a 10×10 pixel crop of the original canvas to 200×200.

zoomctx.drawImage(canvas, 
                  Math.abs(x - 5), Math.abs(y - 5),
                  10, 10, 0, 0, 200, 200);

Because anti-aliasing is enabled by default, we might want to disable the smoothing to see clear pixels. You can toggle the checkbox to see the effect of the imageSmoothingEnabled property (which needs prefixes for different browsers).

var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
img.onload = function() {
  draw(this);
};

function draw(img) {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
  var zoomctx = document.getElementById('zoom').getContext('2d');
 
  var smoothbtn = document.getElementById('smoothbtn');
  var toggleSmoothing = function(event) {
    zoomctx.imageSmoothingEnabled = this.checked;
    zoomctx.mozImageSmoothingEnabled = this.checked;
    zoomctx.webkitImageSmoothingEnabled = this.checked;
    zoomctx.msImageSmoothingEnabled = this.checked;
  };
  smoothbtn.addEventListener('change', toggleSmoothing);

  var zoom = function(event) {
    var x = event.layerX;
    var y = event.layerY;
    zoomctx.drawImage(canvas,
                      Math.abs(x - 5),
                      Math.abs(y - 5),
                      10, 10,
                      0, 0,
                      200, 200);
  };

  canvas.addEventListener('mousemove', zoom);
}

Saving images

The HTMLCanvasElement provides a toDataURL() method, which is useful when saving images. It returns a data URI containing a representation of the image in the format specified by the type parameter (defaults to PNG). The returned image is in a resolution of 96 dpi.

canvas.toDataURL('image/png')
Default setting. Creates a PNG image.
canvas.toDataURL('image/jpeg', quality)
Creates a JPG image. Optionally, you can provide a quality in the range from 0 to 1, with one being the best quality and with 0 almost not recognizable but small in file size.

Once you have generated a data URI from you canvas, you are able to use it as the source of any <image> or put it into a hyper link with a download attribute to save it to disc, for example.

You can also create a Blob from the canvas.

canvas.toBlob(callback, type, encoderOptions)
Creates a Blob object representing the image contained in the canvas.

See also

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : NemoNobobyPersonne, jodenda
 Dernière mise à jour par : NemoNobobyPersonne,