This translation is incomplete. Please help translate this article from English.

Fins ara no hem mirat els píxels reals del nostre llenç. Amb l'objecte ImageData podem llegir i escriure directament una matriu de dades per manipular dades de píxels. També veurem com es pot controlar el suavitzat de la imatge (anti-aliasing) i com guardar imatges del vostre llenç.

L'objecte ImageData

L'objecte ImageData representa les dades de píxels subjacents d'un àrea d'un objecte canvas. Conté els següents atributs de només lectura:

width
L'amplada de la imatge en píxels.
height
L'alçada de la imatge en píxels.
data
Un Uint8ClampedArray representa una matriu unidimensional que conté les dades en l'ordre RGBA, amb valors enters entre 0 i 255 (inclosos).

La propietat data retorna un Uint8ClampedArray al que es pot accedir per veure les dades de píxel en brut; cada píxel està representat per quatre valors d'un byte (vermell, verd, blau i alfa, en aquest ordre; és a dir, format "RGBA"). Cada component de color està representat per un nombre enter entre 0 i 255. A cada component se li assigna un índex consecutiu dins de la matriu, el component vermell del píxel esquerre superior és l'índex 0 dins de la matriu. Els píxels es segueixen d'esquerra a dreta, a després cap avall, a través de la matriu.

El Uint8ClampedArray conté height × width × 4 bytes de dades, amb valors d'índex que van des de 0 fins a (height×width×4)-1.

Per exemple, per llegir el valor del component blau del píxel a la columna 200, fila 50 de la imatge, fariem el següent:

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

Podem accedir a la grandària de la matriu de píxels en bytes, llegint l'atribut Uint8ClampedArray.length:

var numBytes = imageData.data.length;

Crear un objecte ImageData

Per crear un nou objecte ImageData en blanc, hem d'utilitzar el mètode createImageData(). Hi ha dues versions del mètode createImageData():

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

Crea un nou objecte ImageData amb les dimensions especificades. Tots els píxels estan predefinits en negre transparent.

També podem crear un nou objecte ImageData amb les mateixes dimensions que l'objecte especificat amb anotherImageData. Els píxels del nou objecte, estan tots predefinits en negre transparent. Això no copia les dades de la imatge!

var myImageData = ctx.createImageData(anotherImageData);

Obtenir les dades de píxels per a un context

Per obtenir un objecte ImageData que contingui una còpia de les dades de píxel per a un context de llenç, podem utilitzar el mètodegetImageData():

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

Aquest mètode retorna un objecte ImageData que representa les dades de píxel per a l'àrea del llenç, les cantonades del qual estan representades pels punts (left,top), (left+width, top), (left, top+height) i (left+width, top+height). Les coordenades s'especifiquen en unitats d'espai en coordenades canvas.

Nota: Qualsevol píxel fora del llenç es retorna com a negre transparent en l'objecte ImageData resultant.

Aquest mètode també es demostra a l'article Manipulant vídeo usant canvas.

Un selector de colors

En aquest exemple estem usant el mètode getImageData() per mostrar el color sota el cursor del ratolí. Per a això, necessitem la posició actual del ratolí amb layerX i layerY, llavors busquem les dades de píxels en aquesta posició en la matriu de píxels que getImageData() ens proporciona. Finalment, utilitzem les dades de la matriu per establir un color de fons i un text en el <div> per mostrar el 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);

Pintar dades de píxels en un context

Utilitzem el mètode putImageData() per pintar dades de píxels en un context:

ctx.putImageData(myImageData, dx, dy);

Els paràmetres dx i dy indiquen les coordenades del dispositiu, dins del context en el que es pinta la cantonada superior esquerra de les dades de píxels que es vol dibuixar.

Per exemple, per pintar tota la imatge representada per myImageData en la cantonada superior esquerra del context, simplement fem el següent:

ctx.putImageData(myImageData, 0, 0);

Escalat de grisos i inversió de colors

En aquest exemple, iterem sobre tots els píxels per canviar els seus valors, després posem la matriu de píxels modificada, de nou, al llenç, utilitzant putImageData(). La funció invert, simplement, resta cada color del valor màxim 255. La funció grayscale, simplement, utilitza la mitjana de vermell, verd i blau. També es pot utilitzar una mitjana ponderada, donada per la fórmula x = 0.299r + 0.587g + 0.114b, per exemple. Vegeu Escala de grisos (Grayscale) a Wikipedia per obtenir més informació.

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

Ampliació i suavitzat

Amb l'ajuda del mètode drawImage() un segon llenç i la propietat imageSmoothingEnabled, podem ampliar la nostra imatge i veure els detalls.

Obtenim la posició del ratolí, retallem una imatge de 5 píxels a l'esquerra i a dalt a 5 píxels a la dreta i a baix. A continuació, la copiem a un altre llenç i canviem la grandària de la imatge a la grandària que volguem. En el llenç de zoom, canviem la grandària de un retall de 10×10 píxels del llenç original a 200×200.

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

Atès que el suavitzat (anti-aliasing) està habilitat per defecte, és possible que vulguem deshabilitar el suavitzat per veure els píxels clars. Alternant la casella de verificació es pot veure l'efecte de la propietat imageSmoothingEnabled (necessita prefixos per a diferents navegadors).

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

Guardar imatges

El HTMLCanvasElement proporciona un mètode toDataURL(), que és útil quan es guarden imatges. Retorna un URI de dades que conté una representació de la imatge en el format especificat pel paràmetre type (per defecte en PNG). La imatge retornada té una resolució de 96 dpi.

canvas.toDataURL('image/png')
Configuració per defecte. Crea una imatge PNG.
canvas.toDataURL('image/jpeg', quality)
Crea una imatge JPG. Opcionalment, pot proporcionar una qualitat en el rang de 0 a 1, sent una d'elles la millor qualitat i amb 0 gairebé no recognoscible, però, petita en grandària d'arxiu.

Una vegada que s'hagi generat un URI de dades des del llenç, es podrà utilitzar com a font de qualsevol <image> o posar-ho en un hipervíncle amb un atribut de descàrrega per guardar-ho en el disc, per exemple.

També es pot crear un Blob des del llenç.

canvas.toBlob(callback, type, encoderOptions)
Crea un objecte Blob, representant la imatge continguda en el llenç.

Vegeu també

Document Tags and Contributors

 Contributors to this page: Legioinvicta
 Last updated by: Legioinvicta,