我过去一直使用 canvg 将 SVG 转换为 PNG,但是正如您从链接中看到的那样,它并不支持所有 SVG 功能。如果您使用 D3 或任何喜欢在 SVG 中工作的库,那么您可能会遇到一些不起作用的东西——在我的例子中是 textPath。



SVG 提供了沿任意路径绘制文本的功能,我需要在我的Chord Snip附加组件中执行此操作,但我没有任何方法可以获取生成的 SVG 并创建一个图像,Google Sheets 可以将其用作嵌入图像。


理想情况下,我想使用浏览器来呈现 SVG 而不是 canvg,然后以某种方式获取光栅化结果以从中制作 png 图像,然后将其传递给 Google 表格。就是这样。  


Dom 有一个 API 方法来创建一个对象——createObjectURL(svgtext)。API 因浏览器而异,但这里介绍了如何找到它。



var domUrl = window.URL || window.webkitURL || window;


if (!domUrl) {


throw new Error("(browser doesnt support this)")


}




这个想法是从 svg 代码创建该对象,将其加载到图像元素,然后将该图像写入画布。然后我们可以使用 toDataURL() 来制作一个 base64 编码的 PNG 图像,我们就完成了。

第一步是创建 url,但除非 svg 代码定义了其命名空间,否则这将失败,因此我们将戳 svg 代码

// it needs a namespace


if (!svgText.match(/xmlns=\"/mi)){


svgText = svgText.replace ('<svg ','<svg xmlns="http://www.w3.org/2000/svg" ') ;


}





做一个斑点


// make a blob from the svg


var svg = new Blob([svgText], {


type: "image/svg+xml;charset=utf-8"


});




然后从 blob 创建 URL


var url = domUrl.createObjectURL(svg);





接下来我们需要一个画布,但我们需要通过在 svg 代码中挖掘来推断出所需的画布大小。


// figure out the height and width from svg text


var match = svgText.match(/height=\"(\d+)/m);


var height = match && match[1] ? parseInt(match[1],10) : 200;


var match = svgText.match(/width=\"(\d+)/m);


var width = match && match[1] ? parseInt(match[1],10) : 200;




现在我们可以创建一个画布元素来临时使用。我还将允许一些边距空间作为参数传递,因此画布需要足够大以容纳图像加上周围的任何填充。


// create a canvas element to pass through


var canvas = document.createElement("canvas");


canvas.width = height+margin*2;


canvas.height = width+margin*2;


var ctx = canvas.getContext("2d");




我需要一个新图像,当它加载时,我可以把它写到我的画布上。作为额外的一块糖,我将允许图像具有可选的背景填充 - 如果您有边距或透明输入,则很有用。如果它确实有一个,那么我需要第二个画布,可以用来设置第一个画布的样式。整个事情都包含在一个承诺中,因此可以通过传递 svg 图像的最终画布表示的 toDataUrl() 来解决它。

// create a new image to hold it the converted type


var img = new Image;


        


// when the image is loaded we can get it as base64 url


img.onload = function() {


// draw it to the canvas


ctx.drawImage(this, margin, margin);


          


// if it needs some styling, we need a new canvas


if (fill) {


var styled = document.createElement("canvas");


styled.width = canvas.width;


styled.height = canvas.height;


var styledCtx = styled.getContext("2d");


styledCtx.save();


styledCtx.fillStyle = fill;


styledCtx.fillRect(0,0,canvas.width,canvas.height);


styledCtx.strokeRect(0,0,canvas.width,canvas.height);


styledCtx.restore();


styledCtx.drawImage (canvas, 0,0);


canvas = styled;


}


// we don't need the original any more


domUrl.revokeObjectURL(url);


// now we can resolve the promise, passing the base64 url


resolve(canvas.toDataURL());


};


        


// load the image


img.src = url;




整个东西都可以这样使用。


svgToPng (svgCode , marginSize, canvasFillColor)


.then (function(data) {


// do something with the encode b64 image


})


.catch (function (err) {


// do something with the error


});






编码

我会在试用时报告浏览器兼容性,或者如果您试用它们,请告诉我。




/**


  * converts an svg string to base64 png using the domUrl


  * @param {string} svgText the svgtext


  * @param {number} [margin=0] the width of the border - the image size will be height+margin by width+margin


  * @param {string} [fill] optionally backgrund canvas fill


  * @return {Promise} a promise to the bas64 png image


  */


var svgToPng = function (svgText, margin,fill) {


// convert an svg text to png using the browser


return new Promise(function(resolve, reject) {


try {


// can use the domUrl function from the browser


var domUrl = window.URL || window.webkitURL || window;


if (!domUrl) {


throw new Error("(browser doesnt support this)")


}


        


// figure out the height and width from svg text


var match = svgText.match(/height=\"(\d+)/m);


var height = match && match[1] ? parseInt(match[1],10) : 200;


var match = svgText.match(/width=\"(\d+)/m);


var width = match && match[1] ? parseInt(match[1],10) : 200;


margin = margin || 0;


        


// it needs a namespace


if (!svgText.match(/xmlns=\"/mi)){


svgText = svgText.replace ('<svg ','<svg xmlns="http://www.w3.org/2000/svg" ') ;


}


        


// create a canvas element to pass through


var canvas = document.createElement("canvas");


canvas.width = height+margin*2;


canvas.height = width+margin*2;


var ctx = canvas.getContext("2d");


        


        


// make a blob from the svg


var svg = new Blob([svgText], {


type: "image/svg+xml;charset=utf-8"


});


        


// create a dom object for that image


var url = domUrl.createObjectURL(svg);


        


// create a new image to hold it the converted type


var img = new Image;


        


// when the image is loaded we can get it as base64 url


img.onload = function() {


// draw it to the canvas


ctx.drawImage(this, margin, margin);


          


// if it needs some styling, we need a new canvas


if (fill) {


var styled = document.createElement("canvas");


styled.width = canvas.width;


styled.height = canvas.height;


var styledCtx = styled.getContext("2d");


styledCtx.save();


styledCtx.fillStyle = fill;


styledCtx.fillRect(0,0,canvas.width,canvas.height);


styledCtx.strokeRect(0,0,canvas.width,canvas.height);


styledCtx.restore();


styledCtx.drawImage (canvas, 0,0);


canvas = styled;


}


// we don't need the original any more


domUrl.revokeObjectURL(url);


// now we can resolve the promise, passing the base64 url


resolve(canvas.toDataURL());


};


        


// load the image


img.src = url;


        


} catch (err) {


reject('failed to convert svg to png ' + err);


}


});


};