canvas toDataURL – SVG und Canvas als Bitmap speichern

SVG mit toDataURL in Bitmap umwandeln

canvas.toDataURL() erfasst den Inhalt eines Canvas-Elements und gibt eine Base64-codierte Zeichenkette zurück, die z.B. als Bitmap-Bild heruntergeladen werden kann.

23-02-02 SITEMAP CSS HTML JS Basis JS Web Tutorial SVG

Canvas als Bitmap-Bild für den Download anbieten

Die einfachste Methode, einen Canvas als Bitmap zu exportieren, kommt mit Firefox und Chrome: Ein Rechtsklick auf den Canvas und Firefox bietet das Laden als PNG an. Das macht Sinn, denn ein Canvas ist nichts anderes als eine Bitmap.

Canvas als PNG speichern mit Rechtsklick in Firefox und Chrome

So einfach machen IE11, Edge und Safari die Sache nicht. Davon abgesehen, ist der Rechtsklick zum Laden eines Bildes nicht allen Benutzern vertraut. Da springt canvas.toDataURL() ein.

toDataURL(type, quality)

toDataURL() ist eine Methode des Canvas und wandelt das Bild im Canvas in eine Bitmap (64 bit encoded PNG URL) um, um das Bild zu speichern oder in einem img-Tag anzuzeigen oder um den String an eine Anwendung zu übergeben (z.B. um die Zeichnung in ein PDF einzusetzen). Wenn JPG gefragt ist, kann toDataURL () image/jpeg als erstes Argument und einen Wert zwischen 0 und 1 für die Qualität im zweiten Argument aufnehmen.

Die Methode hat zwei optionale Parameter: canvas.toDataURL(type, quality). type ist das Bildformat (ohne Angabe gibt toDataURL den Inhalt als image/png zurück). quality ist eine Zahl zwischen 0 und 1 und steht für die Bildqualität (die Vorgabe ist 0.92).

So kann dem Benutzer die Bitmap im Canvas zum Download angeboten werden.

const canvas = document.querySelector("#littleblue");
const ctx = canvas.getContext("2d");

ctx.beginPath();
ctx.fillStyle = "#445";
ctx.moveTo(59.6,2.14);
ctx.lineTo(1739,2.14);
ctx.bezierCurveTo(1772,2.14, 1800,28.74, 1800,61.74 );
…
// Canvas zu PNG
const dataURL = canvas.toDataURL();
const img = document.createElement("img");
img.width = "1800";
img.height = "1256";
img.src = dataURL;

const link = document.createElement("a");
link.download = "bluerocket.png";
link.href = dataURL;
link.innerHTML = "Download als PNG";
document.getElementById("blue").appendChild(link);

Anstelle von toDataURL("image/png") oder einfach toDataURL() gibt canvas.toDataURL('image/jpeg', quality) das Bild als JPG mit der angegebenen Qualitätsrate zwischen 0 und 1 zurück.

Alle modernen Browser. Getestet mit Chrome, Safari, Firefox. Auch Microsoft Edge ist nachgezogen, aber IE11 unterstützt das Download-Attribut nicht.

Bitmap-Bilder im Canvas

Wenn Bilder in das Canvas-Element geladen werden, müssen die Bilder auf derselben Domain wie das ausführende Script liegen, ansonsten gibt es eine SECURITY_ERR Exception oder Meldungen wie Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

Dabei sind schon

  • https://www.domain.de/
  • https://domain.de
  • http://www.domain.de/

verschiedene Domains.

SVG als Bitmap speichern

Wir haben zwar ein canvas.toDataURL, aber es gibt kein svg.toDataURL, um eine SVG-Grafik als PNG oder JPEG anzubieten. Was bleibt, ist der Weg über das Laden der SVG in einen Canvas, um dem Benutzer ein Bitmap-Bild für den Download anzubieten.

Das haben die Browser in der Vergangenheit immer unterschiedlich angegangen und mit neuen Browserversionen haben sich neue Hindernisse eingestellt. Jetzt haben sich (fast) alle Browser auf denselben Weg geeinigt. Die Ausnahme ist IE11.

SVG inline im Dokument

Passiert in drei Schritten:

  1. Zuerst das SVG in BASE64 umwandeln,
  2. dann das SVGbase64 in den Canvas zeichnen
  3. dann den Canvas in PNG umwandeln
Schritt 1: SVG zu Base64 umgewandelt

SVG als PNG von Canvas

Für Firefox muss das SVG-Element absolute Breite und Höhe haben. Die übliche Angabe von width="100%" height="100%" führt zu einem leeren Bild.

// Nicht 
<svg id="cinema" height="100%" width="100%" viewBox="0 0 800 382">

// Sondern
<svg id="cinema" height="800" width="382" viewBox="0 0 800 382">
const mySVG    = document.querySelector("#cinema"),
      can      = document.createElement('canvas'), // muss auf der Seite nicht angezeigt werden
      ctx      = can.getContext('2d'),
      tgtImage = document.createElement("img"),
      loader   = new Image;  

const viewBox = mySVG.getAttribute("viewBox");
const vb = viewBox.split(' ');

mySVG.setAttribute("width",vb[2]);   // Breite, Höhe des SVG für das Seitenverhältnis
mySVG.setAttribute("height",vb[3]);

tgtImage.width  = can.width  = loader.width = vb[2]; 
tgtImage.height = can.height = loader.height = vb[3];

XMLSerializer erzeugt ein Element für den Download (alle modernen Browser und Internet Explorer ab Version 11)

document.querySelector("#toset").appendChild(tgtImage);

const svgAsXML = (new XMLSerializer).serializeToString( mySVG );
loader.src = 'data:image/svg+xml,' + encodeURIComponent( svgAsXML );

loader.onload = function(){
    ctx.drawImage( loader, 0, 0, loader.width, loader.height );
    tgtImage.src = can.toDataURL('image/png');
};

IE11 warf bei : can.toDataURL einen SecurityError (aufgrund der Umwandlung von SVG) und es scheint keine Lösung zu geben – aber IE ist im Sondermüll des Internets gelandet.

Mit der SVG Library http://fabricjs.com soll das Umwandeln in PNG auch funktionieren, aber fabricjs ist rd. 300KB schwer.