Opératio

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

Jusqu'à présent nous ne nous sommes pas préoccupés des pixels de notre canvas. Avec l'objet ImageData wous pouvez directement lire et écrire dans le tableau de donnée de l'image pour manipuler les pixels un par un. Nous regarderons également comment le lissage (anti-aliasing = depixellisation) de l'image peut être effectué et comment sauvegarder le résultat de vos transformations sur l'image.

L'objet ImageData

L'objet ImageData représente les données qui définissent les composantes de chaque pixel composant une image affichée dans un objet canvas, il contient les attributs (en lecture seule) suivants :

width : largeur
La largeur en nombres de pixels de l'image.
height : hauteur
La hauteur en nombres de pixels de l'image.
data
Une Uint8ClampedArray représentation dans un tableau à une dimension des données sur chaque pixel dans le format RGBA (d'abord R = rouge, puis Vert, etc ...). Les caractéristiques R, G, B, A de chaque pixel sont codées par un nombre de 0 à 255 (inclus), soit sur un octet. Un pixel est défini par quatre de ces nombres se succédant dans l'ordre RGBA, puis viennent les quatre nombre correspondant aux données RGBA du pixel suivant.

La propriété data renvoie (retourne) un tableau unidimentionnel et compact de valeurs numériques Uint8ClampedArray qui peut être inspecté pour en tirer les données chaque pixel ; chaque pixel est représenté par quatre valeurs successives codées chacune sur un octet (ou byte : de 0 à 255) ; c'est le format "RGBA" (red, green, blue, and alpha = transparence).  Chacune des quatre valeurs est représentée par une valeure entière de 0 à 255. Le premier pixel sera codé sur les index 0, 1, 2, 3 du tableau data ; le deuxième pixel sera codé sur les index 4, 5, 6, 7 et ainsi de suite. Toutes les valeurs codant les pixels se succèdent dans le tableau à une dimension data, par conséquent à la fin de chaque ligne de pixel, les quatre valeur (R, G, B et A) du dernier pixel de la ligne sont suivies des quatre valeurs définissant le premier pixel de la ligne suivante et ceci depuis le premier pixel en haut à gauche, jusqu'au dernier pixel en bas à droite (fin de la dernière ligne).

Le Uint8ClampedArray contient au total un nombre d'octets (ou byte) calculable par la formule : height × width × 4 bytes avec un index de tableau compris entre 0 et (height×width×4)-1 (soit 4 fois le nombre total de pixels).

Par exemple, pour lire la valeur B (bleue) d'un pixel situé dans la colonne 200 et la ligne 50  de l'image, vous pourrez écrire le code suivant :

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

Vous pourrez accéder à la taille en bytes du tableau de pixels en lisant l'attribut Uint8ClampedArray.length comme suit :

var numBytes = imageData.data.length;

Creating an ImageData object

To create a new, blank ImageData object, you should use the createImageData() method. There are two versions of the createImageData() method:

var myImageData = ctx.createImageData(width, height);

This creates a new ImageData object with the specified dimensions. All pixels are preset to transparent black.

You can also create a new ImageData object with the same dimensions as the object specified by anotherImageData. The new object's pixels are all preset to transparent black. This does not copy the image data!

var myImageData = ctx.createImageData(anotherImageData);

Getting the pixel data for a context

To obtain an ImageData object containing a copy of the pixel data for a canvas context, you can use the getImageData() method:

var myImageData = ctx.getImageData(left, top, width, height);

This method returns an ImageData object representing the pixel data for the area of the canvas whose corners are represented by the points (left,top), (left+width, top), (left, top+height), and (left+width, top+height). The coordinates are specified in canvas coordinate space units.

Note: Any pixels outside the canvas are returned as transparent black in the resulting ImageData object.

This method is also demonstrated in the article Manipulating video using canvas.

A color picker

In this example we are using the getImageData() method to display the color under the mouse cursor. For this, we need the current position of the mouse with layerX and layerY, then we look up the pixel data on that position in the pixel array that getImageData() provides us. Finally, we use the array data to set a background color and a text in the <div> to display the color.

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

Painting pixel data into a context

You can use the putImageData() method to paint pixel data into a context:

ctx.putImageData(myImageData, dx, dy);

The dx and dy parameters indicate the device coordinates within the context at which to paint the top left corner of the pixel data you wish to draw.

For example, to paint the entire image represented by myImageData to the top left corner of the context, you can simply do the following:

ctx.putImageData(myImageData, 0, 0);

Grayscaling and inverting colors

In this example we iterate over all pixels to change their values, then we put the modified pixel array back to the canvas using putImageData(). The invert function simply subtracts each color from the max value 255. The grayscale function simply uses the average of red, green and blue. You can also use a weighted average, given by the formula x = 0.299r + 0.587g + 0.114b, for example. See Grayscale on Wikipedia for more information.

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 imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var data = imageData.data;
    
  var invert = function() {
    for (var i = 0; i < data.length; i += 4) {
      data[i]     = 255 - data[i];     // red
      data[i + 1] = 255 - data[i + 1]; // green
      data[i + 2] = 255 - data[i + 2]; // blue
    }
    ctx.putImageData(imageData, 0, 0);
  };

  var grayscale = function() {
    for (var i = 0; i < data.length; i += 4) {
      var avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
      data[i]     = avg; // red
      data[i + 1] = avg; // green
      data[i + 2] = avg; // blue
    }
    ctx.putImageData(imageData, 0, 0);
  };

  var invertbtn = document.getElementById('invertbtn');
  invertbtn.addEventListener('click', invert);
  var grayscalebtn = document.getElementById('grayscalebtn');
  grayscalebtn.addEventListener('click', grayscale);
}

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 : jodenda
 Dernière mise à jour par : jodenda,