Javascript Firefox使用drawImage将SVG图像呈现到HTML5画布时出错

Javascript Firefox使用drawImage将SVG图像呈现到HTML5画布时出错,javascript,firefox,svg,html5-canvas,base64,Javascript,Firefox,Svg,Html5 Canvas,Base64,我正在尝试使用画布将外部svg图标转换为base64 png。它在除Firefox之外的所有浏览器中都能工作,Firefox会抛出一个错误“NS\u error\u NOT\u AVAILABLE” 有人能帮我吗?提前感谢。Firefox不支持将SVG图像绘制到画布,除非SVG文件在根元素上具有宽度/高度属性,并且这些宽度/高度属性不是百分比。这是一个很好的例子 您需要编辑icon.svg文件,使其符合上述标准。如前所述,这是一个开放性错误,原因是Firefox在绘制到画布时接受的svg大小规范

我正在尝试使用画布将外部svg图标转换为base64 png。它在除Firefox之外的所有浏览器中都能工作,Firefox会抛出一个错误“NS\u error\u NOT\u AVAILABLE”


有人能帮我吗?提前感谢。

Firefox不支持将SVG图像绘制到画布,除非SVG文件在根
元素上具有宽度/高度属性,并且这些宽度/高度属性不是百分比。这是一个很好的例子


您需要编辑icon.svg文件,使其符合上述标准。

如前所述,这是一个开放性错误,原因是Firefox在绘制到画布时接受的svg大小规范受到限制。有一个变通办法

Firefox要求SVG本身具有明确的宽度和高度属性。我们可以通过将SVG获取为XML并对其进行修改来添加这些内容

var img=newimage();
var src=“icon.svg”;
//请求svg文件的XML
var request=new XMLHttpRequest();
request.open('GET',src,true)
request.onload=函数(){
//一旦请求返回,解析响应并获取SVG
var parser=新的DOMParser();
var result=parser.parseFromString(request.responseText,'text/xml');
var inlineSVG=result.getElementsByTagName(“svg”)[0];
//添加Firefox需要的属性。这些属性应该是绝对值,而不是相对值
setAttribute('width','48px');
setAttribute('height','48px');
//将SVG转换为数据uri
var svg64=btoa(新的XMLSerializer().serializeToString(inlineSVG));
var image64='数据:image/svg+xml;base64'+svg64;
//将其设置为图像源
img.src=img64;
//做你的画布工作
img.onload=函数(){
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”);
返回dataURL;
};
}
//发送请求

request.send()这并不是最健壮的解决方案,但这项技术为我们的目的发挥了作用。提取
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;
   }
}

svg图标是否具有宽度和高度属性?如果是,它们是百分比吗?嗨,Robert,这是一个svg文件,不是svg dom元素,我们可以为它指定任何宽度/高度。我在页面中使用这个svg,因为它没有回答我的问题。icon.svg在根
元素上是否具有宽度/高度属性。如果是,这些属性值是百分比吗?svg图标是使用Adobe Illustrator生成的,我在svg文件中看不到任何宽度/高度。除了调用
drawImage()
甚至没有抛出错误之外,我也遇到了同样的问题。在中添加宽度/高度确实解决了它!想发布一个指向那个bug的链接吗?跟踪fix会很有趣的progress@tivoni我已经添加了一个链接,但是在w3c定义应该发生什么之前,这个bug不会有任何进展。这个评论显示了一个可能的解决方法:
   // @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;
   }
}