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

Fins ara hem creat les nostres pròpies formes i aplicat estils a elles. Una de les característiques més interessants de <canvas> és la capacitat d'usar imatges.  Aquestes poden ser usades per fer composicions fotogràfiques dinàmiques o com a telons de fons de gràfics, per sprites en jocs, etcètera. Les imatges externes es poden utilitzar en qualsevol format compatible amb el navegador, com PNG, GIF o JPEG. Fins i tot es pot utilitzar la imatge produïda per altres elements de canvas a la mateixa pàgina que la font!

 Importar imatges en un llenç és bàsicament un procés de dos passos:

  1. Obtenir una referència a un objecte HTMLImageElement o a un altre element de canvas com a font. També és possible utilitzar imatges proporcionant una URL.
  2. Dibuixi la imatge en el llenç usant la funció drawImage().

Feu un cop d'ull a com fer això.

Obtenir imatges per dibuixar

L'API de canvas pot utilitzar qualsevol dels següents tipus de dades com a font d'imatge:

HTMLImageElement
Aquestes són imatges creades usant el constructor Image(), així com qualsevol element <img>.
SVGImageElement
Aquestes són imatges incrustades usant l'element <image>.
HTMLVideoElement
L'ús d'un element HTML <video> com a font d'imatge, pren el marc actual del vídeo i ho utilitza com a imatge.
HTMLCanvasElement
Es pot utilitzar un altre element <canvas> com la seva font d'imatge

Aquestes fonts es refereixen col·lectivament pel tipus CanvasImageSource.

Hi ha diverses maneres d'obtenir imatges per usar-les en un llenç.

Usar imatges de la mateixa pàgina

Es pot obtenir una referència a les imatges en la mateixa pàgina que el llenç utilitzant una de les següents opcions:

Usar imatges d'altres dominis

Usant l'atribut crossorigin d'un element <img> (reflectit per la propietat HTMLImageElement.crossOrigin property), es pot sol·licitar permís per carregar una imatge d'un altre domini per usar-la cridant a drawImage(). Si el domini d'allotjament permet l'accés de domini creuat a la imatge, la imatge es pot utilitzar en el  llenç sense corrompre's; en cas contrari, usar la imatge corromprà el llenç.

Usar altres elements de canvas

Igual que amb les imatges normals, accedim a altres elements de canvas usant el mètode document.getElementsByTagName() o document.getElementById(). Hem d'estar segurs d'haver dibuixat alguna cosa en el llenç font abans d'usar-ho en el llenç de destinació.

Un dels usos més pràctics d'això seria usar un segon element de canvas com a vista en miniatura de l'altre canvas més gran.

Crear una imatge des de zero

Una altra opció és crear nous HTMLImageElement en un script. Per fer-ho, hem d'utilitzar el constructor adequat Image():

var img = new Image();   // Create new img element
img.src = 'myImage.png'; // Set source path

Quan s'executa aquest script, la imatge comença a carregar-se.

Si intentem cridar drawImage() abans que la imatge s'hagi acabat de carregar, no farà res (o, en navegadors antics, fins i tot pot arribar a produir una excepció). Per tant, ens hem d'assegurar d'utilitzar l'esdeveniment load per no intentar-ho abans de que la imatge es carregui:

var img = new Image();   // Create new img element
img.addEventListener('load', function() {
  // execute drawImage statements here
}, false);
img.src = 'myImage.png'; // Set source path

Si només s'utilitza una imatge externa, això pot ser un bon enfocament, però una vegada que es necessiti rastrejar més d'una, es necessitarà recórrer a una mica més intel·ligent. Està fora de l'abast d'aquest tutorial examinar tàctiques de precàrrega d'imatges, però cal tenir-ho en ment.

Incrustar una imatge mitjançant dades: URL

Una altra forma possible d'incloure imatges és a través de les dades: url. Les URLs de dades permeten definir completament una imatge com una cadena de caràcters codificats en Base64, directament en el codi.

var img = new Image();   // Create new img element
img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';

Un avantatge de les URL de dades és que la imatge resultant està disponible immediatament sense un altre viatge d'anada i tornada al servidor. Un altre avantatge potencial és que també és possible encapsular en un sol arxiu tots els nostres arxius CSS, JavaScript, HTML i imatges, fent-los més portàtils a altres ubicacions.

Alguns desavantatges d'aquest mètode són que la imatge no està emmagatzemada a la memòria cau, i per a imatges més grans la url codificada pot arribar a ser bastant llarga.

Usar marcs d'un vídeo

També es pot utilitzar marcs d'un vídeo, presentat per un element <video> (fins i tot si el vídeo no és visible). Per exemple, si tenim un element <video> amb l'ID "myvideo", es pot fer:

