W3docs

Immagini su Canvas

Impara a disegnare immagini su un canvas HTML: sorgente immagine, tre forme di drawImage(), gestione CORS e canvas contaminato.

Una delle funzionalità dell'elemento <canvas> è la possibilità di utilizzare immagini. Queste possono essere usate per scopi diversi. È possibile usare immagini esterne in qualsiasi formato supportato dal browser (ad es. PNG, GIF o JPEG). Come sorgente si può anche usare un'immagine creata da altri elementi canvas.

Questo capitolo si basa sull'introduzione a Canvas e sulle basi del disegno su Canvas. Qui imparerai come ottenere una sorgente immagine, come usare le tre forme del metodo drawImage() e come evitare il problema del "canvas contaminato" quando si caricano immagini da altri domini.

Importare immagini in un canvas è un processo in due fasi:

  1. Ottenere un riferimento a un altro elemento canvas o a un oggetto HTMLImageElement come sorgente.
  2. Disegnare un'immagine sul canvas con la funzione drawImage().

Come sorgente immagine, l'API canvas può usare uno qualsiasi dei seguenti tipi di dati:

Tipo di datoDescrizione
HTMLImageElementImmagini create con il costruttore Image() o qualsiasi elemento <img>.
SVGImageElementImmagini incorporate con l'elemento <image>.
HTMLVideoElementUn elemento HTML <video> usato come sorgente immagine cattura il fotogramma corrente del video e lo usa come immagine.
HTMLCanvasElementCome sorgente immagine è possibile usare un altro elemento <canvas>.

Questi tipi di sorgente sono collettivamente indicati con il tipo CanvasImageSource.

Esistono molti modi per ottenere immagini da usare su canvas.

Usare immagini dalla stessa pagina

È possibile ottenere un riferimento alle immagini presenti nella stessa pagina del canvas con uno dei seguenti metodi:

  • La raccolta document.images
  • Il metodo document.getElementsByTagName()
  • Il metodo document.getElementById() se si conosce l'ID dell'immagine che si vuole usare

Ad esempio, per recuperare un elemento <img> esistente tramite il suo ID e disegnarlo una volta caricata la pagina:

<img id="photo" src="myImage.png" alt="My image" />
<canvas id="exampleCanvas" width="240" height="225"></canvas>
<script>
  window.onload = function () {
    const canvas = document.getElementById("exampleCanvas");
    const ctx = canvas.getContext("2d");
    const img = document.getElementById("photo");
    ctx.drawImage(img, 0, 0);
  };
</script>

Poiché l'elemento <img> è già nel documento, il browser di solito ha terminato il caricamento nel momento in cui viene attivato window.onload, quindi è sicuro disegnare immediatamente.

Usare immagini da altri domini

Utilizzando l'elemento <img> con l'attributo crossorigin="anonymous", è possibile richiedere il permesso di caricare un'immagine da un altro dominio. Se il dominio di hosting consente l'accesso cross-domain tramite header CORS, è possibile usare l'immagine nel canvas senza contaminarlo.

<img id="remote" src="https://example.com/photo.jpg" crossorigin="anonymous" alt="Remote image" />

Quando si imposta crossorigin="anonymous", il browser invia la richiesta senza credenziali (cookie). L'immagine viene ammessa su un canvas pulito solo se il server risponde con l'header:

Access-Control-Allow-Origin: *

(o un valore che include la propria origine). Se si crea l'immagine in JavaScript, impostare la proprietà prima di src:

const img = new Image();
img.crossOrigin = "anonymous";
img.onload = function () {
  ctx.drawImage(img, 0, 0);
};
img.src = "https://example.com/photo.jpg";

Nota Se si disegna un'immagine cross-origin senza una corretta configurazione CORS, il canvas diventa "contaminato". Un canvas contaminato blocca l'accesso ai dati dei pixel per motivi di sicurezza — chiamare toDataURL(), toBlob() o getImageData() genererà un SecurityError. La soluzione si trova sul server: deve inviare l'header Access-Control-Allow-Origin. Non è possibile leggere i pixel da un canvas contaminato lato client.

Usare altri elementi canvas

È possibile accedere ad altri elementi canvas usando il metodo document.getElementById() o document.getElementsByTagName().

Incorporare un'immagine tramite data: URL

I data URL permettono di specificare un'immagine come stringa di caratteri codificata in Base64 direttamente nel codice. Il vantaggio dei data URL è che l'immagine risultante è disponibile immediatamente. È inoltre possibile raggruppare tutto il proprio CSS, HTML, JavaScript e le immagini in un unico file.

Tuttavia, esiste anche uno svantaggio: l'immagine non viene memorizzata nella cache e l'URL codificato può risultare troppo lungo per immagini di grandi dimensioni.

Per usare un data URL, assegnarlo alla proprietà src di un'immagine e disegnarla una volta caricata:

const img = new Image();
img.onload = function () {
  ctx.drawImage(img, 0, 0);
};
img.src =
  "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";

