Reputation: 41
I would like to compare two images. I wrote a piece of code, but the result shows that images are the same, although in fact image was changed. What I wanted achievied was, when I press 'o' key, I want to refreshing site every 5 seconds and compare image which is place in the website now with the image which was on the page when I set my interval (by pressing 'o' key). The images have the same size.
// @name Nowy123
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match http://*/*
// @grant none
// @include *.*
// ==/UserScript==
(function() {
'use strict';
// Your code here...
let intervalNum = localStorage.getItem('intervalNum');
console.log(intervalNum);
if(intervalNum){
clearInterval(intervalNum);
intervalNum = setInterval(specHero, 5000);
}
document.addEventListener("keydown", event => {
if (event.keyCode === 79) {
console.log("pressed o");
console.log("interval started");
//image
let img = document.querySelector('.contentContainer').querySelector('.heroImage');
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0 );
var refImg = context.getImageData(0, 0, img.width, img.height);
localStorage.setItem('refImg',refImg);
console.log(img);
intervalNum = setInterval(specHero, 5000);
localStorage.setItem('intervalNum', intervalNum);
}
});
document.addEventListener("keydown", event => {
if (event.keyCode === 80) {
console.log("pressed p");
console.log("interval stopped");
intervalNum = localStorage.getItem('intervalNum');
clearInterval(intervalNum);
window.localStorage.clear();
}
});
function specHero(){
let img = document.querySelector('.contentContainer').querySelector('.heroImage');
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0 );
var imgData = context.getImageData(0, 0, img.width, img.height);
let refImg = localStorage.getItem('refImg');
let result = isMatch(imgData, refImg);
console.log(result);
if(!result){
console.log("Found difference");
clearInterval(intervalNum);
return;
}
location.reload();
}
function isMatch(data1,data2){
for(var i = 0; i<data1.length; i++){
if(data1[i] != data2[i]) return false;
}
return true;
}
})();```
Upvotes: 1
Views: 264
Reputation: 31692
You might want to check what is actually stored in localStorage
. Spoiler alert: it's the string "[object ImageData]"
.
localStorage.setItem('refImg',refImg)
doesn't store the actual image data, it stores the string "[object ImageData]"
. That's because localStorage
can only store strings, and when you try to store a non-string value, that value will be converted into a string by calling toString
on it. toString
of image data objects return the string "[object ImageData]"
.
Since you are working with image data objects (typically very large objects) and you want to constantly compare them, using localStorage
(which uses the hard drive to store data) can lead to a hit in performance, besides, there isn't a straightforward way of storing the image data in localStorage
anyway. I suggest you keep the objects stored in memory by using a (semi) global variable to hold the reference image data object like so:
(function() {
'use strict';
let refImageData; // this will hold the reference image data object instead of saving it to localStorage
document.addEventListener("keydown", event => {
/* ... */
refImageData = refImg; // instead of localStorage.setItem('refImg',refImg)
/* ... */
}
function specHero() {
/* ... */
let refImg = refImageData; // instead of let refImg = localStorage.getItem('refImg'), this is redundant anyway because refImageData is already accessible from the other functions
/* ... */
}
Note: as @Kaiido pointed out in a comment bellow, image data objects don't have a length
property, they have a data
property that holds the actual pixel data, so isMatch
should be like this:
function isMatch(data1, data2) {
for(let i = 0; i < data1.data.length; i++) {
if(data1.data[i] != data2.data[i]) {
return false;
}
}
return true;
}
Edit - Saving the image data object to localStorage:
If you must save the image data object to local storage, you need to convert the data
property of the image data object (which is of type Uint8ClampedArray
) into a regular array first using Array.from
, and JSON.stringify
/JSON.parse
to convert that array into a string and back into an array. For that we use these two helper functions, one for saving and one for retrieving the data
property of the image data object:
function saveImageData(key, imageData) {
localStorage.setItem(key, JSON.stringify(Array.from(imageData.data)));
}
function loadImageData(key) {
// it's probably a good idea to check if local storage has something saved before executing the following line of code
return JSON.parse(localStorage.getItem(key));
}
And use them to save/retrieve like so:
saveImageData("refImg", refImg); // instead of localStorage.setItem('refImg',refImg)
let refImg = loadImageData("refImg"); // instead of let refImg = localStorage.getItem('refImg');
Note that this will save only the data
array of the image data object and not the image data object itself. So isMatch
should become:
function isMatch(data1, data2) {
for(let i = 0; i < data1.length; i++) {
if(data1[i] != data2[i]) {
return false;
}
}
return true;
}
When you call isMatch
you have to pass only the data
array of the image data object, like so:
isMatch(imgData.data, refImg);
// imgData is an actual image data object so we need to access its 'data' property
// refImg is the 'data' array saved to local storage, no need to access 'data' on it
Upvotes: 1