JavaScript 将 SVG 下载为 PNG 格式的修改方案
本文介绍如何基于 saveSvgAsPng 库修改代码,实现指定 SVG 元素下载为 PNG 格式。通过封装 download 方法,支持传入 DOM 元素或 D3 选择器获取的目标。重点解决了 SVG 未设置命名空间的问题,确保克隆元素正确添加 xmlns 属性而不影响原图,适用于前端图片导出场景。
SVG 下载为 PNG 的解决方案
在处理需要将 SVG 图形下载为图片的需求时,网络上常见的解决方案如 https://github.com/exupero/saveSvgAsPng 往往存在缺陷,例如会意外下载页面中所有的 SVG 元素。为了解决这一问题,我在其源码基础上进行了针对性修改,具体实现代码如下所示:
var doctype = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [<!ENTITY nbsp " ">]>';
function convertToPng(src, w, h) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = w;
canvas.height = h;
context.drawImage(src, 0, 0);
var png;
try {
png = canvas.toDataURL("image/png");
} catch (e) {
if ((typeof SecurityError !== 'undefined' && e instanceof SecurityError) || e.name == "SecurityError") {
console.error("Rendered SVG images cannot be downloaded in this browser.");
return;
} else {
throw e;
}
}
return png;
}
function isElement(obj) {
return obj instanceof HTMLElement || obj instanceof SVGElement;
}
function reEncode(data) {
data = encodeURIComponent(data);
data = data.replace(/%([0-9A-F]{2})/g, function (match, p1) {
var c = String.fromCharCode('0x' + p1);
return c === '%' ? '%25' : c;
});
return decodeURIComponent(data);
}
function uriToBlob(uri) {
var byteString = window.atob(uri.split(',')[1]);
var mimeString = uri.split(',')[0].split(':')[1].split(';')[0]
var buffer = new ArrayBuffer(byteString.length);
var intArray = new Uint8Array(buffer);
for (var i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
return new Blob([buffer], {type: mimeString});
}
function downLoad(el, name) {
if (!isElement(el)) {
throw new Error('an HTMLElement or SVGElement is required; got ' + el);
}
if (!name) {
console.error("文件名为空!");
return;
}
var xmlns = "http://www.w3.org/2000/xmlns/";
var clone = el.cloneNode(true);
clone.setAttribute("version", "1.1");
if (!clone.getAttribute('xmlns')) {
clone.setAttributeNS(xmlns, "xmlns", "http://www.w3.org/2000/svg");
}
if (!clone.getAttribute('xmlns:xlink')) {
clone.setAttributeNS(xmlns, "xmlns:xlink", "http://www.w3.org/1999/xlink");
}
var svg = clone.outerHTML;
var uri = 'data:image/svg+xml;base64,' + window.btoa(reEncode(doctype + svg));
var image = new Image();
image.onload = function () {
var png = convertToPng(image, image.width, image.height);
var saveLink = document.createElement('a');
var downloadSupported = 'download' in saveLink;
if (downloadSupported) {
saveLink.download = name + ".png";
saveLink.style.display = 'none';
document.body.appendChild(saveLink);
try {
var blob = uriToBlob(png);
var url = URL.createObjectURL(blob);
saveLink.href = url;
saveLink.onclick = function () {
requestAnimationFrame(function () {
URL.revokeObjectURL(url);
})
};
} catch (e) {
saveLink.href = uri;
}
saveLink.click();
document.body.removeChild(saveLink);
}
};
image.src = uri;
}
download 方法的使用与参数说明
实际使用时,只需调用封装好的 download 方法即可,建议将其封装为独立的下载服务模块。该方法的第一个参数 el 代表目标 DOM 元素,即需要下载的 SVG 节点。获取该元素的方式灵活,既可以使用原生 JavaScript,也可以通过 D3 等库的选择器来获取。例如:
<div id="svg-parent-div"><svg>...</svg></div>
通常可以通过获取 SVG 的父容器元素来定位目标节点,具体操作如:
var el = d3.select("#svg-parent-div").node().children[0];
download(el,"下载图片");
完成上述步骤后,即可正常触发下载。
命名空间处理机制
代码中特别处理了 SVG 元素未设置命名空间的情况。如果检测到 SVG 元素缺少必要的命名空间定义,程序会自动进行添加,相关逻辑如下:
el.setAttributeNS(xmlns, "xmlns", "http://www.w3.org/2000/svg");
el.setAttributeNS(xmlns, "xmlns:xlink", "http://www.w3.org/1999/xlink");
需要注意的是,上述添加命名空间的逻辑仅作用于克隆后的元素副本,因此不会对页面上原始的 SVG 元素产生任何副作用。
总结
以上介绍了利用 JavaScript 将 SVG 图片下载为 PNG 格式的具体实现方法,希望能为遇到类似问题的开发者提供参考。如有疑问欢迎留言,我们将及时回复。感谢大家的支持!
ES6模块化中js文件怎么用import和export交互
2026-11-05 17:00:48
JS读取本地文件时报错或无响应的常见原因
2026-11-05 16:32:31
let、const与var的区别:JavaScript变量声明最佳实践
2026-11-05 14:16:38
JS中直接定义静态二维数组的字面量写法
2026-11-05 14:16:08
JS 怎么查找字符串中所有匹配项的位置
2026-11-05 14:15:53
