Back

Bilder mit Canvas in Base64 konvertieren

Bilder mit Canvas in Base64 konvertieren

Wenn Sie Bilddaten aus dem Browser exportieren müssen – sei es für clientseitige Vorschauen, das Einbetten kleiner Grafiken oder die Bildverarbeitung vor dem Upload – ist die HTML Canvas API das direkteste verfügbare Werkzeug. Dieser Artikel erklärt, wie die JavaScript-Canvas-zu-Base64-Konvertierung funktioniert, wann sie eingesetzt werden sollte und wo die häufigsten Fallstricke liegen.

Wichtigste Erkenntnisse

  • Die Canvas-Methode toDataURL() gibt einen vollständigen Data-URI (mit MIME-Präfix) zurück, keinen reinen Base64-String. Entfernen Sie das Präfix, wenn Sie nur die kodierten Daten benötigen.
  • Bevorzugen Sie toBlob() gegenüber toDataURL() für Datei-Uploads und große Bilder, da es asynchron und speichereffizienter ist.
  • PNG ist das einzige universell unterstützte Ausgabeformat. Die Unterstützung für JPEG und WebP variiert je nach Browser.
  • Cross-Origin-Bilder markieren das Canvas als „tainted”, es sei denn, der Server sendet entsprechende CORS-Header und Sie setzen crossOrigin = 'anonymous', bevor Sie die Bild-src zuweisen.

Der grundlegende Ablauf

Die Konvertierung eines Bildes in Base64 mit Canvas erfolgt in drei Schritten: Laden Sie das Bild, zeichnen Sie es auf ein Canvas-Element und exportieren Sie dann die Canvas-Daten als kodierten String.

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const image = new Image();

image.onload = function () {
  canvas.width = image.width;
  canvas.height = image.height;
  ctx.drawImage(image, 0, 0);

  const dataURL = canvas.toDataURL('image/png');
  console.log(dataURL); // "data:image/png;base64,iVBORw0KGg..."
};

image.src = '/path/to/local-image.jpg';

Dies ist die Grundlage der Canvas-basierten Bildkodierung. Die Methode toDataURL() gibt einen vollständigen Data-URI zurück, keinen reinen Base64-String.

Data-URL vs. reiner Base64-String

Das Verständnis des Unterschieds ist wichtig. canvas.toDataURL() gibt einen String in diesem Format zurück:

data:image/png;base64,iVBORw0KGg...

Er enthält ein MIME-Type-Präfix, die Kodierungsbezeichnung und dann die eigentlichen Base64-Daten. Wenn Sie nur den reinen Base64-Teil benötigen – beispielsweise um ihn als JSON an einen Server zu senden – entfernen Sie das Präfix:

const base64String = canvas.toDataURL('image/jpeg').split(',')[1];

Dies teilt beim ersten Komma und nimmt alles danach. Das Präfix wird verworfen, und die reinen kodierten Daten bleiben übrig.

toDataURL vs. toBlob: Welche Methode sollten Sie verwenden?

Dies ist die Entscheidung, die die meisten Artikel überspringen. Hier ist ein direkter Vergleich:

MerkmaltoDataURL()toBlob()
RückgabetypString (synchron)Blob (asynchron, Callback-basiert)
SpeicherverbrauchHöher (Base64 fügt ~33% Overhead hinzu)Niedriger (binäre Darstellung)
Am besten fürKleine Bilder, schnelle EinbettungenUploads, große Bilder

toDataURL() ist synchron und praktisch, lädt aber den gesamten kodierten String auf einmal in den Speicher. Base64-Kodierung erhöht die Datengröße um etwa 33% im Vergleich zum ursprünglichen Binärformat. Bei großen Bildern ist das relevant.

toBlob() ist asynchron und erzeugt direkt ein binäres Blob, was für Uploads effizienter ist:

canvas.toBlob((blob) => {
  const formData = new FormData();
  formData.append('image', blob, 'export.jpg');
  fetch('/upload', { method: 'POST', body: formData });
}, 'image/jpeg', 0.85);

Verwenden Sie Base64 nur, wenn Sie ausdrücklich einen String benötigen – zum Einbetten in JSON, zum Speichern in einem Textfeld oder zum Generieren eines Data-URI für ein <img>-Tag. Für Datei-Uploads ist toBlob() die bessere Wahl.

Format-Unterstützung und der Qualitätsparameter

PNG ist das einzige Ausgabeformat, das in allen Browsern garantiert wird. Die Unterstützung für JPEG und WebP hängt von der Umgebung ab:

