10

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

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

但它返回给我的错误如下

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

我怎样才能摆脱这个错误?

4

2 回答 2

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

我可以说这种方法是从将DOM 对象绘制到 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"); 
   }
});

演示

于 2013-05-10T18:38:20.037 回答
1

About the "cross origin policy" problems

Unable to get image data from canvas because the canvas has been tainted by cross-origin data. SECURITY_ERR: DOM Exception 18

It's a security issue caused by the navigator "cross origin policy".


This error will appear if you have "dirtied" your canvas. This is done by drawing images to the canvas that are from a different origin. For instance, if your canvas is hosted at www.example.com, and you use images from www.wikipedia.org, then your canvas origin-clean flag is set to false internally.

Once the origin-clean flag is set to false, you are no longer allowed to call toDataURL or getImageData


Technically, images are of the same origin if domains, protocols, and ports match.


If you are working locally (file://) then any image drawn will set off the flag. This makes debugging annoying, but with Chrome you can start it with the flag --allow-file-access-from-files to allow this.


To learn more read the article: "Understanding the HTML5 Canvas image security rules".

Credits to Simon Sarris

My files are in the same domain or the chrome flag is activated and I still get this error, what's happening?

The problem is that Chrome (currently) always taints a canvas when an SVG document is drawn to it.

For a more detailed explanation see the question below:

Rasterizing an in-document SVG to Canvas

Ok, the use of svg seems to be the problem, so how to fix it?

At the time of my writing Antony answered it!

See his answer.

于 2013-05-05T17:57:00.337 回答