2

I believe the answer to my problem can be found in Is there an equivalent of canvas's toDataURL method for SVG?. Can someone confirm or give me a pointer in the right direction.

I cannot get canvas.toDataURL() to produce a correct image if the canvas contains an SVG on Chrome and/or Safari. The code below illustrates the problem.

<!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>

I even wrote an equivalent program using node 0.4.2 and node-canvas using the cairo library and I got the same result when using canvas.toDataURL() with an SVG image. When using node-canvas the img.onload event was not triggered for some reason and if I tried to draw the image without waiting for the onload event I got an error saying that the image had not completed loading. The node program can also be found below.

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>");

Edit I was able to solve my issue thanks to @Phrogz's comment
Below is the code with the problem solved

<!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>
4

1 回答 1

0

Webkit currently taints the canvas when you draw an SVG to it (due to difficult-to-track security concerns). Until FF v12 this was also the case with Firefox, but it is now fixed. You will need to use an SVG parser like CanVG for now if you need the data URL.

于 2013-09-12T22:27:50.160 回答