W3docs

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:

  1. Einen Verweis auf ein anderes Canvas-Element oder ein HTMLImageElement-Objekt als Quelle abrufen.
  2. Ein Bild mit der Funktion drawImage() auf dem Canvas zeichnen.

Als Bildquelle kann die Canvas-API jeden der folgenden Datentypen verwenden:

DatentypBeschreibung
HTMLImageElementDies sind Bilder, die mit dem Image()-Konstruktor oder einem beliebigen <img>-Element erstellt wurden.
SVGImageElementDies sind Bilder, die mit dem <image>-Element eingebettet wurden.
HTMLVideoElementEin HTML-<video>-Element als Bildquelle entnimmt das aktuelle Frame aus dem Video und verwendet es als Bild.
HTMLCanvasElementAls 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() oder getImageData() löst einen SecurityError aus. Die Lösung liegt auf dem Server: Er muss den Access-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:

ParameterGruppeBedeutung
sx, syQuelleObere linke Ecke des aus dem Quellbild entnommenen Ausschnitts.
sWidth, sHeightQuelleBreite und Höhe dieses Ausschnitts.
dx, dyZielWo der Ausschnitt auf dem Canvas platziert wird.
dWidth, dHeightZielGröß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>
Gefahr

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>

Übungen

Übung
Wenn Sie in JavaScript ein Bild erstellen, um es auf dem Canvas zu zeichnen, was ist die richtige Reihenfolge der Schritte?
Wenn Sie in JavaScript ein Bild erstellen, um es auf dem Canvas zu zeichnen, was ist die richtige Reihenfolge der Schritte?
Was this page helpful?