cnmesr
cnmesr

Reputation: 345

How do you compare two images in javascript correctly?

I'm using javascript in Tampermonkey (in Google Chrome) and I like to compare two images if they are identical / quite similar.

I thought I could do it by using a canvas element and compare the resulting strings, like that but no matter what images I choose, I always get that they are identical... : /

So the comparison doesn't seem to work and I have no idea why?

Edit 1: Added a timer to wait for the images to load /

/ ==UserScript==
// @name         ImageCompare
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        *://*/*
// @match        www*
// @grant        none
// ==/UserScript==

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function getBase64Image(img) {
    // Create an empty canvas element
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    // Copy the image contents to the canvas
    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    // Get the data-URL formatted image
    // Firefox supports PNG and JPEG. You could check img.src to
    // guess the original format, but be aware the using "image/jpg"
    // will re-encode the image.
    var dataURL = canvas.toDataURL("image/png");

    return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}

var x = new Image();
var y = new Image();
var url_x = "https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2010/03/google_logo.jpg";
var url_y = "https://nairobigarage.com/2017/wp-content/uploads/2015/02/6_logo_predesign.jpg";
x.src = 'chrome://favicon/' + url_x;
y.src = 'chrome://favicon/' + url_y;

var x_base64 = getBase64Image(x);
var y_base64 = getBase64Image(y);

sleep(5000).then(() => {
    if (x_base64 === y_base64)
    {
        alert("identical");
    }
    else
    {
       alert("not identical");
    }
});

Upvotes: 3

Views: 4277

Answers (1)

Patrick Evans
Patrick Evans

Reputation: 42736

You need to wait for the images to load, you can use the onload event to notify you when the image has loaded

var img = new Image();
img.onload = ()=>{
  //do work
};

So:

function getBase64Image(img) {
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    var dataURL = canvas.toDataURL("image/png");
    return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}

var x = new Image();
var y = new Image();
var url_x = "https://cdn0.tnwcdn.com/wp-content/blogs.dir/1/files/2010/03/google_logo.jpg";
var url_y = "https://nairobigarage.com/2017/wp-content/uploads/2015/02/6_logo_predesign.jpg";
x.src = 'chrome://favicon/' + url_x;
y.src = 'chrome://favicon/' + url_y;

//make the load events into promises
var xPromise = new Promise((resolve)=>{
   x.onload = resolve;
});
var yPromise = new Promise((resolve)=>{
   y.onload = resolve;
});
Promise.all([xPromise,yPromise]).then(()=>{
  var x_base64 = getBase64Image(x);
  var y_base64 = getBase64Image(y);
  if(x_base64 == y_base64){
    //match
  } else {
    //no match
  }
});

Note though you are trying to load resources from chrome:// protocol, due to security restrictions you cannot actually get the data of cross origin resources. Either load resources from the same domain that your page is running, or use file inputs to get the image.

Upvotes: 5

Related Questions