Canvas-Bilder
Bilder auf einem HTML Canvas zeichnen: Bildquellen abrufen, drawImage() in drei Formen nutzen, CORS handhaben und ein tainted canvas vermeiden.
Eine der Funktionen des <canvas>-Elements ist die Möglichkeit, Bilder zu verwenden. Diese können für verschiedene Zwecke eingesetzt werden. Sie können externe Bilder in jedem vom Browser unterstützten Format verwenden (z. B. PNG, GIF oder JPEG). Als Quelle können Sie auch Bilder verwenden, die von anderen Canvas-Elementen erstellt wurden.
Dieses Kapitel baut auf der Canvas-Einführung und den Grundlagen des Canvas-Zeichnens auf. Hier erfahren Sie, wie Sie eine Bildquelle abrufen, wie Sie die drei Formen der drawImage()-Methode nutzen und wie Sie das Problem des „tainted canvas" beim Laden von Bildern aus anderen Domains vermeiden.
Das Importieren von Bildern in einen Canvas ist ein zweistufiger Prozess:
- Einen Verweis auf ein anderes Canvas-Element oder ein HTMLImageElement-Objekt als Quelle abrufen.
- Ein Bild mit der Funktion drawImage() auf dem Canvas zeichnen.
Als Bildquelle kann die Canvas-API jeden der folgenden Datentypen verwenden:
| Datentyp | Beschreibung |
|---|---|
| HTMLImageElement | Dies sind Bilder, die mit dem Image()-Konstruktor oder einem beliebigen <img>-Element erstellt wurden. |
| SVGImageElement | Dies sind Bilder, die mit dem <image>-Element eingebettet wurden. |
| HTMLVideoElement | Ein HTML-<video>-Element als Bildquelle entnimmt das aktuelle Frame aus dem Video und verwendet es als Bild. |
| HTMLCanvasElement | Als Bildquelle kann ein weiteres <canvas>-Element verwendet werden. |
Diese Quellen werden zusammenfassend als Typ CanvasImageSource bezeichnet.
Es gibt viele Möglichkeiten, Bilder für die Verwendung auf einem Canvas zu erhalten.
Bilder von derselben Seite verwenden
Sie können mit einer der folgenden Methoden einen Verweis auf Bilder auf derselben Seite wie der Canvas abrufen:
- Die
document.images-Sammlung - Die
document.getElementsByTagName()-Methode - Die
document.getElementById()-Methode, wenn Sie die ID des gewünschten Bildes kennen
Um beispielsweise ein vorhandenes <img>-Element anhand seiner ID abzurufen und es nach dem Laden der Seite zu zeichnen:
<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>Da sich das <img> bereits im Dokument befindet, hat der Browser es in der Regel fertig geladen, wenn window.onload ausgelöst wird, sodass es sicher ist, sofort zu zeichnen.
Bilder aus anderen Domains verwenden
Mit dem <img>-Element und dem Attribut crossorigin="anonymous" können Sie die Berechtigung anfordern, ein Bild aus einer anderen Domain zu laden. Wenn die Hosting-Domain den domainübergreifenden Zugriff über CORS-Header erlaubt, können Sie das Bild in Ihrem Canvas verwenden, ohne ihn zu „verunreinigen".
<img id="remote" src="https://example.com/photo.jpg" crossorigin="anonymous" alt="Remote image" />Wenn Sie crossorigin="anonymous" setzen, sendet der Browser die Anfrage ohne Anmeldeinformationen (Cookies). Das Bild darf nur dann auf einem sauberen Canvas verwendet werden, wenn der Server mit folgendem Header antwortet:
Access-Control-Allow-Origin: *(oder einem Wert, der Ihren Ursprung einschließt). Wenn Sie das Bild in JavaScript erstellen, setzen Sie die Eigenschaft vor src:
const img = new Image();
img.crossOrigin = "anonymous";
img.onload = function () {
ctx.drawImage(img, 0, 0);
};
img.src = "https://example.com/photo.jpg";Hinweis Wenn Sie ein Cross-Origin-Bild ohne ordnungsgemäße CORS-Konfiguration zeichnen, wird der Canvas „tainted" (verunreinigt). Ein tainted Canvas blockiert aus Sicherheitsgründen den Zugriff auf seine Pixeldaten — der Aufruf von
toDataURL(),toBlob()odergetImageData()löst einenSecurityErroraus. Die Lösung liegt auf dem Server: Er muss denAccess-Control-Allow-Origin-Header senden. Es gibt keine Möglichkeit, Pixel von einem tainted Canvas auf der Client-Seite zu lesen.
Andere Canvas-Elemente verwenden
Andere Canvas-Elemente sind über die Methoden document.getElementById() oder document.getElementsByTagName() zugänglich.
Ein Bild über eine data: URL einbetten
Data-URLs ermöglichen es, ein Bild als Base64-kodierten Zeichenstring direkt im Code anzugeben. Der Vorteil einer Data-URL besteht darin, dass das resultierende Bild sofort verfügbar ist. Es ist auch möglich, alle Ihre CSS-, HTML-, JavaScript-Dateien und Bilder in einer einzigen Datei zusammenzufassen.
Es gibt jedoch auch einen Nachteil: Das Bild wird nicht gecacht, und die kodierte URL kann bei größeren Bildern zu lang werden.
Um eine Data-URL zu verwenden, weisen Sie sie dem src eines Bildes zu und zeichnen Sie es, sobald es geladen wurde:
const img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0);
};
img.src =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";Der String nach base64, ist das kodierte Bild. Da er Teil des Skripts ist, wird keine zusätzliche Netzwerkanfrage gestellt — das Bild ist sofort nach dem Dekodieren bereit.
Ein Bild von Grund auf neu erstellen
Sie können auch ein neues HTMLImageElement-Objekt in Ihrem Skript erstellen. Verwenden Sie dafür den Image()-Konstruktor:
Ein Bild von Grund auf neu erstellen
const img = new Image();
img.onload = function () {
ctx.drawImage(img, 0, 0);
};
img.src = "myImage.png";Das Bild beginnt zu laden, sobald src gesetzt wird, und das Laden erfolgt asynchron. Wenn Sie drawImage() aufrufen, bevor das Bild fertig geladen ist, wird nichts gezeichnet. Um sicherzustellen, dass drawImage() erst nach dem Laden des Bildes ausgeführt wird, fügen Sie den onload-Ereignishandler vor dem Setzen von src hinzu.
Die drawImage()-Funktion
Sobald ein Verweis auf das Quellbild verfügbar ist, können Sie die drawImage()-Methode verwenden. Sie ist in drei Formen verfügbar, wobei jede Form mehr Parameter als die vorherige akzeptiert:
1. Nur Position
ctx.drawImage(image, dx, dy);Zeichnet das gesamte Bild in seiner natürlichen Größe und platziert dessen obere linke Ecke am Punkt (dx, dy) auf dem Canvas.
2. Position und Größe (Skalierung)
ctx.drawImage(image, dx, dy, dWidth, dHeight);Zeichnet das gesamte Bild, skaliert auf eine Box von dWidth × dHeight Pixeln, deren obere linke Ecke sich bei (dx, dy) befindet.
3. Ausschneiden (Quellrechteck auf Zielrechteck)
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);Nimmt einen rechteckigen Ausschnitt des Quellbilds und zeichnet ihn in ein Zielrechteck auf dem Canvas. Dies ist die flexibelste Form — sie wird für Sprite-Sheets, Zuschneiden und Zoomen verwendet.
Die Parameter unterteilen sich in zwei Gruppen:
| Parameter | Gruppe | Bedeutung |
|---|---|---|
sx, sy | Quelle | Obere linke Ecke des aus dem Quellbild entnommenen Ausschnitts. |
sWidth, sHeight | Quelle | Breite und Höhe dieses Ausschnitts. |
dx, dy | Ziel | Wo der Ausschnitt auf dem Canvas platziert wird. |
dWidth, dHeight | Ziel | Größe, in der der Ausschnitt auf dem Canvas gezeichnet wird (er wird skaliert, wenn er von sWidth/sHeight abweicht). |
Die s*-(Quell-)Werte werden in Pixeln des Originalbilds gemessen; die d*-(Ziel-)Werte werden in Canvas-Pixeln gemessen. Die Grundform drawImage(image, dx, dy) ist lediglich die erste dieser drei.
Im folgenden Beispiel verwenden wir die document.getElementById()-Methode, um einen Verweis auf das Bild zu erhalten, und dann die drawImage()-Funktion, um es zu zeichnen.
Beispiel für das Zeichnen eines Bildes mit der drawImage()-Funktion:
<!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-Bilder müssen die Breite und Höhe im Root-Element <svg> definieren.
Frames aus einem Video verwenden
Es ist auch möglich, Frames aus einem Video zu verwenden, das durch ein <video>-Element dargestellt wird, selbst wenn das Video nicht sichtbar ist. Wenn Sie zum Beispiel ein <video>-Element mit der ID "videoCanvas" haben, gehen Sie wie folgt vor:
Beispiel für das Zeichnen eines Videos mit Canvas:
Canvas Images
<!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>