【问题标题】:JavaScript: toDataUrl() throwing "Security Error: Tainted canvases may not be exported."JavaScript:toDataUrl() 抛出“安全错误:可能无法导出受污染的画布。”
【发布时间】:2017-01-02 01:56:16
【问题描述】:

我有一个 HTML5 画布,我在其上从 svg 绘制图像。

HTML

<canvas id="canvas" width="600" height="320"></canvas>

JavaScript

var DOMURL = window.URL || window.webkitURL || window;

var data = '<svg xmlns="http://www.w3.org/2000/svg" width="600" height="320">'+
                    '<foreignObject width="100%" height="100%">'+
                        '<style>'+
                             'foreignObject {'+
                                 'background-color: #000;'+
                                 'color: #fff'+
                                 'border-radius: 10px;'+
                             '}'+
                            'h1 {'+
                                'color: #2acabd;'+
                                'font: 25px arial;'+
                                'font-weight: bold;'+
                                'text-align: center;'+
                            '}'+
                            'h2 {'+
                                'margin: 0;'+
                                'color: #2acabd;'+
                                'font: 15px arial;'+
                            '}'+
                            'p {'+
                                'color: #fff;'+
                            '}'+
                        '</style>'+
                        '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size: 40px;">'+
                            '<h1>Heading</h1>'+
                            '<div>'+
                                '<div id="details-wrapper">'+
                                    '<h2>Full Name</h2>'+
                                    '<p>Alan Johnson</p>'+

                                    '<h2>Date of Birth</h2>'+
                                    '<p>7th November 1988</p>'+

                                    '<p><span id="user-id">34329483028493284093284432</span></p>'+
                                '</div>'+
                            '</div>'+
                        '</div>'+
                    '</foreignObject>'+
                '</svg>';


var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
img = new Image();
img.setAttribute("crossOrigin", "anonymous");
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);

img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
  console.log(canvas.toDataURL());
}
img.src = url;

(JS 小提琴:https://jsfiddle.net/LondonAppDev/qnpcg8th/1/

当我打电话给canvas.toDataURL() 时,我得到了异常:

(index):98 Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

我在 Stack Overflow 上看到了许多其他与此异常相关的问题和答案。我的问题不同,因为(如您所见)我在任何时候都不会在我的 svg 或画布中包含来自另一个域的任何图像。

我猜问题是我正在使用DOMURL.createObjectURL 创建一个对象 URL。

我知道在不同的浏览器中执行此操作存在一些兼容性问题,但是此应用只需要在 Chrome 中运行。另外,不能直接在画布上绘制文本,我必须通过 svg 来完成。

关于如何解决此问题并成功获取我的画布的 PNG 的任何想法?

【问题讨论】:

  • 您是否尝试过使用数据 url 而不是 createObjectURL

标签: javascript html canvas svg


【解决方案1】:

我通过将 svg 转换为数据 URL 而不是 Blob 解决了这个问题。

我删除了var url = DOMURL.createObjectURL(svg); 并将img.src = url; 替换为:

function buildSvgImageUrl(svg) {
    b64 = window.btoa(svg);
    return "data:image/svg+xml;base64," + b64;
}

img.src = buildSvgImageUrl(data);

现在它可以完美运行了。

【讨论】:

  • 我一直在寻找和寻找,最后我创造了自己的“你的解决方案”并想分享“我的想法”,所以搜索了一个问题并找到了你的答案,疯狂:)
【解决方案2】:

出于安全和用户隐私的原因。
在画布上绘制&lt;foreignObject&gt; 可能会泄露一些关于用户的信息,在此之前,chrome 团队认为他们没有足够的安全措施来防止这种情况,所以他们确实污染了画布。

这里是关于这个问题的chromium bug report

但正如 OP 发现的那样,他们有一个实现错误,忘记对 dataURI 版本设置此限制。
我确实发布了这个bug report 关于他们不会用 dataURIs 污染画布的事实。

所有这些都导致了之前限制的影响,因此在下一个版本的 chrome 中,我们应该能够在画布上绘制 &lt;foreignObject&gt; 而不会污染它,即使使用 BlobURI。

但请注意,Safari 仍然有相同的限制(没有实现错误,即 dataURI hack 在那里不起作用),并且 IE <foreignObject> 元素并在 时污染画布任何 SVG 已被绘制到它上面,并且 FF 确实删除了所有 UserAgent 和 OS 样式(这会导致与您预期的结果不同)。

真正的解决方法是不使用此hack 来绘制元素,而是使用 CanvasAPI 绘图方法绘制所有 HTML(就像 html2canvas 所做的那样)。

【讨论】:

    【解决方案3】:

    我同意接受的答案,但它对我不起作用.......这种类似的方法做到了: Tainted Canvas with canvas.toBlob

    这是代码:

    let img = new Image();
    let svg = document.getElementById('svg-node');
    let url = "data:image/svg+xml;charset=utf-8," + (new XMLSerializer()).serializeToString(svg);
    img.src = url;
    

    希望我为您节省了一些时间! :)

    【讨论】:

      猜你喜欢
      • 2020-03-25
      • 2018-02-11
      • 2018-04-09
      • 2018-10-28
      • 2017-07-12
      • 2021-02-10
      • 2014-09-14
      • 2020-06-08
      • 2021-02-28
      相关资源
      最近更新 更多