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


当前回答

Svg到png可以根据条件转换:

如果svg的格式是svg(字符串)路径:

创建画布 创建新的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;

注意,ie中不支持Path2D, edge中部分支持。填充物解决了这个问题: https://github.com/nilzona/path2d-polyfill

使用.drawImage()创建svg blob并在画布上绘制:

制作画布元素 从svg xml生成一个svgBlob对象 从domUrl.createObjectURL(svgBlob)创建一个url对象; 创建一个Image对象并将url分配给Image src 将图像绘制到画布中 从canvas获取png数据字符串:canvas. todataurl ();

漂亮的描述: https://web.archive.org/web/20200125162931/http://ramblings.mcpher.com:80/Home/excelquirks/gassnips/svgtopng

注意,在ie中,你会在canvas.toDataURL()的阶段得到异常;这是因为IE有很高的安全性限制,在那里绘制图像后将canvas视为只读。所有其他浏览器只限制图像是交叉来源。

使用canvg JavaScript库。它是一个单独的库,但有有用的功能。

如:

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

其他回答

使用Canvg库有几种方法将SVG转换为PNG。

在我的例子中,我需要从内联SVG中获取PNG blob。

库文档提供了一个示例(参见OffscreenCanvas示例)。

但是这个方法目前在Firefox中不起作用。是的,你可以在设置中启用gfx. offscreenvas .enabled选项。但是网站上的每个用户都会这么做吗?:)

然而,还有另一种方法也适用于Firefox。

const el = document.getElementById("some-svg"); //this is our inline SVG

var canvas = document.createElement('canvas'); //create a canvas for the SVG render
canvas.width = el.clientWidth; //set canvas sizes
canvas.height = el.clientHeight;

const svg = new XMLSerializer().serializeToString(el); //convert SVG to string

//render SVG inside canvas
const ctx = canvas.getContext('2d');
const v = await Canvg.fromString(ctx, svg);
await v.render();

let canvasBlob = await new Promise(resolve => canvas.toBlob(resolve));

最后一行多亏了这个答案

下面是你如何通过JavaScript来做到这一点:

使用Canvas JavaScript库渲染SVG图像:https://github.com/gabelerner/canvg 根据以下说明,从画布中捕获编码为JPG(或PNG)的数据URI:

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

这似乎在大多数浏览器中都有效:

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

下面是一个函数,它在没有库的情况下工作,并返回一个Promise:

/**
 * converts a base64 encoded data url SVG image to a PNG image
 * @param originalBase64 data url of svg image
 * @param width target width in pixel of PNG image
 * @return {Promise<String>} resolves to png data url of the image
 */
function base64SvgToBase64Png (originalBase64, width) {
    return new Promise(resolve => {
        let img = document.createElement('img');
        img.onload = function () {
            document.body.appendChild(img);
            let canvas = document.createElement("canvas");
            let ratio = (img.clientWidth / img.clientHeight) || 1;
            document.body.removeChild(img);
            canvas.width = width;
            canvas.height = width / ratio;
            let ctx = canvas.getContext("2d");
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
            try {
                let data = canvas.toDataURL('image/png');
                resolve(data);
            } catch (e) {
                resolve(null);
            }
        };
        img.onerror = function() {
            resolve(null);
        };
        img.src = originalBase64;
    });
}

在Firefox上,svg没有设置宽度/高度是有问题的。

请参阅此工作示例,其中包括Firefox问题的修复。