Konversi SVG ke gambar (JPEG, PNG, dll.) Di browser

300

Saya ingin mengubah SVG menjadi gambar bitmap (seperti JPEG, PNG, dll.) Melalui JavaScript.

Zain
sumber
Tugas apa yang sebenarnya ingin Anda capai? Meskipun jawaban echo-aliran memberi tahu kami bahwa (di beberapa browser) mungkin ada metode konversi yang lebih baik dan lebih mudah untuk hampir semua kasus praktis.
aaaaaaaaaaaa
2
Berikut ini contoh menggunakan d3: stackoverflow.com/a/23667012/439699
ace
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - Bekerja dengan sempurna! [Pada halaman tautan, sourceSVG = $ ("# your_svg_elem_name"). Dapatkan (0)]
Vijay Singh
terkait: stackoverflow.com/questions/3173048/...
mathheadinclouds

Jawaban:

244

Berikut ini cara melakukannya melalui JavaScript:

  1. Gunakan perpustakaan JavaScript canvg untuk merender gambar SVG menggunakan Canvas: https://github.com/gabelerner/canvg
  2. Abadikan data URI yang disandikan sebagai JPG (atau PNG) dari Kanvas, sesuai dengan petunjuk ini: Menangkap Kanvas HTML sebagai gif / jpg / png / pdf?
jbeard4
sumber
28
Ini bukan sepenuhnya Javascript, tetapi HTML5 juga. Ini tidak akan berfungsi pada IE8, atau browser lain yang tidak mendukung HTML5 Canvas.
James
16
Jika browser mendukung SVG dan kanvas, maka akan ada cara yang jauh lebih sederhana untuk memuat SVG ke dalam memori dan kemudian melukisnya ke dalam kanvas, tanpa perlu Canvg, yang merupakan perpustakaan yang cukup besar karena menangani semua penguraian SVG yang browser yang mendukung SVG sudah menyediakan secara gratis. Saya tidak yakin apakah ini memenuhi kasus penggunaan asli, tetapi jika demikian, maka lihat sumber daya ini untuk detailnya .
Premasagar
120
Terima kasih karena tidak mendukung IE8. Orang-orang harus mengerti bahwa sudah waktunya untuk pindah.
Sanket Sahu
9
Anda sekarang dapat menggunakan perpustakaan JavaScript SVG Pablo untuk mencapai ini (saya membuatnya). Lihat toImage()dan juga download()untuk gambar yang diunduh otomatis.
Premasagar
2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - Bekerja dengan sempurna! [Pada halaman tautan, sourceSVG = $ ("# your_svg_elem_name"). Dapatkan (0)]
Vijay Singh
44

solusi jbeard4 bekerja dengan baik.

Saya menggunakan Raphael SketchPad untuk membuat SVG. Tautkan ke file di langkah 1.

Untuk tombol Simpan (id svg adalah "editor", id kanvas adalah "kanvas"):

$("#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...
});
mengurung
sumber
1
canvg memerlukan parameter kedua menjadi <svg>...</svgtetapi fungsi jquery html () tidak menambahkan tag svg, jadi kode ini berfungsi untuk saya tetapi saya perlu mengedit canvg langsung kecanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn
1
@Luckyn jika Anda memanggil $(selector).html()orang tua dari elemen svg Anda , itu akan berhasil
jonathanGB
@Luckyn dan @jonathanGB, Anda tidak harus menggunakan html()pembungkus, atau membuat svgtag induk secara manual - yang bahkan mungkin memiliki atribut yang Anda tinggalkan dengan peretasan ini. Cukup gunakan $(svg_elem)[0].outerHTMLmemberi Anda sumber penuh svg dan isinya. Hanya mengatakan ...
nemesisfixx
18

Ini tampaknya berfungsi di sebagian besar 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;
}
terburuk
sumber
3
Ini tidak berfungsi di IE11, karena masalah keamanan dengan.msToBlob()
Florian Leitgeb
Terima kasih!! Saya suka cara kerjanya untuk simpul HTML SVG "lokal" dan URL SVG jarak jauh. Plus itu tidak memerlukan perpustakaan eksternal penuh
Fabricio PH
7

