Problems with getting canvas dataURI from svg with foreignObject

后端 未结 1 383
独厮守ぢ
独厮守ぢ 2021-01-21 03:08

Hi I have the following problem.

I\'m generating a SVG image (https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Drawing_DOM_objects_into_a_canvas).

相关标签:
1条回答
  • 2021-01-21 03:50

    This has nothing to do with CORS. You are not doing any request to an external resource.

    The issue is that drawing an svg (moreover when it contains html elements) is a really sensitive action for browsers.

    That's why there are a lot of limitations on this technique (you can't load external resources, scripts are ignored, you can't style the content from external CSS, all default browser and OS styles are disabled to avoid fingerprinting etc.).
    I don't work for safari nor chrome, so I can't tell for sure, but I think they aren't able to provide enough security on one of these points (safari realised it in v9, and it's a known issue in chrome too).

    So what they do, is that they taint the canvas, locking any of its export methods. (Note that IE < Edge did also taint the canvas whenever any svg had been drawn to the canvas for similar security reasons).

    If what you want is to rasterize DOM elements, then you should parse the DOM and all its applied styles, and reproduce it with canvas drawings methods.
    Doing so, you can bypass most security issues, and no UA will taint the canvas. Some library out there do exactly this, the most famous being html2canvas.

    If what you want is to draw this image, then you can rewrite it without using a foreignObject (svg text has more options than canvas one), then use a library like canvg to render it on your canvas (because otherwise IE will taint the canvas as said previously).


    Note : chrome's issue can be workedaround, but I'm not sure it's a good idea, it will still not work in Safari, nor in IE < Edge, and chrome may just have forgotten to block it too and will in next releases, anyway, here is how :

    var canvas = document.getElementById('c');
    var ctx = canvas.getContext('2d');
    
    var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
      '<foreignObject width="100%" height="100%">' +
      '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
      '<em>I</em> like ' +
      '<span style="color:white; text-shadow:0 0 2px blue;">' +
      'beer</span>' +
      '</div>' +
      '</foreignObject>' +
      '</svg>';
    
    
    var img = new Image();
    // instead of a blobURL, if we use a dataURL, chrome seems happy...
    var url = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(data);
    
    img.onload = function() {
      c.width = this.width;
      c.height = this.height;
      ctx.drawImage(img, 0, 0);
      var dataURL = canvas.toDataURL();
      console.log(dataURL);
    };
    
    img.src = url;
    <canvas id="c"></canvas>

    0 讨论(0)
提交回复
热议问题