แปลง SVG เป็นรูปภาพ (JPEG, PNG, ฯลฯ ) ในเบราว์เซอร์


299

ฉันต้องการแปลง SVG เป็นภาพบิตแมป (เช่น JPEG, PNG, ฯลฯ ) ผ่านทาง JavaScript


งานอะไรที่คุณต้องการจะทำจริง ๆ ? แม้ว่าคำตอบ echo-flow จะบอกเราว่าเป็นไปได้ (ในบางเบราว์เซอร์) มีวิธีการแปลงที่ดีกว่าและง่ายกว่าสำหรับเกือบทุกกรณี
aaaaaaaaaaaa

2
นี่คือตัวอย่างการใช้ d3: stackoverflow.com/a/23667012/439699
ace

svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - ทำงานได้อย่างสมบูรณ์แบบ! [บนหน้าลิงก์ sourceSVG = $ ("# your_svg_elem_name"). รับ (0)]
Vijay Singh

คำตอบ:


244

นี่คือวิธีที่คุณสามารถทำได้ผ่าน JavaScript:

  1. ใช้ไลบรารี JavaScript canvg เพื่อแสดงภาพ SVG โดยใช้ Canvas: https://github.com/gabelerner/canvg
  2. จับภาพข้อมูล URI ที่เข้ารหัสเป็น JPG (หรือ PNG) จาก Canvas ตามคำแนะนำเหล่านี้: จับภาพ Canvas HTML เป็น gif / jpg / png / pdf หรือไม่

28
นี่ไม่ใช่จาวาสคริปต์อย่างเคร่งครัด แต่เป็น HTML5 เช่นกัน สิ่งนี้จะไม่ทำงานบน IE8 หรือเบราว์เซอร์อื่น ๆ ที่ไม่รองรับ HTML5 Canvas
James

16
หากเบราว์เซอร์รองรับ SVG และแคนวาสจะมีวิธีที่ง่ายกว่ามากในการโหลด SVG ลงในหน่วยความจำแล้วทาสีลงในผืนผ้าใบโดยไม่จำเป็นต้องใช้ Canvg ซึ่งเป็นห้องสมุดขนาดใหญ่เพราะจัดการ SVG ทั้งหมดที่แยกวิเคราะห์ เบราว์เซอร์ที่รองรับ SVG ให้บริการฟรีแล้ว ฉันไม่แน่ใจว่าสิ่งนี้ตรงกับกรณีการใช้ดั้งเดิมหรือไม่ แต่ถ้าเป็นเช่นนั้นให้ดูรายละเอียดของแหล่งข้อมูลนี้
Premasagar

120
ขอบคุณที่ไม่รองรับ IE8 ผู้คนควรเข้าใจว่าถึงเวลาที่ต้องเดินหน้าต่อไป
Sanket Sahu

9
ตอนนี้คุณสามารถใช้Pabloห้องสมุด JavaScript SVG เพื่อให้บรรลุนี้ (ฉันทำมัน) ดูtoImage()และdownload()สำหรับรูปภาพที่ดาวน์โหลดอัตโนมัติ
Premasagar

2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - ทำงานได้อย่างสมบูรณ์แบบ! [บนหน้าลิงก์ sourceSVG = $ ("# your_svg_elem_name"). รับ (0)]
Vijay Singh

44

โซลูชัน jbeard4 ทำงานได้อย่างสวยงาม

ฉันใช้Raphael SketchPadเพื่อสร้าง SVG ลิงก์ไปยังไฟล์ในขั้นตอนที่ 1

