【问题标题】:toDataURL does not work for html5 canvas with an SVG imagetoDataURL 不适用于带有 SVG 图像的 html5 画布
【发布时间】:2012-05-06 06:34:15
【问题描述】:

我相信我的问题的答案可以在Is there an equivalent of canvas's toDataURL method for SVG? 中找到。有人可以确认或给我一个正确方向的指针。

如果画布在 Chrome 和/或 Safari 上包含 SVG,我无法让 canvas.toDataURL() 生成正确的图像。下面的代码说明了这个问题。

<!DOCTYPE html>
<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
  <script>
  $(document).ready(function () {
        var __readLocalXml = function(file)
        {
            xmlHttp = new XMLHttpRequest();
            xmlHttp.open("GET",file,false);
            xmlHttp.send();
            return xmlHttp.responseXML;
        };

        var __drawSVG = function(context, sourceSVG, x, y){
            var svg_xml = (new XMLSerializer()).serializeToString(sourceSVG);

            var img = new Image();
            img.src="";
            var myFunction = function() {
                context.drawImage(img, x, y);
            }
            img.addEventListener('load', myFunction, false);
            img.src = "data:image/svg+xml;base64,"+btoa(svg_xml);

        };

        var settings = {
            //White King
            //Chess_klt45.svg
            //<http://en.wikipedia.org/wiki/File:Chess_klt45.svg>
            'whiteKingSVG'      : function() { return __readLocalXml("svg/Chess_klt45.svg") }
        }

        var canvas = document.createElement('canvas');
        var cw = canvas.width = 45;
        var ch = canvas.height = 45;

        var context = canvas.getContext('2d');

        context.fillStyle = '#FFFFCC';
        context.fillRect(0,
                         0,
                        ch,
                        cw);
        __drawSVG(context, settings.whiteKingSVG(),0,0);

        $('#withCanvas').after(canvas);
        $('#withToDataUrl').after('<img src="' + canvas.toDataURL() + '" />');
  });
  </script>
</head>
<body>
    <h1>Works</h1>
    <div id="withCanvas"></div>
    <hr>
    <h1>Does not Work</h1>
    <div id="withToDataUrl"></div>
</body>
</html>

我什至使用 cairo 库使用 node 0.4.2 和 node-canvas 编写了一个等效程序,并且在使用带有 SVG 图像的 canvas.toDataURL() 时得到了相同的结果。使用 node-canvas 时,由于某种原因没有触发 img.onload 事件,如果我尝试在不等待 onload 事件的情况下绘制图像,则会收到错误消息,指出图像尚未完成加载。节点程序也可以在下面找到。

var Canvas = require('canvas');

var __readFileNodeSync=function(file){
   var fs = require('fs');

   try {
      return fs.readFileSync(file, 'ascii');
   } catch (err) {
      console.error("There was an error opening the file:");
      console.log(err);
   }
}

var __loadXml_xmldom=function(file){
   var DOMParser = require("xmldom").DOMParser;
   var xml=__readFileNodeSync(file)
   return new DOMParser().parseFromString(xml)
}

var __drawSVG = function(context, sourceSVG, x, y){
   var btoa = require('btoa');
   var XMLSerializer = require("xmldom").XMLSerializer;
   var svg_xml = new XMLSerializer().serializeToString(sourceSVG);
   var img = new Canvas.Image;
   img.onload = function(){
      context.drawImage(img, x, y);
   }
   img.src = "data:image/svg+xml;base64,"+btoa(svg_xml);
};


var settings = {
   //White King
   //Chess_klt45.svg
   //<http://en.wikipedia.org/wiki/File:Chess_klt45.svg>
   'whiteKingSVG'      : function() { return __loadXml_xmldom("../svg/Chess_klt45.svg") }
}

   var canvas = new Canvas();
   var cw = canvas.width = 45;
   var ch = canvas.height = 45;

   var context = canvas.getContext('2d');

   context.fillStyle = '#FFFFCC';
   context.fillRect(0,
                    0,
                   ch,
                   cw);
   __drawSVG(context, settings.whiteKingSVG(),0,0);

   console.log("<html>");
   console.log("<head>");
   console.log("</head>");
   console.log("<body>");
   console.log('<img src="'+canvas.toDataURL() + '" />');
   console.log("</body>");
   console.log("</html>");

编辑感谢@Phrogz 的评论,我能够解决我的问题
下面是解决问题的代码

<!DOCTYPE html>
<html>
<head>
  <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script> 
  <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
  <script>
  $(document).ready(function () {

        var settings = {
            //White King
            //Chess_klt45.svg
            //<http://en.wikipedia.org/wiki/File:Chess_klt45.svg>
            'whiteKingSVG'      : "svg/Chess_klt45.svg" 
        }

        var canvas = document.createElement('canvas');

        var cw = canvas.width = 45;
        var ch = canvas.height = 45;
        var context = canvas.getContext('2d');

        context.fillStyle = '#FFFFCC';
        context.fillRect(0,
                     0,
                    ch,
                    cw);

        canvg(canvas, settings.whiteKingSVG, { 
                ignoreMouse: true, 
                ignoreAnimation: true, 
                ignoreDimensions: true, 
                ignoreClear: true, 
                offsetX: 0, 
                offsetY: 0
        });
        $('#withCanvas').after(canvas);
        $('#withToDataUrl').after('<img alt="whiteKing.png" src="' + canvas.toDataURL("image/png") + '" />');
  });
  </script>
</head>
<body>
    <h1>Works</h1>
    <div id="withCanvas"></div>
    <hr>
    <h1>Works! (using canvg)</h1>
    <div id="withToDataUrl"></div>
</body>
</html>

【问题讨论】:

  • Webkit 当前在您向其绘制 SVG 时会污染画布(由于难以跟踪的安全问题)。在 FF v12 之前,Firefox 也是如此,但现在已修复。如果你需要数据 URL,你现在需要使用像 CanVG 这样的 SVG 解析器。
  • 谢谢@Phrogz。你的评论正是我所需要的。

标签: html node.js canvas webkit svg


【解决方案1】:

当前,当您在画布上绘制 SVG 时,Webkit 会污染画布(由于难以跟踪的安全问题)。在 FF v12 之前,Firefox 也是如此,但现在已修复。如果您需要数据 URL,您现在需要使用像 CanVG 这样的 SVG 解析器。

【讨论】:

    猜你喜欢
    • 2011-08-07
    • 2014-05-22
    • 1970-01-01
    • 2013-04-11
    • 2014-05-30
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 2012-05-16
    相关资源
    最近更新 更多