【问题标题】:Firefox error rendering an SVG image to HTML5 canvas with drawImageFirefox 使用 drawImage 将 SVG 图像渲染到 HTML5 画布时出错
【发布时间】:2015-04-25 18:31:27
【问题描述】:

我正在尝试使用画布将外部 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;
};

有人可以帮我解决这个问题吗?提前致谢。

【问题讨论】:

  • 你的 svg 图标有宽度和高度属性吗?如果是,它们是百分比吗?
  • 嗨罗伯特,这是一个 svg 文件而不是 svg dom 元素,我们可以为其分配任何宽度/高度。我在页面中使用这个 svg 作为
  • 这不能回答我的问题。 icon.svg 是否在根 <svg> 元素上具有宽度/高度属性。如果是,这些属性值是百分比吗?
  • svg 图标是使用 Adob​​e Illustrator 生成的,我在 svg 文件中看不到任何宽度/高度。 w3.org/2000/svg" xmlns:xlink="w3.org/1999/xlink" xmlns:a="ns.adobe.com/AdobeSVGViewerExtensions/3.0" x="0px" y="0px" viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
  • 我遇到了同样的问题,只是对drawImage() 的调用甚至没有引发错误。在 中添加宽度/高度确实解决了它!

标签: javascript firefox svg html5-canvas base64


【解决方案1】:

Firefox 不支持将 SVG 图像绘制到画布上,除非 svg 文件在根 <svg> 元素上具有宽度/高度属性,并且这些宽度/高度属性不是百分比。这是longstanding bug

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

【讨论】:

  • 关心发布该错误的链接吗?跟踪修复进度会很有趣
  • @tivoni 我已经添加了一个链接,但是在 w3c 定义应该发生的情况之前,该错误不会有任何进展。
  • 此评论显示了一种可能的解决方法:bugzilla.mozilla.org/show_bug.cgi?id=700533#c39
【解决方案2】:

如前所述,这是一个开放的错误,原因是 Firefox 在绘制到画布时接受的 SVG 尺寸规范受到限制。有一个解决方法。

Firefox 要求 SVG 本身具有明确的宽度和高度属性。我们可以通过将 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 行)中展示了更好的错误处理,我从中派生了该方法的一部分。

【讨论】:

    【解决方案3】:

    这不是最强大的解决方案,但这个 hack 对我们的目的有用。提取viewBox 数据并将这些尺寸用于宽度/高度属性。

    这只有在遇到的第一个 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;
       }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 2015-11-01
      相关资源
      最近更新 更多