สำหรับปุ่มบันทึก (id ของ svg คือ "editor", id ของ 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 ต้องการพารามิเตอร์ที่สองที่จะเป็น<svg>...</svgแต่ jquery html () ฟังก์ชั่นไม่ได้เพิ่มแท็ก svg ดังนั้นรหัสนี้ใช้งานได้สำหรับฉัน แต่ฉันต้องการที่จะแก้ไข canvg อยู่เพื่อcanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
15:05

1
@Luckyn ถ้าคุณเรียกร้อง$(selector).html()ให้ผู้ปกครองขององค์ประกอบsvgของคุณมันจะทำงาน
jonathanGB

@Luckyn และ @jonathanGB คุณไม่ควรใช้สิ่งhtml()ห่อหุ้มหรือสร้างsvgแท็กหลักด้วยตนเอง- ซึ่งอาจมีคุณลักษณะที่คุณไม่ต้องทำด้วยแฮ็คนี้ เพียงใช้$(svg_elem)[0].outerHTMLช่วยให้คุณได้แหล่งที่มาเต็มรูปแบบของ svg และเนื้อหา แค่พูดว่า ...
nemesisfixx

18

ดูเหมือนว่าจะใช้งานได้ในเบราว์เซอร์ส่วนใหญ่:

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
สิ่งนี้ไม่ทำงานใน IE11 เนื่องจากปัญหาด้านความปลอดภัยด้วย.msToBlob()
Florian Leitgeb

ขอบคุณ !! ฉันชอบที่วิธีนี้ใช้ได้กับทั้งโหนด SVG HTML ในพื้นที่และ URL SVG ระยะไกล นอกจากนี้มันไม่จำเป็นต้องมีห้องสมุดภายนอกเต็มรูปแบบ
Fabricio PH

7

วิธีแก้ปัญหาการแปลง SVG เป็น blob URL และ blob URL เป็นภาพ 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

ฉันเขียน ES6 Class ซึ่งทำหน้าที่นี้

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

นี่คือวิธีการใช้งาน

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

หากคุณต้องการรุ่นของวานิลลา JavaScript คุณสามารถตรงไปที่เว็บไซต์ของ Babelและเปลี่ยนรหัสที่นั่น


2

นี่คือโซลูชันฝั่งเซิร์ฟเวอร์ซึ่งใช้ PhantomJS คุณสามารถใช้ JSONP เพื่อโทรข้ามโดเมนไปยังบริการรูปภาพได้:

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

ตัวอย่างเช่น:

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

จากนั้นคุณสามารถแสดงภาพด้วยแท็ก img:

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

มันทำงานผ่านเบราว์เซอร์


บริการดูเหมือนจะตาย

3
โฮสต์ของเราถูกโจมตีด้วยคำขอปลอม ดังนั้นเราจึงตัดสินใจที่จะลง คุณจะต้องเรียกใช้เซิร์ฟเวอร์ของคุณเองในตอนนี้ ดู repo GitHub สำหรับข้อมูลเพิ่มเติม
Phuoc Do

1

เปลี่ยนsvgให้ตรงกับองค์ประกอบของคุณ

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
มันไม่ทำงานสำหรับฉันฉันได้รับข้อผิดพลาดนี้:Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
Xsmael

1
@Xsmael พยายามที่จะสลับอินเตอร์เฟซ DOMParser developer.mozilla.org/en-US/docs/Web/API/DOMParser
มาห์ Khalili

1

Svgที่pngสามารถแปลงได้ขึ้นอยู่กับเงื่อนไข:

  1. หากsvgอยู่ในรูปแบบเส้นทาง SVG (สตริง) :
    • สร้างผืนผ้าใบ
    • สร้างnew Path2D()และตั้งsvgเป็นพารามิเตอร์
    • วาดเส้นทางบนผืนผ้าใบ
    • สร้างภาพและการใช้งานเป็นcanvas.toDataURL()src

ตัวอย่าง:

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;

โปรดทราบว่าPath2Dไม่รองรับieและรองรับบางส่วนในขอบ Polyfill แก้ปัญหาได้ที่: https://github.com/nilzona/path2d-polyfill

  1. สร้างsvgหยดและวาดบนผืนผ้าใบโดยใช้.drawImage():
    • ทำองค์ประกอบผ้าใบ
    • สร้างวัตถุ svgBlob จาก svg xml
    • ทำวัตถุ url จาก domUrl.createObjectURL (svgBlob);
    • สร้างวัตถุรูปภาพและกำหนด url ให้กับรูปภาพ src
    • วาดภาพลงบนผืนผ้าใบ
    • รับสตริงข้อมูล png จาก canvas: canvas.toDataURL ();

คำอธิบายที่ดี: http://ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

โปรดทราบว่าใน ie คุณจะได้รับข้อยกเว้นในระยะของ canvas.toDataURL (); เป็นเพราะ IE มีข้อ จำกัด ด้านความปลอดภัยที่สูงเกินไปและถือว่า Canvas เป็นแบบอ่านอย่างเดียวหลังจากวาดภาพที่นั่น เบราว์เซอร์อื่น ๆ ทั้งหมดจะ จำกัด เฉพาะในกรณีที่ภาพเป็นจุดกำเนิดข้าม

  1. ใช้canvgไลบรารี JavaScript มันเป็นห้องสมุดแยก แต่มีฟังก์ชั่นที่มีประโยชน์

ชอบ:

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

ลิงก์ที่สามเสีย
Serdar Sayın

ใช่แน่นอน. ฉันไม่รู้จะไปที่นั่นได้อย่างไร แต่คำอธิบายข้างต้นอาจเพียงพอสำหรับความเข้าใจ ความคิดที่ดีสำหรับอนาคตที่จะคัดลอกบริบทหลังจากการอ้างอิง
Alex Vovchuk

0

เมื่อเร็ว ๆ นี้ฉันค้นพบห้องสมุดติดตามภาพสองภาพสำหรับ JavaScript ซึ่งสามารถสร้างบิตแมปที่ยอมรับได้ทั้งขนาดและคุณภาพ ฉันกำลังพัฒนาไลบรารี JavaScript และ CLI นี้:

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

ซึ่งจัดทำ API แบบครบวงจรสำหรับพวกเขาทั้งหมดรองรับเบราว์เซอร์และโหนดไม่ขึ้นอยู่กับ DOM และเครื่องมือบรรทัดคำสั่ง

สำหรับการแปลงโลโก้ / การ์ตูน / ภาพเหมือนมันทำงานได้ดี สำหรับภาพถ่าย / ความสมจริงปรับแต่งบางอย่างเป็นสิ่งจำเป็นเนื่องจากขนาดเอาต์พุตสามารถเติบโตได้มาก

มันมีสนามเด็กเล่นแม้ว่าตอนนี้ฉันกำลังใช้งานที่ดีกว่าใช้งานง่ายกว่าเนื่องจากมีการเพิ่มคุณสมบัติเพิ่มเติม:

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.