Konvertieren Sie SVG im Browser in ein Bild (JPEG, PNG usw.)


299

Ich möchte SVG über JavaScript in Bitmap-Bilder (wie JPEG, PNG usw.) konvertieren.


Welche Aufgabe möchten Sie eigentlich erfüllen? Obwohl die Antwort auf Echo-Flows uns sagt, dass es (in einigen Browsern) möglich ist, gibt es für fast alle praktischen Fälle bessere und einfachere Konvertierungsmethoden.
aaaaaaaaaaaa

2
Hier ist ein Beispiel mit d3: stackoverflow.com/a/23667012/439699
Ass

svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - Funktioniert perfekt! [Auf der Link-Seite ist sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Vijay Singh

Antworten:


244

So können Sie dies mit JavaScript tun:

  1. Verwenden Sie die JavaScript-Bibliothek von canvg, um das SVG-Bild mithilfe von Canvas zu rendern: https://github.com/gabelerner/canvg
  2. Erfassen Sie einen als JPG (oder PNG) codierten Daten-URI aus dem Canvas gemäß den folgenden Anweisungen: HTML-Canvas als gif / jpg / png / pdf erfassen?

28
Dies ist nicht ausschließlich Javascript, sondern auch HTML5. Dies funktioniert nicht mit IE8 oder einem anderen Browser, der HTML5 Canvas nicht unterstützt.
James

16
Wenn der Browser SVG und Canvas unterstützt, gibt es eine viel einfachere Möglichkeit, das SVG in den Speicher zu laden und es dann in ein Canvas zu malen, ohne dass Canvg erforderlich ist, eine ziemlich große Bibliothek, da es das gesamte SVG-Parsen übernimmt Ein SVG-unterstützender Browser bietet bereits kostenlos. Ich bin nicht sicher, ob dies dem ursprünglichen Anwendungsfall entspricht, aber wenn ja, lesen Sie diese Ressource für Details .
Premasagar

120
Vielen Dank, dass Sie IE8 nicht unterstützen. Die Leute sollten verstehen, dass es Zeit ist, weiterzumachen.
Sanket Sahu

9
Sie können jetzt die JavaScript-SVG-Bibliothek Pablo verwenden , um dies zu erreichen (ich habe es geschafft). Siehe das toImage()und auch download()für ein automatisch heruntergeladenes Bild.
Premasagar

2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - Funktioniert perfekt! [Auf der Link-Seite ist sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Vijay Singh

44

Die jbeard4-Lösung hat wunderbar funktioniert.

Ich verwende Raphael SketchPad , um eine SVG zu erstellen. Link zu den Dateien in Schritt 1.

Für eine Schaltfläche Speichern (ID von svg ist "editor", ID von canvas ist "canvas"):

$("#editor_save").click(function() {

// the canvg call that takes the svg xml and converts it to a canvas
canvg('canvas', $("#editor").html());

// the canvas calls to output a png
var canvas = document.getElementById("canvas");
var img = canvas.toDataURL("image/png");
// do what you want with the base64, write to screen, post to server, etc...
});

1
canvg muss den zweiten Parameter haben, <svg>...</svgaber die Funktion jquery html () fügt kein svg-Tag hinzu, daher funktioniert dieser Code für mich, aber ich musste das canvg live bearbeitencanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn

1
@Luckyn, wenn Sie $(selector).html()das übergeordnete Element Ihres svg- Elements aufrufen , wird es funktionieren
jonathanGB

@Luckyn und @jonathanGB sollten Sie nicht html()für Wrapper verwenden oder das übergeordnete svgTag manuell erstellen müssen - möglicherweise sogar Attribute, die Sie bei diesem Hack auslassen. Durch die einfache Verwendung erhalten $(svg_elem)[0].outerHTMLSie die vollständige Quelle des SVG und seines Inhalts.
Ich

18

Dies scheint in den meisten Browsern zu funktionieren:

function copyStylesInline(destinationNode, sourceNode) {
   var containerElements = ["svg","g"];
   for (var cd = 0; cd < destinationNode.childNodes.length; cd++) {
       var child = destinationNode.childNodes[cd];
       if (containerElements.indexOf(child.tagName) != -1) {
            copyStylesInline(child, sourceNode.childNodes[cd]);
            continue;
       }
       var style = sourceNode.childNodes[cd].currentStyle || window.getComputedStyle(sourceNode.childNodes[cd]);
       if (style == "undefined" || style == null) continue;
       for (var st = 0; st < style.length; st++){
            child.style.setProperty(style[st], style.getPropertyValue(style[st]));
       }
   }
}

function triggerDownload (imgURI, fileName) {
  var evt = new MouseEvent("click", {
    view: window,
    bubbles: false,
    cancelable: true
  });
  var a = document.createElement("a");
  a.setAttribute("download", fileName);
  a.setAttribute("href", imgURI);
  a.setAttribute("target", '_blank');
  a.dispatchEvent(evt);
}

function downloadSvg(svg, fileName) {
  var copy = svg.cloneNode(true);
  copyStylesInline(copy, svg);
  var canvas = document.createElement("canvas");
  var bbox = svg.getBBox();
  canvas.width = bbox.width;
  canvas.height = bbox.height;
  var ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, bbox.width, bbox.height);
  var data = (new XMLSerializer()).serializeToString(copy);
  var DOMURL = window.URL || window.webkitURL || window;
  var img = new Image();
  var svgBlob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
  var url = DOMURL.createObjectURL(svgBlob);
  img.onload = function () {
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);
    if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob)
    {
        var blob = canvas.msToBlob();         
        navigator.msSaveOrOpenBlob(blob, fileName);
    } 
    else {
        var imgURI = canvas
            .toDataURL("image/png")
            .replace("image/png", "image/octet-stream");
        triggerDownload(imgURI, fileName);
    }
    document.removeChild(canvas);
  };
  img.src = url;
}