canvas.toDataURL('image/jpeg', 0.85); // Qualität: 0 bis 1, nur JPEG/WebP
canvas.toDataURL('image/webp', 0.9);  // nicht in allen Browsern unterstützt

Der Qualitätsparameter hat keine Auswirkung auf PNG, das immer verlustfrei ist. Für JPEG ist 0.85 ein vernünftiger Standardwert, der Dateigröße und visuelle Qualität ausbalanciert. Wenn Sie ein nicht unterstütztes Format übergeben, fällt der Browser stillschweigend auf PNG zurück.

Das Problem des „Tainted Canvas”

Wenn Sie ein Cross-Origin-Bild ohne entsprechende CORS-Konfiguration auf ein Canvas zeichnen, wird das Canvas als „tainted” (kontaminiert) markiert. Der Aufruf von toDataURL() oder toBlob() auf einem tainted Canvas löst einen SecurityError aus.

Um dies zu vermeiden, muss der Server, der das Bild hostet, entsprechende CORS-Header (Access-Control-Allow-Origin) senden, und Sie müssen crossOrigin auf dem Image-Element setzen, bevor Sie dessen src zuweisen:

const image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://other-origin.com/image.png';

Die Reihenfolge ist hier entscheidend. Wenn Sie crossOrigin nach src setzen, kann der Browser mit dem Abrufen beginnen, ohne das CORS-Flag zu verwenden, was das Canvas dennoch kontaminiert. Bilder, die vom selben Origin geladen werden, sind nie ein Problem. Cross-Origin-Bilder ohne CORS-Header können nicht exportiert werden – es gibt keine clientseitige Lösung.

Wann Canvas-basierte Kodierung sinnvoll ist

Verwenden Sie den Canvas-Ansatz, wenn Sie:

  • Ein Bild clientseitig verkleinern oder zuschneiden müssen, bevor Sie es kodieren
  • Filter oder Transformationen anwenden müssen, bevor Sie exportieren
  • Kleine verarbeitete Bilder als Data-URIs einbetten möchten

Wenn Sie nur eine lokale Datei als Base64 lesen müssen, ohne Canvas-Manipulation, ist FileReader.readAsDataURL() einfacher und überspringt das Canvas vollständig.

Fazit

Die Canvas API gibt Ihnen präzise Kontrolle über die Bildkodierung im Browser. Verwenden Sie toDataURL() für kleine Bilder und String-basierte Anwendungsfälle, bevorzugen Sie toBlob() für Uploads und leistungskritische Arbeiten, und berücksichtigen Sie immer CORS bei der Arbeit mit externen Bildern. Wenn keine Pixelmanipulation erforderlich ist, überspringen Sie das Canvas ganz und greifen Sie stattdessen zu FileReader.

FAQs

Ja, Sie können ein SVG auf ein Canvas zeichnen und toDataURL() aufrufen. Das SVG muss jedoch zuerst als Image-Element geladen werden, und Cross-Origin-Beschränkungen gelten weiterhin. Das exportierte Ergebnis ist eine gerasterte Bitmap, kein skalierbarer Vektor. Externe Ressourcen, auf die das SVG verweist, wie Schriftarten oder verlinkte Bilder, werden möglicherweise nicht korrekt auf dem Canvas gerendert.

Dies geschieht normalerweise, weil toDataURL() aufgerufen wird, bevor das Bild vollständig geladen ist. Stellen Sie sicher, dass Sie es innerhalb des onload-Handlers des Bildes aufrufen. Ein schwarzes Bild kann auch entstehen, wenn Sie die Canvas-Breite und -Höhe nicht auf die Abmessungen des Quellbildes setzen, bevor Sie zeichnen, wodurch das Canvas bei seiner Standardgröße von 300 mal 150 Pixeln bleibt.

Es gibt keine formale Spezifikationsgrenze, aber Browser setzen praktische Beschränkungen. Sehr große Canvas-Elemente können Base64-Strings erzeugen, die erheblichen Speicher verbrauchen oder dazu führen, dass der Browser-Tab langsam wird oder abstürzt. Für große Bilder ist toBlob() die sicherere und speichereffizientere Alternative.

Standard-Canvas-Elemente sind in Web Workern nicht verfügbar, da sie vom DOM abhängen. Sie können jedoch OffscreenCanvas verwenden, das in modernen Browsern unterstützt wird, um das Zeichnen durchzuführen und dessen convertToBlob()-Methode innerhalb eines Workers aufzurufen. Beachten Sie, dass OffscreenCanvas toDataURL() nicht unterstützt, sodass Sie das resultierende Blob mit einem FileReader in Base64 konvertieren müssten, wenn ein String erforderlich ist.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay