我想通过 JavaScript 将 SVG 转换为位图图像(如 JPEG、PNG 等)。
我想通过 JavaScript 将 SVG 转换为位图图像(如 JPEG、PNG 等)。
以下是如何通过JavaScript实现:
toDataURL
即可。 - Mike 'Pomax' Kamermansjbeard4的解决方案效果非常好。
我正在使用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...
});
<svg>...</svg>
,但是jQuery的html()函数不会添加svg标签,所以这段代码对我有用,但我需要编辑canvg实时代码为canvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
。 - Luckyn$(selector).html()
,它将起作用。 - jonathanGBhtml()
或手动构建父 svg
标记——这甚至可能会使这种 hack 遗漏一些属性。只需使用 $(svg_elem)[0].outerHTML
即可获得 svg 的完整源代码及其内容。仅供参考... - JWL这似乎在大多数浏览器中都有效:
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;
}
.msToBlob()
的安全问题,此功能在IE11中无法正常工作。 - Florian Leitgeb将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;
}
URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }))
时,一些SVG被污染了(我怀疑是因为它们在内部定义了 <style>),但是后来我尝试从头开始创建数据URL,像这样:'data:image/svg+xml;utf-8,${svg.replace(/#/g, '%23').replace(/\n/g, '%0A')}';
,这个方法完美地解决了问题!你也可以像这样使用base64:'data:image/svg+xml;base64,${btoa(drawing)}';
。我正在使用electron。 - puaaaal这是一个老问题,在2022年我们有ES6,不需要第三方库。
这里有一种将svg
图像转换为其他格式的基本方法。
关键是将svg
元素作为img
元素加载,然后使用画布元素将图像转换为所需格式。因此,需要四个步骤:
svg
提取为xml
数据字符串。xml
数据字符串加载到img
元素中canvas
元素将img
元素转换为dataURL
dataURL
加载到新的img
元素中提取svg
作为xml
数据字符串很简单,我们不需要将其转换为base64字符串。我们只需将其序列化为XML,然后将字符串编码为URI:
// Data header for a svg image:
const dataHeader = 'data:image/svg+xml;charset=utf-8'
// Serialize it as xml string:
const serializeAsXML = $e => (new XMLSerializer()).serializeToString($e)
// Encode URI data as UTF8 data:
const encodeAsUTF8 = s => `${dataHeader},${encodeURIComponent(s)}`
// Select the element:
const $svg = document.getElementById('svg-container').querySelector('svg')
// Encode it as a data string:
const svgData = encodeAsUTF8(serializeAsXML($svg))
...
// Encode URI data as base64 data:
const encodeAsB64 = s => `${dataHeader};base64,${btoa(s)}`
...
// Encode it as a data string:
const svgData = encodeAsB64(serializeAsXML($svg))
// This function returns a Promise whenever the $img is loaded
const loadImage = async url => {
const $img = document.createElement('img')
$img.src = url
return new Promise((resolve, reject) => {
$img.onload = () => resolve($img)
$img.onerror = reject
$img.src = url
})
}
img.src
两次,我认为第二个就足够了。 - kartsimsdata:image/svg+xml
图像。如果在您的情况下step 2
足够好,请使用我提供的完整解决方案。 - Teocci更改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()
Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
- Xsmael我的使用场景是从网络加载svg数据,而这个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.
});
不需要任何库即可运行
/**
* 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;
});
}
data:image/svg+xml;base64,${btoa(new XMLSerializer().serializeToString(svgElem))}
<!-- test data-->
<svg width="400" height="400"><g transform="translate(23.915343915343925,-80.03971756398937)" class="glyph" stroke="#000000" fill="#a0a0a0"><path d="M74.97 108.70L74.97 108.70L100.08 110.77Q93.89 147.91 87.35 179.89L87.35 179.89L148.23 179.89L148.23 194.34Q143.76 277.91 113.84 339.81L113.84 339.81Q144.44 363.54 163.70 382.46L163.70 382.46L146.51 402.75Q128.62 384.18 101.80 361.83L101.80 361.83Q75.32 405.85 34.39 436.80L34.39 436.80L17.20 415.82Q57.43 386.93 82.20 345.66L82.20 345.66Q57.78 326.40 27.86 304.39L27.86 304.39Q44.37 257.96 56.75 203.97L56.75 203.97L19.26 203.97L19.26 179.89L61.90 179.89Q69.47 145.16 74.97 108.70ZM93.20 323.99L93.20 323.99Q118.65 272.06 123.12 203.97L123.12 203.97L82.20 203.97Q69.47 260.03 55.71 297.17L55.71 297.17Q76.01 311.61 93.20 323.99ZM160.26 285.13L160.26 260.37L239.71 260.37L239.71 216.01Q268.25 191.24 294.05 155.48L294.05 155.48L170.58 155.48L170.58 130.71L322.94 130.71L322.94 155.48Q297.49 191.93 265.50 223.92L265.50 223.92L265.50 260.37L337.38 260.37L337.38 285.13L265.50 285.13L265.50 397.59Q265.50 431.64 237.65 431.64L237.65 431.64L187.09 431.64L180.21 407.57Q202.22 407.91 227.67 407.91L227.67 407.91Q239.71 407.91 239.71 390.03L239.71 390.03L239.71 285.13L160.26 285.13Z"></path></g></svg>
<button title="download">svg2png</button>
<script>
const output = {"name": "result.png", "width": 64, "height": 64}
document.querySelector("button").onclick = () => {
const svgElem = document.querySelector("svg")
// const uriData = `data:image/svg+xml;base64,${btoa(svgElem.outerHTML)}` // it may fail.
const uriData = `data:image/svg+xml;base64,${btoa(new XMLSerializer().serializeToString(svgElem))}`
const img = new Image()
img.src = uriData
img.onload = () => {
const canvas = document.createElement("canvas");
[canvas.width, canvas.height] = [output.width, output.height]
const ctx = canvas.getContext("2d")
ctx.drawImage(img, 0, 0, output.width, output.height)
// download
const a = document.createElement("a")
const quality = 1.0 // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality
a.href = canvas.toDataURL("image/png", quality)
a.download = output.name
a.append(canvas)
a.click()
a.remove()
}
}
</script>
SVG
可以根据条件转换为 PNG
:
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
,在edge中部分支持。可以使用polyfill解决此问题:
https://github.com/nilzona/path2d-polyfill
svg
blob对象并使用.drawImage()
绘制到画布上:请注意,在ie中,您将在canvas.toDataURL()阶段收到异常。这是因为IE具有过高的安全限制,并在绘制图像后将canvas视为只读。所有其他浏览器仅在图像跨域时限制。
canvg
。它是一个单独的库,但具有有用的功能。例如:
ctx.drawSvg(rawSvg);
var dataURL = canvas.toDataURL();