3
Dies funktioniert nicht in IE11, wegen des Sicherheitsproblems mit.msToBlob()
Florian Leitgeb

Vielen Dank!! Ich finde es toll, wie dies sowohl für einen "lokalen" SVG-HTML-Knoten als auch für eine entfernte SVG-URL funktioniert. Außerdem ist keine vollständige externe Bibliothek erforderlich
Fabricio PH

7

Die Lösung zum Konvertieren von SVG in Blob-URL und Blob-URL in PNG-Bild

const svg=`<svg version="1.1" baseProfile="full" width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
   <rect width="100%" height="100%" fill="red" />
   <circle cx="150" cy="100" r="80" fill="green" />
   <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text></svg>`
svgToPng(svg,(imgData)=>{
    const pngImage = document.createElement('img');
    document.body.appendChild(pngImage);
    pngImage.src=imgData;
});
 function svgToPng(svg, callback) {
    const url = getSvgUrl(svg);
    svgUrlToPng(url, (imgData) => {
        callback(imgData);
        URL.revokeObjectURL(url);
    });
}
function getSvgUrl(svg) {
    return  URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
}
function svgUrlToPng(svgUrl, callback) {
    const svgImage = document.createElement('img');
    // imgPreview.style.position = 'absolute';
    // imgPreview.style.top = '-9999px';
    document.body.appendChild(svgImage);
    svgImage.onload = function () {
        const canvas = document.createElement('canvas');
        canvas.width = svgImage.clientWidth;
        canvas.height = svgImage.clientHeight;
        const canvasCtx = canvas.getContext('2d');
        canvasCtx.drawImage(svgImage, 0, 0);
        const imgData = canvas.toDataURL('image/png');
        callback(imgData);
        // document.body.removeChild(imgPreview);
    };
    svgImage.src = svgUrl;
 }


3

Ich habe diese ES6-Klasse geschrieben, die den Job macht.

class SvgToPngConverter {
  constructor() {
    this._init = this._init.bind(this);
    this._cleanUp = this._cleanUp.bind(this);
    this.convertFromInput = this.convertFromInput.bind(this);
  }

  _init() {
    this.canvas = document.createElement("canvas");
    this.imgPreview = document.createElement("img");
    this.imgPreview.style = "position: absolute; top: -9999px";

    document.body.appendChild(this.imgPreview);
    this.canvasCtx = this.canvas.getContext("2d");
  }

  _cleanUp() {
    document.body.removeChild(this.imgPreview);
  }

  convertFromInput(input, callback) {
    this._init();
    let _this = this;
    this.imgPreview.onload = function() {
      const img = new Image();
      _this.canvas.width = _this.imgPreview.clientWidth;
      _this.canvas.height = _this.imgPreview.clientHeight;
      img.crossOrigin = "anonymous";
      img.src = _this.imgPreview.src;
      img.onload = function() {
        _this.canvasCtx.drawImage(img, 0, 0);
        let imgData = _this.canvas.toDataURL("image/png");
        if(typeof callback == "function"){
            callback(imgData)
        }
        _this._cleanUp();
      };
    };

    this.imgPreview.src = input;
  }
}

So verwenden Sie es

let input = "https://restcountries.eu/data/afg.svg"
new SvgToPngConverter().convertFromInput(input, function(imgData){
    // You now have your png data in base64 (imgData). 
    // Do what ever you wish with it here.
});

Wenn Sie eine Vanille-JavaScript-Version wünschen, können Sie zur Babel-Website gehen und den Code dort transpilieren.


2

Hier ist eine serverseitige Lösung, die auf PhantomJS basiert. Mit JSONP können Sie den Image-Service domänenübergreifend aufrufen:

