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.
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:
- Zuerst das SVG in BASE64 umwandeln,
- dann das SVGbase64 in den Canvas zeichnen
- dann den Canvas in PNG umwandeln
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.