function getMyVideo() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    return document.getElementById('myvideo');
  }
}

Això retorna l'objecte HTMLVideoElement per al vídeo, que, com s'ha explicat anteriorment, és un dels objectes que es pot utilitzar com CanvasImageSource.

Dibuixar imatges

Una vegada que tenim una referència al nostre objecte d'imatge font podem usar el mètode drawImage() para representar-la en el llenç. Com veurem més endavant el mètode drawImage() està sobrecarregat i té diverses variants. En la seva forma més bàsica, es veu així:

drawImage(image, x, y)
Dibuixa el CanvasImageSource especificat pel paràmetre image en les coordenades (x, y).

Les imatges SVG han d'especificar un amplada i una alçada en l'element arrel <svg>.

Exemple: Un gràfic de línia senzilla

En el següent exemple, utilitzarem una imatge externa com a fons per un petit gràfic de línia. L'ús de fons pot fer que el script sigui considerablement més petit perquè evitem la necessitat de codi per generar el fons. En aquest exemple, només estem utilitzant una imatge, per la qual cosa s'utilitza el controlador d'esdeveniments load de l'objecte image per executar les sentències de dibuix. El mètode drawImage() col·loca el fons en la coordenada (0,0), que és la cantonada superior esquerra del llenç.

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.onload = function() {
    ctx.drawImage(img, 0, 0);
    ctx.beginPath();
    ctx.moveTo(30, 96);
    ctx.lineTo(70, 66);
    ctx.lineTo(103, 76);
    ctx.lineTo(170, 15);
    ctx.stroke();
  };
  img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png';
}

El gràfic resultant és el següent:

ScreenshotLive sample

Escalar

La segona variant del mètode drawImage() afegeix dos nous paràmetres i ens permet col·locar imatges a escala en el llenç.

drawImage(image, x, y, width, height)
Això afegeix els paràmetres width i height, que indiquen la grandària al que s'ha d'escalar la imatge en dibuixar-la sobre el llenç.

Exemple: Mosaic d'una imatge

En aquest exemple, usarem una imatge com a fons de pantalla i la repetirem diverses vegades sobre el llenç. Això es fa, simplement, fent un bucle i col·locant les imatges escalades en diferents posicions. En el codi següent, el primer cicle de bucle itera sobre les files. El segon cicle for itera sobre les columnes. La imatge s'escala a un terç de la seva grandària original, que és de 50x38 píxels.

Nota: Les imatges poden tornar-se borroses en augmentar l'escala o granuloses si es redueixen massa. Escalar és millor no fer-ho, si tenim una mica de text que ha de seguir sent llegible.

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.onload = function() {
    for (var i = 0; i < 4; i++) {
      for (var j = 0; j < 3; j++) {
        ctx.drawImage(img, j * 50, i * 38, 50, 38);
      }
    }
  };
  img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
}

El llenç resultant es veu així:

ScreenshotLive sample

Retallar

La tercera i última variant del mètode drawImage() té vuit paràmetres a més de la font d'imatge. Ens permet retallar una secció de la imatge font, després escalar-la i dibuixar-la en el llenç.

drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
Donada una image, aquesta funció pren l'àrea de la imatge font especificada pel rectangle, la cantonada superior esquerra de la qual és (sx, sy) i l'amplada de la qual i l'alçada són sWidth i sHeight i la dibuixa en el llenç, col·locant-la sobre el llenç a (dx, dy) i escalant-la a la grandària especificada per dWidth i dHeight.

Per entendre realment què fa això, pot ajudar, mirar la imatge a la dreta. Els primers quatre paràmetres defineixen la ubicació i la grandària del retall en la imatge font. Els últims quatre paràmetres defineixen el rectangle en el qual dibuixar la imatge sobre el llenç de destinació.

El retallar pot ser una eina útil quan es desitja fer composicions. Es pot tenir tots els elements en un sol arxiu d'imatge i usar aquest mètode per compondre un dibuix complet. Per exemple, si es vol fer una gràfic, tenint una imatge PNG que contingui tot el text necessari en un sol arxiu i depenent de les dades, es podria canviar l'escala del gràfic amb bastant facilitat. Un altre avantatge és que no es necessita carregar cada imatge individualment, la qual cosa millora el rendiment de la càrrega.

Exemple: Enquadrar una imatge

En aquest exemple, usarem el mateix rinoceront que en l'exemple anterior, però li retallarem el cap i el compondrem en un marc d'imatge. La imatge del marc és una imatge PNG de 24 bits que inclou una ombra. A causa que les imatges PNG de 24 bits inclouen un canal alfa complet de 8 bits, a diferència de les imatges GIF i PNG de 8 bits, es poden col·locar en qualsevol fons sense que preocupi el color mat.