La stringa dopo base64, è l'immagine codificata. Poiché fa parte dello script, non viene effettuata alcuna richiesta di rete aggiuntiva — l'immagine è pronta non appena viene decodificata.

Creare un'immagine da zero

È anche possibile creare un nuovo oggetto HTMLImageElement nello script. A questo scopo, si usa il costruttore Image():

Creare un'immagine da zero

const img = new Image();
img.onload = function () {
  ctx.drawImage(img, 0, 0);
};
img.src = "myImage.png";

L'immagine inizia a caricarsi nel momento in cui viene impostato src, e il caricamento è asincrono. Se si chiama drawImage() prima che il caricamento sia completato, non viene disegnato nulla. Per garantire che drawImage() venga eseguito solo quando l'immagine è pronta, collegare il gestore dell'evento onload prima di impostare src.

La funzione drawImage()

Una volta disponibile un riferimento all'immagine sorgente, è possibile usare il metodo drawImage(). Esistono tre forme, ognuna con più parametri rispetto alla precedente:

1. Solo posizione

ctx.drawImage(image, dx, dy);

Disegna l'intera immagine alle sue dimensioni naturali, posizionando l'angolo superiore sinistro nel punto (dx, dy) del canvas.

2. Posizione e dimensioni (ridimensionamento)

ctx.drawImage(image, dx, dy, dWidth, dHeight);

Disegna l'intera immagine ridimensionata per adattarsi a un riquadro di dWidth × dHeight pixel il cui angolo superiore sinistro si trova in (dx, dy).

3. Ritaglio (rettangolo sorgente verso rettangolo destinazione)

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

Prende una porzione rettangolare dell'immagine sorgente e la disegna in un rettangolo di destinazione sul canvas. È la forma più flessibile — viene usata per sprite sheet, ritaglio e zoom.

I parametri si dividono in due gruppi:

ParametroGruppoSignificato
sx, sySorgenteAngolo superiore sinistro del ritaglio dell'immagine sorgente.
sWidth, sHeightSorgenteLarghezza e altezza del ritaglio.
dx, dyDestinazioneDove viene posizionato il ritaglio sul canvas.
dWidth, dHeightDestinazioneDimensioni a cui viene disegnato il ritaglio sul canvas (viene ridimensionato se diverso da sWidth/sHeight).

I valori s* (sorgente) sono misurati in pixel dell'immagine originale; i valori d* (destinazione) sono misurati in pixel del canvas. La forma base, drawImage(image, dx, dy), è semplicemente la prima delle tre.

Nel seguente esempio, usiamo il metodo document.getElementById() per ottenere un riferimento all'immagine e poi usiamo la funzione drawImage() per disegnarla.

Esempio di disegno di un'immagine con la funzione drawImage():

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Image</h2>
    <img id="photo" src="/uploads/media/default/0001/01/25acddb3da54207bc6beb5838f65f022feaa81d7.jpeg" alt="Aleq" width="200" height="185" />
    <h2>Image with canvas:</h2>
    <canvas id="exampleCanvas" width="240" height="225" style="border:2px solid #cccccc;">
      Your browser doesn't support the canvas tag.
    </canvas>
    <script>
      window.onload = function() {
        const canvas = document.getElementById("exampleCanvas");
        const ctx = canvas.getContext("2d");
        const img = document.getElementById("photo");
        ctx.drawImage(img, 20, 20);
      };
    </script>
  </body>
</html>
Pericolo

SVG images must define the width and height in the root <svg> element.

Usare fotogrammi da un video

È anche possibile usare fotogrammi da un video presentato da un elemento <video>, anche quando il video non è visibile. Ad esempio, se si dispone di un elemento <video> con l'ID "videoCanvas", procedere come segue:

Esempio di disegno di un video con canvas:

Immagini su Canvas

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Video</h2>
    <video id="videoCanvas" controls width="350" autoplay>
      <source src="/build/videos/arcnet.io(7-sec).mp4" type="video/mp4" />
    </video>
    <h2>Canvas  draws the current video:</h2>
    <canvas id="exampleCanvas" width="310" height="190" style="border:1px solid #d3d3d3;">
      Your browser doesn't support the canvas tag.
    </canvas>
    <script>
      const v = document.getElementById("videoCanvas");
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      let animId;
      function drawFrame() {
        ctx.drawImage(v, 5, 5, 300, 180);
        animId = requestAnimationFrame(drawFrame);
      }
      v.addEventListener("play", function() {
        animId = requestAnimationFrame(drawFrame);
      }, false);
      v.addEventListener("pause", function() {
        cancelAnimationFrame(animId);
      }, false);
      v.addEventListener("ended", function() {
        cancelAnimationFrame(animId);
      }, false);
    </script>
  </body>
</html>

Esercizio

Pratica
Quando si crea un'immagine in JavaScript per disegnarla sul canvas, qual è l'ordine corretto dei passaggi?
Quando si crea un'immagine in JavaScript per disegnarla sul canvas, qual è l'ordine corretto dei passaggi?
Was this page helpful?