getImageData始终返回0

10

我一直在尝试使用HTML5和Javascript编写一个比较两张图片的脚本。但是,不知道为什么,它总是返回这些图片完全相同。

当我尝试查找问题时,我发现每个像素的每个数据值都返回了“0”,这很奇怪。

那么,你有什么想法是我做错了什么吗?:)

出于某种原因,我觉得这是非常简单的事情,但我刚刚学习了画布元素。

这是我的代码:

function compareImg() {
    var c1 = document.getElementById("c");
    var ctx1 = c1.getContext("2d");
    var c2 = document.getElementById("c2");
    var ctx2 = c2.getContext("2d");

    var match = 0;

    var img1 = new Image();
    img1.src = "cat.jpg";
    img1.onload = function() {
        ctx1.drawImage(img1, 0, 0);
    }
    var img2 = new Image();
    img2.src = "bird.jpg";
    img2.onload = function() {
        ctx2.drawImage(img2, 0, 0);
    }


    for(var x = 0; x<c1.width; x++) {  // For each x value
        for(var y = 0; y<c1.height; y++) { // For each y value
            var data1 = ctx1.getImageData(x, y, 1, 1);
            var data2 = ctx2.getImageData(x, y, 1, 1);
            if (data1.data[0] == data2.data[0] && data1.data[1] == data2.data[1] && data1.data[2] == data2.data[2]) {
                match++;
            }
        }
    }
    var pixels = c1.width*c1.height;
    match = match/pixels*100;
    document.getElementById("match").innerHTML = match + "%";
}
2个回答

6

在执行比较之前,您并不需要等待图像加载并绘制完成。尝试以下方法:

var img = new Image;
img.onload = function(){
  ctx1.drawImage(img,0,0);
  var img = new Image;
  img.onload = function(){
    ctx2.drawImage(img,0,0);
    // diff them here
  };
  img.src = 'cat.jpg';
};
img.src = 'cat.jpg';

如上所示,您应始终在 onload 之后设置您的 src(原文链接)

谢谢你对于“src”和“onload”顺序的赞同,这让我感到很欣慰。也许这并不是迷信! - Pointy
太棒了,@Phrogz!这些年来我一直告诉人们要这样做,现在感到被证明是正确的。 - Pointy
你的意思是我应该把比较图像的代码放在你写“diff them here”的地方吗?很抱歉我不是很理解 :) - iamarcel
@iamarcel 是的 - 这个答案基本上和我的一样,只是用了稍微不同的方式表达。如果你尝试这个方法,你也会遇到相同的安全错误问题 :-) - Pointy

1
我怀疑问题可能是在您尝试将图像数据用于画布时,该数据可能还没有准备好。如果您将该代码推迟到onload处理程序中,那么这将(很可能)有所帮助:
var img1 = new Image(), count = 2;
img1.src = "cat.jpg";
img1.onload = function() {
    ctx1.drawImage(img1, 0, 0);
    checkReadiness();
}
var img2 = new Image();
img2.src = "bird.jpg";
img2.onload = function() {
    ctx2.drawImage(img2, 0, 0);
    checkReadiness();
}

function checkReadiness() {
  if (--count !== 0) return;

  for(var x = 0; x<c1.width; x++) {  // For each x value
    for(var y = 0; y<c1.height; y++) { // For each y value
        var data1 = ctx1.getImageData(x, y, 1, 1);
        var data2 = ctx2.getImageData(x, y, 1, 1);
        if (data1.data[0] == data2.data[0] && data1.data[1] == data2.data[1] && data1.data[2] == data2.data[2]) {
            match++;
        }
    }
  }
  var pixels = c1.width*c1.height;
  match = match/pixels*100;
  document.getElementById("match").innerHTML = match + "%";
}

我所做的就是在你的代码周围添加了一个函数包装器。该函数检查我添加的图像计数变量,只有当它为零时(即仅在两个图像都加载后)才会执行工作。
(这可能是迷信,但我总是在设置“src”属性之前分配“onload”处理程序。我认为,也许只是过去,浏览器可能会在图像已经缓存的情况下无法运行处理程序。)
现在另一件事:你可能应该只获取一次图像数据,然后迭代返回的数据。对于浏览器来说,为每个像素调用“getImageData()”将是很多工作。

现在我在脚本获取图像数据的第一行遇到了“安全错误”... Chrome 显示“SECURITY_ERR: DOM exception 18”,而 Firefox 则显示“Error: uncaught exception: [Exception... "Security error" code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR) ...]" - iamarcel
1
你是从另一个域名获取图片吗?如果是,那么这是一个安全错误 :-) 这被认为是与尝试干扰加载了来自另一个域的内容的<iframe>相同类型的问题。 - Pointy
不,我是从与HTML文件相同的文件夹中加载图像。(顺便说一下,是本地加载) - iamarcel
1
啊,现代浏览器中一些/大多数/所有都将所有本地文件视为彼此不可信。在某些浏览器中有一个选项可以允许访问;例如,在Chrome中,您可以使用标志“--allow-file-access-from-files”启动它(非常确定是这样的...) - Pointy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接