<html>
 <body onload="draw();">
   <canvas id="canvas" width="150" height="150"></canvas>
   <div style="display:none;">
     <img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227">
     <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150">
   </div>
 </body>
</html>
function draw() {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');

  // Draw slice
  ctx.drawImage(document.getElementById('source'),
                33, 71, 104, 124, 21, 20, 87, 104);

  // Draw frame
  ctx.drawImage(document.getElementById('frame'), 0, 0);
}

Aquesta vegada hem pres un enfocament diferent per carregar les imatges. En lloc de carregar-les creant nous objectes HTMLImageElement, les incloem com a etiquetes <img> directament en el nostre codi font HTML i recuperem les imatges d'aquestes . Les imatges s'oculten de la sortida, establint la propietat CSS display a none per a aquestes imatges.

ScreenshotLive sample

El propi script és molt senzill. Cada <img> se li assigna un atribut ID, la qual cosa facilita la selecció dels mateixos mitjançant document.getElementById(). A continuació, simplement usem drawImage() per retallar el rinoceront de la primera imatge i escalar-lo en el llenç, després dibuixem el marc en la part superior usant una segona crida a drawImage().

Exemple de galeria d'art

En l'últim exemple d'aquest capítol, construirem una petita galeria d'art. La galeria consisteix en una taula que conté diverses imatges. Quan es carrega la pàgina, s'insereix un element <canvas> per a cada imatge i es dibuixa un marc al seu voltant.

En aquest cas, cada imatge té una amplada i alçada fixa, igual que el marc que es dibuixa al seu al voltant. Es pot millorar el script (seqüència de comandaments) perquè usi l'amplada i l'alçada de la imatge, perquè el marc s'adapti perfectament al seu voltant.

El següent codi ha de ser autoexplicatiu. Recorrem el contenidor document.images i afegim nous elements canvas. Probablement l'única cosa que cal tenir en compte, per a aquells que no estan tan familiaritzats amb el DOM, és l'ús del mètode Node.insertBefore. insertBefore() és un mètode del node pare (una cel·la de taula) de l'element (image) en que previament inserirem un nou node (l'element canvas).

<html>
 <body onload="draw();">
     <table>
      <tr>
        <td><img src="https://mdn.mozillademos.org/files/5399/gallery_1.jpg"></td>
        <td><img src="https://mdn.mozillademos.org/files/5401/gallery_2.jpg"></td>
        <td><img src="https://mdn.mozillademos.org/files/5403/gallery_3.jpg"></td>
        <td><img src="https://mdn.mozillademos.org/files/5405/gallery_4.jpg"></td>
      </tr>
      <tr>
        <td><img src="https://mdn.mozillademos.org/files/5407/gallery_5.jpg"></td>
        <td><img src="https://mdn.mozillademos.org/files/5409/gallery_6.jpg"></td>
        <td><img src="https://mdn.mozillademos.org/files/5411/gallery_7.jpg"></td>
        <td><img src="https://mdn.mozillademos.org/files/5413/gallery_8.jpg"></td>
      </tr>
     </table>
     <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150">
 </body>
</html>

I aquí hi ha una mica de CSS per fer que les coses es vegin bé:

body {
  background: 0 -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A;
  margin: 10px;
}

img {
  display: none;
}

table {
  margin: 0 auto;
}

td {
  padding: 15px;
}

Javascript ho lliga tot junt, per dibuixar les imatges emmarcades:

function draw() {

  // Loop through all images
  for (var i = 0; i < document.images.length; i++) {

    // Don't add a canvas for the frame image
    if (document.images[i].getAttribute('id') != 'frame') {

      // Create canvas element
      canvas = document.createElement('canvas');
      canvas.setAttribute('width', 132);
      canvas.setAttribute('height', 150);

      // Insert before the image
      document.images[i].parentNode.insertBefore(canvas,document.images[i]);

      ctx = canvas.getContext('2d');

      // Draw image to canvas
      ctx.drawImage(document.images[i], 15, 20);

      // Add frame
      ctx.drawImage(document.getElementById('frame'), 0, 0);
    }
  }
}

Controlar el comportament d'escalat de la imatge

Com es va esmentar anteriorment, l'escalat d'imatges pot donar com a resultat objectes borrosos o bloquejats a causa del procés d'escalat. Es pot utilitzar la propietat imageSmoothingEnabled del context de dibuix, per controlar l'ús d'algoritmes de suavitzat d'imatge en escalar imatges dins del seu context. Per defecte, això és true, la qual cosa significa que les imatges se suavitzaran en escalar-les. Aquesta característica es pot deshabilitar d'aquesta manera:

ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;

Document Tags and Contributors

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