https://github.com/vidalab/banquo-server

Beispielsweise:

http: // [host] /api/https%3A%2F%2Fvida.io%2Fdocuments%2FWgBMc4zDWF7YpqXGR/viewport_width=980&viewport_height=900&delay=5000&selector=%23canvas

Dann können Sie das Bild mit dem img-Tag anzeigen:

<img src="data:image/png;base64, [base64 data]"/>

Es funktioniert browserübergreifend.


Der Dienst scheint tot zu sein.

3
Unser Gastgeber war von falschen Anfragen getroffen worden. Also beschlossen wir, es abzubauen. Sie müssen jetzt Ihren eigenen Server betreiben. Weitere Informationen finden Sie unter Github Repo.
Phuoc Do

1

Ändern Sie svg, um Ihrem Element zu entsprechen

function svg2img(){
    var svg = document.querySelector('svg');
    var xml = new XMLSerializer().serializeToString(svg);
    var svg64 = btoa(xml); //for utf8: btoa(unescape(encodeURIComponent(xml)))
    var b64start = 'data:image/svg+xml;base64,';
    var image64 = b64start + svg64;
    return image64;
};svg2img()

1
es funktioniert nicht für mich, ich bekomme diesen Fehler:Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
Xsmael

1
@ Xsmael versuchen, die DOMParser-Schnittstelle zu wechseln developer.mozilla.org/en-US/docs/Web/API/DOMParser
Mahdi Khalili

1

Svgto pngkann abhängig von den Bedingungen konvertiert werden:

  1. Wenn svgim Format SVG (String) Pfade ist :
    • Leinwand erstellen
    • erstellen new Path2D()und svgals Parameter festlegen
    • zeichne Pfad auf Leinwand
    • Bild erstellen und verwenden canvas.toDataURL()als src.

Beispiel:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let svgText = 'M10 10 h 80 v 80 h -80 Z';
let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
ctx.stroke(p);
let url = canvas.toDataURL();
const img = new Image();
img.src = url;

Beachten Sie, dass dies in Edge Path2Dnicht ieund teilweise in Edge unterstützt wird. Polyfill löst Folgendes: https://github.com/nilzona/path2d-polyfill

  1. Erstellen Sie einen svgBlob und zeichnen Sie auf Leinwand mit .drawImage():
    • Leinwandelement machen
    • Erstellen Sie ein svgBlob-Objekt aus der svg-XML
    • Erstellen Sie ein URL-Objekt aus domUrl.createObjectURL (svgBlob).
    • Erstellen Sie ein Image-Objekt und weisen Sie Image src eine URL zu
    • Bild in Leinwand zeichnen
    • png-Datenzeichenfolge von canvas abrufen: canvas.toDataURL ();

Schöne Beschreibung: http://ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

Beachten Sie, dass Sie in dh auf der Bühne von canvas.toDataURL () eine Ausnahme erhalten; Dies liegt daran, dass der IE zu hohe Sicherheitsbeschränkungen aufweist und die Leinwand nach dem Zeichnen des Bilds als schreibgeschützt behandelt. Alle anderen Browser schränken nur ein, wenn das Bild einen Kreuzursprung aufweist.

  1. Verwenden Sie die canvgJavaScript-Bibliothek. Es ist eine separate Bibliothek, hat aber nützliche Funktionen.

Mögen:

ctx.drawSvg(rawSvg);
var dataURL = canvas.toDataURL();

3. Link ist defekt
Serdar Sayın

ja in der Tat. Ich weiß jetzt nicht, wie ich dorthin gelangen soll. Die obige Beschreibung kann jedoch für ein gewisses Verständnis ausreichen. Gute Idee für zukünftige Co-Kopie eines Kontextes nach der Referenz
Alex Vovchuk

0

Ich habe kürzlich einige Bildverfolgungsbibliotheken für JavaScript entdeckt, die tatsächlich eine akzeptable Annäherung an die Bitmap erstellen können, sowohl in Bezug auf Größe als auch Qualität. Ich entwickle diese JavaScript-Bibliothek und CLI:

https://www.npmjs.com/package/svg-png-converter

Dies bietet eine einheitliche API für alle, unterstützt Browser und Knoten, unabhängig vom DOM, und ein Befehlszeilentool.

Zum Konvertieren von Logos / Cartoons / ähnlichen Bildern macht es hervorragende Arbeit. Für Fotos / Realismus sind einige Anpassungen erforderlich, da die Ausgabegröße stark ansteigen kann.

Es gibt einen Spielplatz, obwohl ich gerade an einem besseren arbeite, der einfacher zu bedienen ist, da weitere Funktionen hinzugefügt wurden:

https://cancerberosgx.github.io/demos/svg-png-converter/playground/#

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.