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:
- Ottenere un riferimento a un altro elemento canvas o a un oggetto HTMLImageElement come sorgente.
- 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 dato | Descrizione |
|---|---|
| HTMLImageElement | Immagini create con il costruttore Image() o qualsiasi elemento <img>. |
| SVGImageElement | Immagini incorporate con l'elemento <image>. |
| HTMLVideoElement | Un elemento HTML <video> usato come sorgente immagine cattura il fotogramma corrente del video e lo usa come immagine. |
| HTMLCanvasElement | Come 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()ogetImageData()genererà unSecurityError. La soluzione si trova sul server: deve inviare l'headerAccess-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:
| Parametro | Gruppo | Significato |
|---|---|---|
sx, sy | Sorgente | Angolo superiore sinistro del ritaglio dell'immagine sorgente. |
sWidth, sHeight | Sorgente | Larghezza e altezza del ritaglio. |
dx, dy | Destinazione | Dove viene posizionato il ritaglio sul canvas. |
dWidth, dHeight | Destinazione | Dimensioni 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>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>