Chuyển đổi SVG thành hình ảnh (JPEG, PNG, v.v.) trong trình duyệt


299

Tôi muốn chuyển đổi SVG thành hình ảnh bitmap (như JPEG, PNG, v.v.) thông qua JavaScript.


Nhiệm vụ nào mà bạn thực sự muốn hoàn thành? Mặc dù câu trả lời của echo cho chúng ta biết rằng (trong một số trình duyệt) có thể có các phương thức chuyển đổi tốt hơn và dễ dàng hơn cho hầu hết các trường hợp thực tế.
aaaaaaaaaaaa

2
Dưới đây là một ví dụ sử dụng d3: stackoverflow.com/a/23667012/439499
ace

svgopen.org/2010/auge/62-From_SVG_to_Canvas_and_Back - Hoạt động hoàn hảo! [Trên trang liên kết, sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Vijay Singh

Câu trả lời:


244

Đây là cách bạn có thể làm điều đó thông qua JavaScript:

  1. Sử dụng thư viện JavaScript canvg để hiển thị hình ảnh SVG bằng Canvas: https://github.com/gabelerner/canvg
  2. Chụp URI dữ liệu được mã hóa dưới dạng JPG (hoặc PNG) từ Canvas, theo các hướng dẫn sau: Chụp Canvas HTML dưới dạng gif / jpg / png / pdf?

28
Đây không hoàn toàn là Javascript, nhưng HTML5 cũng vậy. Điều này sẽ không hoạt động trên IE8 hoặc bất kỳ trình duyệt nào khác không hỗ trợ HTML5 Canvas.
James

16
Nếu trình duyệt hỗ trợ SVG và canvas, thì sẽ có cách đơn giản hơn nhiều để tải SVG vào bộ nhớ và sau đó vẽ nó vào canvas, không cần Canvg, đây là một thư viện khá lớn vì nó xử lý tất cả các phân tích SVG một trình duyệt hỗ trợ SVG đã cung cấp miễn phí. Tôi không chắc điều này có thỏa mãn trường hợp sử dụng ban đầu hay không, nhưng nếu vậy, hãy xem tài nguyên này để biết chi tiết .
Premasagar

120
Cảm ơn vì đã không hỗ trợ IE8. Mọi người nên hiểu rằng đã đến lúc tiến lên.
Sanket Sahu

9
Bây giờ bạn có thể sử dụng thư viện JavaScript SVG Pablo để đạt được điều này (tôi đã tạo ra nó). Xem toImage()và cũng download()cho một hình ảnh tự động tải xuống.
Premasagar

2
svgopen.org/2010/auge/62-From_SVG_to_Canvas_and_Back - Hoạt động hoàn hảo! [Trên trang liên kết, sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Vijay Singh

44

giải pháp jbeard4 làm việc đẹp.

Tôi đang sử dụng Raphael SketchPad để tạo một SVG. Liên kết đến các tập tin trong bước 1.

Đối với nút Lưu (id của svg là "trình chỉnh sửa", id của canvas là "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 cần tham số thứ hai là <svg>...</svgnhưng hàm jquery html () không thêm thẻ svg, vì vậy mã này hoạt động với tôi nhưng tôi cần chỉnh sửa canvg trực tiếp thànhcanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn

1
@Luckyn nếu bạn gọi $(selector).html()cha mẹ của phần tử svg , nó sẽ hoạt động
jonathanGB

@Luckyn và @jonathanGB, bạn không nên sử dụng html()trên trình bao bọc hoặc xây dựng thủ công svgthẻ cha - có thể có các thuộc tính bạn bỏ qua với bản hack này. Chỉ cần sử dụng $(svg_elem)[0].outerHTMLcung cấp cho bạn nguồn đầy đủ của Svg và nội dung của nó. Chỉ cần nói ...
nemeisfixx

18

Điều này dường như hoạt động trong hầu hết các trình duyệt:

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
Điều này không hoạt động trong IE11, vì vấn đề bảo mật với.msToBlob()
Florian Leit Quay

Cảm ơn!! Tôi thích cách thức hoạt động của cả nút HTML SVG "cục bộ" và URL SVG từ xa. Thêm vào đó, nó không yêu cầu một thư viện bên ngoài đầy đủ
Fabricio PH

7

Giải pháp chuyển đổi SVG sang URL blob và URL blob thành hình ảnh 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

Tôi đã viết Lớp ES6 này thực hiện Công việc.

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

Đây là cách bạn sử dụng nó

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

Nếu bạn muốn có phiên bản JavaScript vanilla, bạn có thể truy cập trang web Babel và dịch mã ở đó.


2

Đây là một giải pháp phía máy chủ dựa trên PhantomJS. Bạn có thể sử dụng JSONP để thực hiện cuộc gọi tên miền chéo đến dịch vụ hình ảnh:

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

Ví dụ:

http: // [host] /api/https%3A%2F%2Fvida.io%2Fdocument

Sau đó, bạn có thể hiển thị hình ảnh với thẻ img:

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

Nó hoạt động trên trình duyệt.


Các dịch vụ dường như đã chết.

3
Máy chủ của chúng tôi đã bị tấn công với các yêu cầu không có thật. Vì vậy, chúng tôi quyết định đưa nó xuống. Bạn sẽ phải chạy máy chủ của riêng bạn bây giờ. Xem repo github để biết thêm.
Phước Đỗ

1

thay đổi svgđể phù hợp với yếu tố của bạn

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
nó không hoạt động với tôi, tôi gặp lỗi này:Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
Xsmael 14/12/18

1
@Xsmael thử chuyển đổi nhà phát triển
Mahdi Khalili

1

Svgđể pngcó thể được chuyển đổi tùy thuộc vào điều kiện:

  1. Nếu svgở định dạng đường dẫn SVG (chuỗi) :
    • tạo vải
    • tạo new Path2D()và đặt svglàm tham số
    • vẽ đường dẫn trên vải
    • tạo hình ảnh và sử dụng canvas.toDataURL()như src.

thí dụ:

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;

Lưu ý rằng Path2Dkhông được hỗ trợ ievà hỗ trợ một phần trong cạnh. Polyfill giải quyết rằng: https://github.com/nilzona/path2d-polyfill

  1. Tạo svgblob và vẽ trên canvas bằng cách sử dụng .drawImage():
    • làm yếu tố vải
    • tạo một đối tượng svgBlob từ svg xml
    • tạo một đối tượng url từ domUrl.createObjectURL (svgBlob);
    • tạo một đối tượng Image và gán url cho src hình ảnh
    • vẽ hình ảnh vào khung vẽ
    • lấy chuỗi dữ liệu png từ canvas: canvas.toDataURL ();

Mô tả hay: http://ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

Lưu ý rằng tức là bạn sẽ có ngoại lệ trên sân khấu của canvas.toDataURL (); Đó là bởi vì IE có giới hạn bảo mật quá cao và coi canvas là chỉ đọc sau khi vẽ hình ảnh ở đó. Tất cả các trình duyệt khác chỉ hạn chế nếu hình ảnh có nguồn gốc chéo.

  1. Sử dụng canvgthư viện JavaScript. Nó là thư viện riêng biệt nhưng có chức năng hữu ích.

Giống:

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

Liên kết thứ 3 bị hỏng
Serdar Sayın

vâng, thực sự Tôi không biết làm thế nào để đến đó bây giờ. Nhưng mô tả ở trên có thể là đủ cho một số hiểu biết. Ý tưởng tốt cho tương lai sao chép một số bối cảnh sau khi tham khảo
Alex Vovchuk

0

Gần đây tôi đã phát hiện ra một vài thư viện theo dõi hình ảnh cho JavaScript mà thực sự có thể xây dựng một xấp xỉ chấp nhận được cho bitmap, cả về kích thước và chất lượng. Tôi đang phát triển thư viện JavaScript và CLI này:

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

Cung cấp API hợp nhất cho tất cả chúng, hỗ trợ trình duyệt và nút, không phụ thuộc vào DOM và công cụ dòng lệnh.

Để chuyển đổi logo / phim hoạt hình / hình ảnh giống như nó làm công việc tuyệt vời. Đối với ảnh / hiện thực, một số điều chỉnh là cần thiết vì kích thước đầu ra có thể tăng lên rất nhiều.

Nó có một sân chơi mặc dù hiện tại tôi đang làm việc trên một cái tốt hơn, dễ sử dụng hơn, vì nhiều tính năng đã được thêm vào:

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.