Solusi untuk mengkonversi SVG ke gumpalan URL dan gumpalan URL ke gambar 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;
 }

Thom Kiesewetter
sumber
3

Saya menulis Kelas ES6 ini yang melakukan Pekerjaan.

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

Inilah cara Anda menggunakannya

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

Jika Anda menginginkan versi JavaScript vanilla, Anda bisa menuju ke situs web Babel dan mengubah kode di sana.

Cels
sumber
2

Inilah solusi sisi server berdasarkan PhantomJS. Anda dapat menggunakan JSONP untuk melakukan panggilan lintas domain ke layanan gambar:

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

Sebagai contoh:

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

Kemudian Anda dapat menampilkan gambar dengan tag img:

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

Ini berfungsi di seluruh browser.

Phuoc Do
sumber
Layanan tampaknya sudah mati.
3
Tuan rumah kami dipukul dengan permintaan palsu. Jadi kami memutuskan untuk mengambilnya. Anda harus menjalankan server Anda sendiri sekarang. Lihat repo github untuk info lebih lanjut.
Phuoc Do
1

ubah svguntuk mencocokkan elemen Anda

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()
Mahdi Khalili
sumber
1
itu tidak berfungsi untuk saya, saya mendapatkan kesalahan ini:Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
Xsmael
1
@Xsmael mencoba untuk Mengganti antarmuka DOMParser, developer.mozilla.org/en-US/docs/Web/API/DOMParser
Mahdi Khalili
1

Svguntuk pngdapat dikonversi tergantung pada kondisi:

  1. Jika svgdalam format jalur SVG (string) :
    • buat kanvas
    • buat new Path2D()dan tetapkan svgsebagai parameter
    • menggambar jalan di atas kanvas
    • buat gambar dan gunakan canvas.toDataURL()sebagai src.

contoh:

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;

Perhatikan bahwa Path2Dtidak didukung di iedan sebagian didukung di tepi. Polyfill memecahkan itu: https://github.com/nilzona/path2d-polyfill

  1. Buat svggumpalan dan gambar di atas kanvas menggunakan .drawImage():
    • membuat elemen kanvas
    • membuat objek svgBlob dari xml svg
    • membuat objek url dari domUrl.createObjectURL (svgBlob);
    • buat objek Gambar dan tetapkan url ke gambar src
    • menggambar gambar ke kanvas
    • dapatkan png data string dari canvas: canvas.toDataURL ();

Deskripsi yang bagus: http://ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

Perhatikan bahwa dalam contoh Anda akan mendapatkan pengecualian pada tahap canvas.toDataURL (); Itu karena IE memiliki batasan keamanan yang terlalu tinggi dan memperlakukan kanvas sebagai hanya baca setelah menggambar di sana. Semua browser lain hanya membatasi jika gambar asal lintas.

  1. Gunakan canvgperpustakaan JavaScript. Ini adalah perpustakaan yang terpisah tetapi memiliki fungsi yang berguna.

Suka:

ctx.drawSvg(rawSvg);
var dataURL = canvas.toDataURL();
Alex Vovchuk
sumber
Tautan ke-3 rusak
Serdar Sayın
ya memang. Saya tidak tahu bagaimana mencapai di sana sekarang. Tetapi deskripsi di atas bisa cukup untuk beberapa pengertian. Ide bagus untuk co copy masa depan beberapa konteks setelah referensi
Alex Vovchuk
0

Baru-baru ini saya menemukan beberapa pustaka penelusuran gambar untuk JavaScript yang memang mampu membangun perkiraan yang dapat diterima terhadap bitmap, baik ukuran dan kualitasnya. Saya sedang mengembangkan perpustakaan JavaScript dan CLI ini:

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

Yang menyediakan API terpadu untuk semuanya, mendukung browser dan node, tidak tergantung pada DOM, dan alat baris perintah.

Untuk mengkonversi gambar logo / kartun / seperti itu melakukan pekerjaan dengan sangat baik. Untuk foto / realisme beberapa penyesuaian diperlukan karena ukuran output dapat tumbuh banyak.

Ini memiliki taman bermain meskipun saat ini saya sedang mengerjakan yang lebih baik, lebih mudah digunakan, karena lebih banyak fitur telah ditambahkan:

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

kankerbero
sumber