Skip to content

Instantly share code, notes, and snippets.

@endemic
Created August 8, 2016 15:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save endemic/5e56485d3fc3ae2fe2424042b9b9a4c6 to your computer and use it in GitHub Desktop.
Save endemic/5e56485d3fc3ae2fe2424042b9b9a4c6 to your computer and use it in GitHub Desktop.
Image diffing using JavaScript
const avgDiff = (canvas) => {
let context = canvas.getContext('2d');
let imageData = context.getImageData(0, 0, canvas.width, canvas.height);
let data = imageData.data;
let sum = 0;
let count = 0;
// TODO: perhaps this can be sped up by not going over every pixel?
for (let i = 0; i < data.length; i += 4) {
sum += Math.abs(128 - data[i]); // red
sum += Math.abs(128 - data[i + 1]); // green
sum += Math.abs(128 - data[i + 2]); // blue
// skipping alpha
count += 3;
}
return sum / count;
};
const invert = (canvas) => {
let context = canvas.getContext('2d');
let imageData = context.getImageData(0, 0, canvas.width, canvas.height);
let data = imageData.data;
// Invert rgb data
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // red
data[i + 1] = 255 - data[i + 1]; // green
data[i + 2] = 255 - data[i + 2]; // blue
// skipping alpha
}
// Overwrite original image
context.putImageData(imageData, 0, 0);
};
module.exports = (sources) => {
// *** Setup ***
let canvas1 = document.createElement('canvas');
let canvas2 = document.createElement('canvas');
// DEBUG
// document.body.appendChild(canvas1);
// document.body.appendChild(canvas2);
let context1 = canvas1.getContext('2d');
let context2 = canvas2.getContext('2d');
let results = [];
let promises = [];
console.time('diff');
console.info('diffing!');
for (i = 0; i < sources.length - 1; i += 1) {
let p1 = new Promise((resolve, reject) => {
var image = document.createElement('img');
image.src = sources[i];
image.onload = e => {
canvas1.width = image.width;
canvas1.height = image.height;
context1.drawImage(image, 0, 0);
resolve();
};
image.onerror = e => {
reject();
};
});
let p2 = new Promise((resolve, reject) => {
var image = document.createElement('img');
image.src = sources[i + 1];
image.onload = e => {
context2.globalAlpha = 1; // Reset alpha channel
canvas2.width = image.width;
canvas2.height = image.height;
context2.drawImage(image, 0, 0);
resolve();
};
image.onerror = e => {
reject();
};
});
let p3 = Promise.all([p1, p2]).then(() => {
// Invert 1st image
invert(canvas1);
// Layer 1st image over 2nd image
context2.globalAlpha = 0.5; // This value influences shapes/images drawn to the context
context2.drawImage(canvas1, 0, 0, canvas1.width, canvas1.height);
// Get diff from average
results.push(avgDiff(canvas2));
});
promises.push(p3);
}
return Promise.all(promises).then(() => {
console.timeEnd('diff');
console.info('end diff');
return results;
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment