试图比较两个Canvas元素

时间:2013-05-02 12:24:09

标签: javascript google-chrome-extension html5-canvas

我使用下面的代码来比较两个画布元素

function createImage(html, can) {
     var canvas = $( "#" + can );
     var ctx = canvas[0].getContext("2d");
     var data = "<svg xmlns='http://www.w3.org/2000/svg' width='1000' height='1000'>" +
                    "<foreignObject width='100%' height='100%'>" +
                        "<div xmlns='http://www.w3.org/1999/xhtml'>" +
                            html +
                        "</div>" +
                    "</foreignObject>" +
                "</svg>";
    var DOMURL = self.URL || self.webkitURL || self;
    var img = new Image();
    img.crossOrigin = '';
    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);
    };
    img.src = url;
    //return img.src;
    return canvas[0];
}
var a1 = createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>","can1");
var a2 = createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>", "can2");
setTimeout(function() {
    var ctx1 = a1.getContext('2d');
    var imageData = ctx1.getImageData(0, 0, a1.width, a1.height);
    var pixels = imageData.data;
    var ctx2 = a2.getContext('2d');
    var imageData2 = ctx2.getImageData(0, 0, a2.width, a2.height);
    var pixels2 = imageData2.data, count;
    for(var i = 0, il = pixels.length; i < il; i++) {
        if(pixels[i] == pixels2[i]){
            count++;
        }
    }
    if(count === pixels.length && count === pixels2.length){
        alert("Match");
    }
},5000);

但它正在回复我的错误如下

  

无法从画布获取图像数据,因为画布已被跨源数据污染。

如何摆脱这个错误?

2 个答案:

答案 0 :(得分:5)

您遇到跨源错误的原因是因为<svg>使用位于http://www.w3.org/的名称空间声明,其来源不同:

var data = "<svg xmlns='http://www.w3.org/2000/svg' width='1000' height='1000'>" +
             "<foreignObject width='100%' height='100%'>" +
               "<div xmlns='http://www.w3.org/1999/xhtml'>" +
                    html +
               "</div>" +
             "</foreignObject>" +
           "</svg>";

我可以说这个方法来自Drawing DOM objects into a canvas on MDN

以这种方式重新访问数据时,

var ctx1 = a1.getContext('2d');
var imageData = ctx1.getImageData(0, 0, a1.width, a1.height);

你会遇到错误:

  

无法从画布获取图像数据,因为画布已被跨源数据污染。

您可以在Chrome上进行测试:

您只能从函数返回数据以避免出现此错误。但由于img.onload的异步性,

img.onload = function () {
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);
};

您必须推迟检索数据,强制您从函数中重新访问数据并导致错误。

因此,您应该使用另一种方法来构建画布,其中DOM对象不依赖于<svg>,如html2canvas

function createImage(html) {
    var dfd = new $.Deferred();
    var el = document.createElement("div");
        el.innerHTML = html;
        el.style.display = 'inline-block';
        document.body.appendChild(el);
    html2canvas(el, {
      onrendered: function(canvas) {
          document.body.appendChild(canvas);
          document.body.removeChild(el);
          dfd.resolve(canvas.toDataURL());
      }
    });
    return dfd;
}
$.when(
    createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>"), 
    createImage("<span style='font-size:34px'><i><b>Hello</b></i></span>")
).done(function(a1, a2){
   if (a1 === a2) {
      alert("Match"); 
   }
});

请参阅DEMO

答案 1 :(得分:1)

关于“交叉原始政策”问题

  

无法从画布获取图像数据,因为画布已被跨源数据污染。   SECURITY_ERR:DOM例外18

这是导航器“交叉原始政策”导致的安全问题。


如果您的画布“弄脏了”,则会出现此错误。这是通过将图像绘制到来自不同来源的画布来完成的。例如,如果您的画布托管在www.example.com,并且您使用的是www.wikipedia.org中的图像,那么您的画布origin-clean标志将在内部设置为false

将origin-clean标志设置为false后,您将不再被允许致电toDataURLgetImageData


从技术上讲,如果域,协议和端口匹配,图像的来源相同。


如果您在本地工作(file://),那么绘制的任何图像都会将标志设置为off。这会使调试变得烦人,但使用Chrome时,您可以使用标记--allow-file-access-from-files启动它以允许此操作。


要了解详情,请阅读文章:“Understanding the HTML5 Canvas image security rules”。

Simon Sarris

的信用

我的文件位于同一个域中,或者chrome标志已激活,我仍然收到此错误,发生了什么事?

问题是Chrome(当前)在绘制SVG文档时总是玷污画布。

有关更详细的说明,请参阅以下问题:

<强> Rasterizing an in-document SVG to Canvas

好的,使用svg似乎是个问题,那么如何解决呢?

在我写作的时候,安东尼回答了它!

See his answer