getImageData always returning 0
Asked Answered
P

2

10

I have been trying to make a script that compares two images in HTML5 and Javascript. But for some odd reason, it always returns that the images are completely the same.

And when looking at what the problem could be, I found out that every data value of every pixel returned, for some odd reason, "0".

So, any idea of what I have done wrong? :)

For some reason I feel like it's something very simple, but I just learned about the canvas element, so yeah.

This is my code:

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 + "%";
}
Pervert answered 17/4, 2011 at 16:4 Comment(0)
U
6

You are not waiting until your images have loaded and drawn before performing your comparison. Try this:

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

As shown above, you should always set your src after your onload.

Unveil answered 17/4, 2011 at 16:11 Comment(5)
Thanks for echoing my superstition about the order of assigning "src" and "onload". :-) Maybe it's not a superstition after all!Semasiology
@Semasiology No, it is not just superstition.Unveil
Fascinating, @Phrogz! I feel vindicated for all these years of telling people to do that :-)Semasiology
Do you mean that I should put the code for comparing the images where you wrote "diff them here"? Sorry that I don't completely understand it :)Pervert
@Pervert yes - This answer suggests basically the same thing as mine, only in a slightly different way. If you try this, you'll end up with the same security error problems too :-)Semasiology
S
1

I suspect that the problem is that your image data is probably not ready at the point you try to use it for the canvas. If you defer that code to the onload handlers, that will (probably) help:

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 + "%";
}

All I did was add a function wrapper around your code. That function checks the image count variable I added, and only when it's zero (i.e., only after both images have loaded) will it do the work.

(This may be superstition, but I always assign the "onload" handler before I set the "src" attribute. I have this idea that, perhaps only in the past, browsers might fail to run the handler if the image is already in the cache.)

Now another thing: you probably should just get the image data once, and then iterate over the returned data. Calling "getImageData()" for every single pixel is going to be a lot of work for the browser to do.

Semasiology answered 17/4, 2011 at 16:9 Comment(4)
Now I'm getting a "security error" on the first line where the script gets the image data... Chrome says "SECURITY_ERR: DOM exception 18" and Firefox says "Error: uncaught exception: [Exception... "Security error" code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR) ...]"Pervert
Are you fetching the images from another domain? If so, then that's a security error :-) It's considered the same sort of problem as trying to mess with an <iframe> loaded with content from another domain.Semasiology
Nope, I'm loading the images from the same folder as the HTML file. (locally, by the way)Pervert
Ah, well some/most/all modern browsers treat all local files as mutually untrustable. There's an option in some to allow access; for Chrome, for example, you can start it with the flag "--allow-file-access-from-files" (pretty sure that's it ...)Semasiology

© 2022 - 2024 — McMap. All rights reserved.