Converti SVG in immagine (JPEG, PNG, ecc.) Nel browser


300

Voglio convertire SVG in immagini bitmap (come JPEG, PNG, ecc.) Tramite JavaScript.


Quale compito vuoi veramente svolgere? Anche se la risposta ai flussi di eco ci dice che è possibile (in alcuni browser), esistono metodi di conversione migliori e più facili per quasi tutti i casi pratici.
aaaaaaaaaaaa,

2
Ecco un esempio usando d3: stackoverflow.com/a/23667012/439699
asso

svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - Funziona perfettamente! [Nella pagina dei collegamenti, sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Vijay Singh

Risposte:


244

Ecco come puoi farlo tramite JavaScript:

  1. Utilizzare la libreria JavaScript canvg per eseguire il rendering dell'immagine SVG utilizzando Canvas: https://github.com/gabelerner/canvg
  2. Cattura un URI di dati codificato come JPG (o PNG) dalla tela, secondo queste istruzioni: Cattura la tela HTML come gif / jpg / png / pdf?

28
Questo non è strettamente Javascript, ma anche HTML5. Questo non funzionerà su IE8 o su qualsiasi altro browser che non supporta HTML5 Canvas.
James,

16
Se il browser supporta SVG e canvas, allora ci sarebbe un modo molto più semplice per caricare l'SVG in memoria e poi dipingerlo in un canvas, senza la necessità di Canvg, che è una libreria piuttosto grande perché gestisce tutto l'SVG che analizza quel un browser che supporta SVG fornisce già gratuitamente. Non sono sicuro che questo soddisfi il caso d'uso originale, ma in tal caso, vedere questa risorsa per i dettagli .
Premasagar,

120
Grazie per non supportare IE8. Le persone dovrebbero capire che è tempo di andare avanti.
Sanket Sahu,

9
Ora puoi usare la libreria SVG di JavaScript Pablo per raggiungere questo obiettivo (ce l'ho fatta). Vedere toImage()e anche download()per un'immagine scaricata automaticamente.
Premasagar,

2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - Funziona perfettamente! [Nella pagina dei collegamenti, sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Vijay Singh

44

La soluzione jbeard4 ha funzionato magnificamente.

Sto usando Raphael SketchPad per creare un SVG. Collegamento ai file al passaggio 1.

Per un pulsante Salva (id di svg è "editor", id di canvas è "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 ha bisogno del secondo parametro per essere <svg>...</svgma la funzione jquery html () non aggiunge il tag svg, quindi questo codice funziona per me ma dovevo modificare il canvg livecanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn

1
@Luckyn se chiami $(selector).html()il genitore del tuo elemento svg , funzionerà
jonathanGB

@Luckyn e @jonathanGB, non dovresti usare gli html()involucri o costruire manualmente il svgtag principale , che potrebbe anche avere attributi che lasci fuori da questo hack. Basta usare $(svg_elem)[0].outerHTMLti dà la fonte completa di svg e il suo contenuto.
Sto

18

Questo sembra funzionare nella maggior parte dei browser:

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
Questo non funziona in IE11, a causa del problema di sicurezza con.msToBlob()
Florian Leitgeb,

Grazie!! Adoro come funziona sia per un nodo HTML SVG "locale" che per un URL SVG remoto. Inoltre non richiede una libreria esterna completa
Fabricio PH

7

La soluzione per convertire SVG in URL BLOB e URL BLOB in immagine PNG

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

Ho scritto questa classe ES6 che fa il lavoro.

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;
  }
}

Ecco come lo usi

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.
});

Se desideri una versione JavaScript vaniglia, puoi visitare il sito Web di Babel e compilare il codice lì.


2

Ecco una soluzione lato server basata su PhantomJS. È possibile utilizzare JSONP per effettuare una chiamata tra domini al servizio immagine:

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

Per esempio:

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

Quindi puoi visualizzare l'immagine con il tag img:

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

Funziona su browser.


Il servizio sembra essere morto.

3
Il nostro ospite era stato colpito da richieste fasulle. Quindi abbiamo deciso di smontarlo. Dovrai eseguire il tuo server ora. Vedi repo github per maggiori informazioni.
Phuoc Do,

1

cambia svgper abbinare il tuo elemento

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
non funziona per me, ho questo errore:Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
Xsmael,

1
@Xsmael prova a cambiare l'interfaccia DOMParser developer.mozilla.org/en-US/docs/Web/API/DOMParser
Mahdi Khalili il

1

Svgto pngpuò essere convertito in base alle condizioni:

  1. Se svgè in formato percorsi SVG (stringa) :
    • creare tela
    • crea new Path2D()e imposta svgcome parametro
    • disegna il percorso su tela
    • crea immagine e usa canvas.toDataURL()come src.

esempio:

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;

Si noti che Path2Dnon è supportato iee parzialmente supportato in Edge. Polyfill risolve questo problema: https://github.com/nilzona/path2d-polyfill

  1. Crea svgblob e disegna su tela usando .drawImage():
    • crea un elemento canvas
    • crea un oggetto svgBlob dal svg xml
    • crea un oggetto url da domUrl.createObjectURL (svgBlob);
    • crea un oggetto Image e assegna l'URL a image src
    • disegna l'immagine su tela
    • ottenere la stringa di dati png da canvas: canvas.toDataURL ();

Bella descrizione: http://ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

Si noti che in ie si otterrà un'eccezione sullo stage di canvas.toDataURL (); È perché IE ha una restrizione di sicurezza troppo elevata e considera il canvas immediatamente dopo aver disegnato l'immagine lì. Tutti gli altri browser limitano solo se l'immagine è di origine incrociata.

  1. Usa la canvglibreria JavaScript. È una libreria separata ma ha funzioni utili.

Piace:

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

Terzo collegamento interrotto
Serdar Sayın il

si Certamente. Non so come arrivarci adesso. Ma la descrizione sopra può essere sufficiente per una certa comprensione. Buona idea per il futuro copiare un po 'di contesto dopo il riferimento
Alex Vovchuk,

0

Di recente ho scoperto un paio di librerie di tracciamento di immagini per JavaScript che sono effettivamente in grado di costruire un'approssimazione accettabile per la bitmap, sia per dimensioni che per qualità. Sto sviluppando questa libreria JavaScript e CLI:

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

Che fornisce API unificate per tutti loro, supportando browser e nodo, non dipendenti dal DOM, e uno strumento da riga di comando.

Per convertire loghi / cartoni animati / immagini simili, fa un ottimo lavoro. Per le foto / il realismo sono necessarie alcune modifiche poiché le dimensioni dell'output possono crescere molto.

Ha un parco giochi anche se in questo momento sto lavorando a uno migliore, più facile da usare, poiché sono state aggiunte più funzionalità:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.