我正在尝试使用画布将外部svg图标转换为base64 png。它适用于除Firefox之外的所有浏览器,它会引发错误" NS_ERROR_NOT_AVAILABLE"。
var img = new Image();
img.src = "icon.svg";
img.onload = function() {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL;
};
有人可以帮我吗?提前谢谢。
答案 0 :(得分:25)
Firefox不支持将SVG图像绘制到画布,除非svg文件在根<svg>
元素上具有width / height属性,并且这些width / height属性不是百分比。这是longstanding bug。
您需要编辑icon.svg文件,使其符合上述条件。
答案 1 :(得分:1)
如前所述,这是一个开放的错误,是由Firefox在绘制到画布上时作为SVG尺寸规范接受的限制引起的。有一种解决方法。
Firefox在SVG本身中需要显式的width和height属性。我们可以通过将SVG转换为XML并对其进行修改来添加它们。
var img = new Image();
var src = "icon.svg";
// request the XML of your svg file
var request = new XMLHttpRequest();
request.open('GET', src, true)
request.onload = function() {
// once the request returns, parse the response and get the SVG
var parser = new DOMParser();
var result = parser.parseFromString(request.responseText, 'text/xml');
var inlineSVG = result.getElementsByTagName("svg")[0];
// add the attributes Firefox needs. These should be absolute values, not relative
inlineSVG.setAttribute('width', '48px');
inlineSVG.setAttribute('height', '48px');
// convert the SVG to a data uri
var svg64 = btoa(new XMLSerializer().serializeToString(inlineSVG));
var image64 = 'data:image/svg+xml;base64,' + svg64;
// set that as your image source
img.src = img64;
// do your canvas work
img.onload = function() {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL;
};
}
// send the request
request.send();
这是此解决方案的最基本版本,并且在检索XML时不包含任何错误处理。 this inline-svg handler(大约第110行)展示了更好的错误处理,我从中得出了该方法的一部分。
答案 2 :(得分:0)
这不是最可靠的解决方案,但此黑客确实可以达到我们的目的。提取viewBox
数据,并将这些尺寸用于width / height属性。
只有在遇到的第一个viewBox
的大小可以准确地表示SVG文档的大小的情况下才有效,这并非在所有情况下都是正确的。
// @svgDoc is some SVG document.
let svgSize = getSvgViewBox(svgDoc);
// No SVG size?
if (!svgSize.width || !svgSize.height) {
console.log('Image is missing width or height');
// Have size, resolve with new SVG image data.
} else {
// Rewrite SVG doc
let unit = 'px';
$('svg', svgDoc).attr('width', svgSize.width + unit);
$('svg', svgDoc).attr('height', svgSize.height + unit);
// Get data URL for new SVG.
let svgDataUrl = svgDocToDataURL(svgDoc);
}
function getSvgViewBox(svgDoc) {
if (svgDoc) {
// Get viewBox from SVG doc.
let viewBox = $(svgDoc).find('svg').prop('viewBox').baseVal;
// Have viewBox?
if (viewBox) {
return {
width: viewBox.width,
height: viewBox.height
}
}
}
// If here, no viewBox found so return null case.
return {
width: null,
height: null
}
}
function svgDocToDataURL(svgDoc, base64) {
// Set SVG prefix.
const svgPrefix = "data:image/svg+xml;";
// Serialize SVG doc.
var svgData = new XMLSerializer().serializeToString(svgDoc);
// Base64? Return Base64-encoding for data URL.
if (base64) {
var base64Data = btoa(svgData);
return svgPrefix + "base64," + base64Data;
// Nope, not Base64. Return URL-encoding for data URL.
} else {
var urlData = encodeURIComponent(svgData);
return svgPrefix + "charset=utf8," + urlData;
}
}