123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- // js-imagediff 1.0.3
- // (c) 2011-2012 Carl Sutherland, Humble Software
- // Distributed under the MIT License
- // For original source and documentation visit:
- // http://www.github.com/HumbleSoftware/js-imagediff
- (function (name, definition) {
- var root = this;
- if (typeof module !== 'undefined') {
- try {
- var Canvas = require('canvas');
- } catch (e) {
- throw new Error(
- e.message + '\n' +
- 'Please see https://github.com/HumbleSoftware/js-imagediff#cannot-find-module-canvas\n'
- );
- }
- module.exports = definition(root, name, Canvas);
- } else if (typeof define === 'function' && typeof define.amd === 'object') {
- define(definition);
- } else {
- root[name] = definition(root, name);
- }
- })('imagediff', function (root, name, Canvas) {
- var
- TYPE_ARRAY = /\[object Array\]/i,
- TYPE_CANVAS = /\[object (Canvas|HTMLCanvasElement)\]/i,
- TYPE_CONTEXT = /\[object CanvasRenderingContext2D\]/i,
- TYPE_IMAGE = /\[object (Image|HTMLImageElement)\]/i,
- TYPE_IMAGE_DATA = /\[object ImageData\]/i,
- UNDEFINED = 'undefined',
- canvas = getCanvas(),
- context = canvas.getContext('2d'),
- previous = root[name],
- imagediff, jasmine;
- // Creation
- function getCanvas(width, height) {
- var
- canvas = Canvas ?
- new Canvas() :
- document.createElement('canvas');
- if (width) canvas.width = width;
- if (height) canvas.height = height;
- return canvas;
- }
- function getImageData(width, height) {
- canvas.width = width;
- canvas.height = height;
- context.clearRect(0, 0, width, height);
- return context.createImageData(width, height);
- }
- // Type Checking
- function isImage(object) {
- return isType(object, TYPE_IMAGE);
- }
- function isCanvas(object) {
- return isType(object, TYPE_CANVAS);
- }
- function isContext(object) {
- return isType(object, TYPE_CONTEXT);
- }
- function isImageData(object) {
- return !!(object &&
- isType(object, TYPE_IMAGE_DATA) &&
- typeof (object.width) !== UNDEFINED &&
- typeof (object.height) !== UNDEFINED &&
- typeof (object.data) !== UNDEFINED);
- }
- function isImageType(object) {
- return (
- isImage(object) ||
- isCanvas(object) ||
- isContext(object) ||
- isImageData(object)
- );
- }
- function isType(object, type) {
- return typeof (object) === 'object' && !! Object.prototype.toString.apply(object).match(type);
- }
- // Type Conversion
- function copyImageData(imageData) {
- var
- height = imageData.height,
- width = imageData.width,
- data = imageData.data,
- newImageData, newData, i;
- canvas.width = width;
- canvas.height = height;
- newImageData = context.getImageData(0, 0, width, height);
- newData = newImageData.data;
- for (i = imageData.data.length; i--;) {
- newData[i] = data[i];
- }
- return newImageData;
- }
- function toImageData(object) {
- if (isImage(object)) {
- return toImageDataFromImage(object);
- }
- if (isCanvas(object)) {
- return toImageDataFromCanvas(object);
- }
- if (isContext(object)) {
- return toImageDataFromContext(object);
- }
- if (isImageData(object)) {
- return object;
- }
- }
- function toImageDataFromImage(image) {
- var
- height = image.height,
- width = image.width;
- canvas.width = width;
- canvas.height = height;
- context.clearRect(0, 0, width, height);
- context.drawImage(image, 0, 0);
- return context.getImageData(0, 0, width, height);
- }
- function toImageDataFromCanvas(canvas) {
- var
- height = canvas.height,
- width = canvas.width,
- context = canvas.getContext('2d');
- return context.getImageData(0, 0, width, height);
- }
- function toImageDataFromContext(context) {
- var
- canvas = context.canvas,
- height = canvas.height,
- width = canvas.width;
- return context.getImageData(0, 0, width, height);
- }
- function toCanvas(object) {
- var
- data = toImageData(object),
- canvas = getCanvas(data.width, data.height),
- context = canvas.getContext('2d');
- context.putImageData(data, 0, 0);
- return canvas;
- }
- // ImageData Equality Operators
- function equalWidth(a, b) {
- return a.width === b.width;
- }
- function equalHeight(a, b) {
- return a.height === b.height;
- }
- function equalDimensions(a, b) {
- return equalHeight(a, b) && equalWidth(a, b);
- }
- function equal(a, b, tolerance) {
- var
- aData = a.data,
- bData = b.data,
- length = aData.length,
- i;
- tolerance = tolerance || 0;
- if (!equalDimensions(a, b)) return false;
- e = true;
- for (i = length; i--;)
- if (aData[i] !== bData[i] && Math.abs(aData[i] - bData[i]) > tolerance) {
- console.log(i + "|" + aData[i] + "|" + bData[i]);
- e = false;
- }
- return e;
- }
- // Diff
- function diff(a, b, options) {
- return (equalDimensions(a, b) ? diffEqual : diffUnequal)(a, b, options);
- }
- function diffEqual(a, b, options) {
- var
- height = a.height,
- width = a.width,
- c = getImageData(width, height), // c = a - b
- aData = a.data,
- bData = b.data,
- cData = c.data,
- length = cData.length,
- row, column,
- i, j, k, v;
- for (i = 0; i < length; i += 4) {
- cData[i] = Math.abs(aData[i] - bData[i]);
- cData[i + 1] = Math.abs(aData[i + 1] - bData[i + 1]);
- cData[i + 2] = Math.abs(aData[i + 2] - bData[i + 2]);
- cData[i + 3] = Math.abs(255 - Math.abs(aData[i + 3] - bData[i + 3]));
- }
- return c;
- }
- function diffUnequal(a, b, options) {
- var
- height = Math.max(a.height, b.height),
- width = Math.max(a.width, b.width),
- c = getImageData(width, height), // c = a - b
- aData = a.data,
- bData = b.data,
- cData = c.data,
- align = options && options.align,
- rowOffset,
- columnOffset,
- row, column,
- i, j, k, v;
- for (i = cData.length - 1; i > 0; i = i - 4) {
- cData[i] = 255;
- }
- // Add First Image
- offsets(a);
- for (row = a.height; row--;) {
- for (column = a.width; column--;) {
- i = 4 * ((row + rowOffset) * width + (column + columnOffset));
- j = 4 * (row * a.width + column);
- cData[i + 0] = aData[j + 0]; // r
- cData[i + 1] = aData[j + 1]; // g
- cData[i + 2] = aData[j + 2]; // b
- // cData[i+3] = aData[j+3]; // a
- }
- }
- // Subtract Second Image
- offsets(b);
- for (row = b.height; row--;) {
- for (column = b.width; column--;) {
- i = 4 * ((row + rowOffset) * width + (column + columnOffset));
- j = 4 * (row * b.width + column);
- cData[i + 0] = Math.abs(cData[i + 0] - bData[j + 0]); // r
- cData[i + 1] = Math.abs(cData[i + 1] - bData[j + 1]); // g
- cData[i + 2] = Math.abs(cData[i + 2] - bData[j + 2]); // b
- }
- }
- // Helpers
- function offsets(imageData) {
- if (align === 'top') {
- rowOffset = 0;
- columnOffset = 0;
- } else {
- rowOffset = Math.floor((height - imageData.height) / 2);
- columnOffset = Math.floor((width - imageData.width) / 2);
- }
- }
- return c;
- }
- // Validation
- function checkType() {
- var i;
- for (i = 0; i < arguments.length; i++) {
- if (!isImageType(arguments[i])) {
- throw {
- name: 'ImageTypeError',
- message: 'Submitted object was not an image.'
- };
- }
- }
- }
- // Jasmine Matchers
- function get(element, content) {
- element = document.createElement(element);
- if (element && content) {
- element.innerHTML = content;
- }
- return element;
- }
- jasmine = {
- toBeImageData: function (util, customEqualityTesters) {
- return {
- compare: function (actual) {
- return imagediff.isImageData(actual);
- }
- }
- },
- toImageDiffEqual: function (util, customEqualityTesters) {
- return {
- compare: function (actual, expected, tolerance, maxDiffCount) {
- var message;
- if (typeof (document) !== UNDEFINED) {
- message = function () {
- var
- div = get('div'),
- a = get('div', '<div>Actual:</div>'),
- b = get('div', '<div>Expected:</div>'),
- c = get('div', '<div>Diff:</div>'),
- diff = imagediff.diff(actual, expected),
- canvas = getCanvas(),
- context;
- canvas.height = diff.height;
- canvas.width = diff.width;
- div.style.overflow = 'hidden';
- a.style.float = 'left';
- b.style.float = 'left';
- c.style.float = 'left';
- context = canvas.getContext('2d');
- context.putImageData(diff, 0, 0);
- a.appendChild(toCanvas(actual));
- b.appendChild(toCanvas(expected));
- c.appendChild(canvas);
- div.appendChild(a);
- div.appendChild(b);
- div.appendChild(c);
- return div;
- };
- }
- return { pass: imagediff.equal(actual, expected, tolerance, maxDiffCount), message: message () };
- }
- }
- }
- };
- // Image Output
- function imageDataToPNG(imageData, outputFile, callback) {
- var
- canvas = toCanvas(imageData),
- base64Data,
- decodedImage;
- callback = callback || Function;
- base64Data = canvas.toDataURL().replace(/^data:image\/\w+;base64,/, "");
- decodedImage = new Buffer(base64Data, 'base64');
- require('fs').writeFile(outputFile, decodedImage, callback);
- }
- // Definition
- imagediff = {
- createCanvas: getCanvas,
- createImageData: getImageData,
- isImage: isImage,
- isCanvas: isCanvas,
- isContext: isContext,
- isImageData: isImageData,
- isImageType: isImageType,
- toImageData: function (object) {
- checkType(object);
- if (isImageData(object)) {
- return copyImageData(object);
- }
- return toImageData(object);
- },
- equal: function (a, b, tolerance) {
- checkType(a, b);
- a = toImageData(a);
- b = toImageData(b);
- return equal(a, b, tolerance);
- },
- diff: function (a, b, options) {
- checkType(a, b);
- a = toImageData(a);
- b = toImageData(b);
- return diff(a, b, options);
- },
- jasmine: jasmine,
- // Compatibility
- noConflict: function () {
- root[name] = previous;
- return imagediff;
- }
- };
- if (typeof module !== 'undefined') {
- imagediff.imageDataToPNG = imageDataToPNG;
- }
- return imagediff;
- });
|