在浏览器中将SVG转换为图像(JPEG,PNG等)


299

我想通过JavaScript将SVG转换为位图图像(如JPEG,PNG等)。


您实际上要完成什么任务?即使echo-flows回答告诉我们(在某些浏览器中)可能,对于几乎所有实际情况,都有更好,更轻松的转换方法。
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”)。get(0)]
Vijay Singh

Answers:


244

您可以通过JavaScript进行以下操作:

  1. 使用canvg JavaScript库通过Canvas渲染SVG图像:https : //github.com/gabelerner/canvg
  2. 根据以下说明,从Canvas捕获编码为JPG(或PNG)的数据URI:将HTML Canvas捕获为gif / jpg / png / pdf?

28
严格来说,这不是Javascript,但HTML5也是如此。这在IE8或任何其他不支持HTML5 Canvas的浏览器上将不起作用。
詹姆斯

16
如果浏览器支持SVG和画布,那么将有一种更简单的方法将SVG加载到内存中,然后将其绘制到画布中,而无需Canvg,这是一个相当大的库,因为它可以处理所有的SVG解析支持SVG的浏览器已经免费提供。我不确定这是否满足原始用例,但如果满足,请参阅此资源以获取详细信息
2013年

120
感谢您不支持IE8。人们应该明白,该继续前进了。
Sanket Sahu 2014年

9
现在,您可以使用JavaScript SVG库Pablo来实现此目的(我做到了)。有关自动下载的图片,请参见toImage()download()
2014年

2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back-完美运行![在链接页面上,sourceSVG = $(“#your_svg_elem_name”)。get(0)]
Vijay Singh

44

jbeard4解决方案效果很好。

我正在使用Raphael SketchPad创建SVG。链接到步骤1中的文件。

对于“保存”按钮(svg的ID为“ editor”,canvas的ID为“ 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 live编辑为canvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn 2015年

1
@Luckyn如果调用svg元素$(selector).html()的父元素,它将起作用
jonathanGB

@Luckyn和@jonathanGB,您不必html()在包装器上使用,也不必手动构造父svg标记-甚至可能具有此hack遗漏的属性。只需使用即可$(svg_elem)[0].outerHTML为您提供svg及其内容的完整来源。只是说...
nemesisfixx '16

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
由于IE的安全性问题,这在IE11中不起作用.msToBlob()
Florian Leitgeb

谢谢!!我喜欢这对“本地” SVG HTML节点和远程SVG URL都起作用的方式。另外,它不需要完整的外部库
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 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:// [host] /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
我们的房东遭到虚假请求的打击。因此,我们决定将其删除。您现在必须运行自己的服务器。有关更多信息,请参见github repo。
Phuoc Do 2015年

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

Svgpng可根据条件被转换:

  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. 使用以下方法创建svgblob并在画布上绘制.drawImage()
    • 制作画布元素
    • 从svg xml制作svgBlob对象
    • 从domUrl.createObjectURL(svgBlob)创建一个url对象;
    • 创建一个Image对象并将URL分配给image src
    • 将图像绘制到画布中
    • 从画布获取png数据字符串:canvas.toDataURL();

不错的描述: http //ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

注意,在ie中,您将在canvas.toDataURL()阶段获得异常;这是因为IE的安全性限制过高,并且在此处绘制图像后将画布视为只读。所有其他浏览器仅在图像是跨原点的情况下才进行限制。

  1. 使用canvgJavaScript库。它是单独的库,但具有有用的功能。

喜欢:

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

第三条链接中断
SerdarSayı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/#

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.