resemblejs
Advanced tools
Comparing version 2.10.0 to 2.10.1
@@ -1,13 +0,13 @@ | ||
var resemble = require('./resemble'); | ||
const resemble = require("./resemble"); | ||
module.exports = function(image1, image2, options) { | ||
return new Promise(function(resolve, reject) { | ||
resemble.compare(image1, image2, options, function(err, data) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(data); | ||
} | ||
module.exports = function compareImages(image1, image2, options) { | ||
return new Promise((resolve, reject) => { | ||
resemble.compare(image1, image2, options, (err, data) => { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(data); | ||
} | ||
}); | ||
}); | ||
}); | ||
}; |
{ | ||
"name": "resemblejs", | ||
"version": "2.10.0", | ||
"description": "Image analysis and comparison with HTML5", | ||
"main": "resemble.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Huddle/Resemble.js.git" | ||
}, | ||
"keywords": [ | ||
"comparison", | ||
"visual", | ||
"image", | ||
"diff", | ||
"compare", | ||
"html5" | ||
], | ||
"author": "James Cryer", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/Huddle/Resemble.js/issues" | ||
}, | ||
"homepage": "https://github.com/Huddle/Resemble.js", | ||
"scripts": { | ||
"test": "jest nodejs-tests", | ||
"test-watch": "jest --watch nodejs-tests" | ||
}, | ||
"dependencies": { | ||
"canvas-prebuilt": "^1.6.5-prerelease.1" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.4.1", | ||
"jest": "^20.0.4", | ||
"jest-cli": "^20.0.4", | ||
"color-convert": "^1.9.0" | ||
}, | ||
"jest": { | ||
"testEnvironment": "node" | ||
} | ||
"name": "resemblejs", | ||
"version": "2.10.1", | ||
"description": "Image analysis and comparison with HTML5", | ||
"main": "resemble.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/Huddle/Resemble.js.git" | ||
}, | ||
"keywords": ["comparison", "visual", "image", "diff", "compare", "html5"], | ||
"author": "James Cryer", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/Huddle/Resemble.js/issues" | ||
}, | ||
"homepage": "https://github.com/Huddle/Resemble.js", | ||
"scripts": { | ||
"test": "jest nodejs-tests", | ||
"test-watch": "jest --watch nodejs-tests", | ||
"precommit": "lint-staged", | ||
"lint": "eslint **/*.js --fix" | ||
}, | ||
"lint-staged": { | ||
"*.{js,json,css,md}": ["prettier --write", "git add"] | ||
}, | ||
"dependencies": { | ||
"canvas-prebuilt": "^1.6.5-prerelease.1" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.4.1", | ||
"color-convert": "^1.9.0", | ||
"eslint": "^4.19.1", | ||
"eslint-config-es5": "^0.5.0", | ||
"eslint-config-prettier": "^2.9.0", | ||
"eslint-plugin-import": "^2.9.0", | ||
"eslint-plugin-prettier": "^2.6.0", | ||
"husky": "^0.14.3", | ||
"jest": "^20.0.4", | ||
"jest-cli": "^20.0.4", | ||
"lint-staged": "^7.0.0", | ||
"prettier": "^1.11.1" | ||
}, | ||
"jest": { | ||
"testEnvironment": "node" | ||
} | ||
} |
@@ -1,8 +0,15 @@ | ||
[![Build Status](https://travis-ci.org/HuddleEng/Resemble.js.svg?branch=master)](https://travis-ci.org/HuddleEng/Resemble.js) | ||
<h1 align="center"><img src="https://raw.github.com/HuddleEng/Resemble.js/master/demoassets/resemble.png" alt="Resemble.js" width="256"/></h1> | ||
<img src="https://raw.github.com/HuddleEng/Resemble.js/master/demoassets/resemble.png" alt="Resemble.js" width="256"/> | ||
<p align="center"> | ||
<a href="https://travis-ci.org/HuddleEng/Resemble.js"><img alt="Build Status" src="https://travis-ci.org/HuddleEng/Resemble.js.svg?branch=master" /></a> | ||
<a href="https://app.codacy.com/app/Huddleoss/Resemble.js?utm_source=github.com&utm_medium=referral&utm_content=HuddleEng/Resemble.js&utm_campaign=badger"><img alt="Code Health" src="https://api.codacy.com/project/badge/Grade/1e0972581406417e9914bc58f57704b3" /></a> | ||
<a href="https://opensource.org/licenses/MIT"><img alt="Build Status" src="https://img.shields.io/badge/License-MIT-yellow.svg" /></a> | ||
<a href="https://www.npmjs.com/package/resemblejs"><img alt="NPM Downloads" src="https://img.shields.io/npm/dm/resemblejs.svg" /></a> | ||
</p> | ||
Analyse and compare images with Javascript and HTML5. [More info & Resemble.js Demo](http://huddleeng.github.io/Resemble.js/). Compatible with Node.js. | ||
<p align="center"> | ||
Analyse and compare images with Javascript and HTML5. <a href="http://huddleeng.github.io/Resemble.js/">More info & Resemble.js Demo</a>. Compatible with Node.js. | ||
</p> | ||
![Two image diff examples side-by-side, one pink, one yellow.](https://raw.github.com/HuddleEng/Resemble.js/master/demoassets/readmeimage.jpg "Visual image comparison") | ||
<hr /> | ||
@@ -9,0 +16,0 @@ ### Get it |
1592
resemble.js
@@ -6,30 +6,33 @@ /* | ||
(function (root, factory) { | ||
'use strict'; | ||
if (typeof define === 'function' && define.amd) { | ||
define([], factory); | ||
} else if (typeof module === 'object' && module.exports) { | ||
module.exports = factory(); | ||
} else { | ||
root.resemble = factory(); | ||
} | ||
}(this, function () { | ||
'use strict'; | ||
(function(root, factory) { | ||
"use strict"; | ||
if (typeof define === "function" && define.amd) { | ||
define([], factory); | ||
} else if (typeof module === "object" && module.exports) { | ||
module.exports = factory(); | ||
} else { | ||
root.resemble = factory(); | ||
} | ||
})(this, function() { | ||
"use strict"; | ||
var Img; | ||
var Canvas; | ||
var Img; | ||
var Canvas; | ||
if (typeof Image !== 'undefined') { | ||
if (typeof Image !== "undefined") { | ||
Img = Image; | ||
} else { | ||
Canvas = require('canvas-prebuilt'); | ||
Canvas = require("canvas-prebuilt"); // eslint-disable-line global-require | ||
Img = Canvas.Image; | ||
} | ||
var document = typeof window !== "undefined" ? window.document : { | ||
createElement: function() { | ||
// This will work as long as only createElement is used on window.document | ||
return new Canvas(); | ||
} | ||
}; | ||
var document = | ||
typeof window !== "undefined" | ||
? window.document | ||
: { | ||
createElement: function() { | ||
// This will work as long as only createElement is used on window.document | ||
return new Canvas(); | ||
} | ||
}; | ||
@@ -39,856 +42,993 @@ var oldGlobalSettings = {}; | ||
function setGlobalOutputSettings(settings) { | ||
var msg = 'warning resemble.outputSettings mutates global state, and ' + | ||
'will be removed in 3.0.0'; | ||
console.warn(msg); | ||
globalOutputSettings = settings; | ||
return this | ||
} | ||
function setGlobalOutputSettings(settings) { | ||
var msg = | ||
"warning resemble.outputSettings mutates global state, and " + | ||
"will be removed in 3.0.0"; | ||
console.warn(msg); | ||
globalOutputSettings = settings; | ||
return this; | ||
} | ||
var resemble = function( fileData ){ | ||
var pixelTransparency = 1; | ||
var resemble = function(fileData) { | ||
var pixelTransparency = 1; | ||
var errorPixelColor = { // Color for Error Pixels. Between 0 and 255. | ||
red: 255, | ||
green: 0, | ||
blue: 255, | ||
alpha: 255 | ||
}; | ||
var errorPixelColor = { | ||
// Color for Error Pixels. Between 0 and 255. | ||
red: 255, | ||
green: 0, | ||
blue: 255, | ||
alpha: 255 | ||
}; | ||
var targetPix = {r: 0, g: 0, b: 0, a: 0}; // isAntialiased | ||
var targetPix = { r: 0, g: 0, b: 0, a: 0 }; // isAntialiased | ||
function colorsDistance(c1, c2){ | ||
return (Math.abs(c1.r - c2.r) + Math.abs(c1.g - c2.g) + Math.abs(c1.b - c2.b))/3; | ||
} | ||
function colorsDistance(c1, c2) { | ||
return ( | ||
(Math.abs(c1.r - c2.r) + | ||
Math.abs(c1.g - c2.g) + | ||
Math.abs(c1.b - c2.b)) / | ||
3 | ||
); | ||
} | ||
function withinBoundingBox(x, y, width, height, box) { | ||
return x > (box.left || 0) && | ||
x < (box.right || width) && | ||
y > (box.top || 0) && | ||
y < (box.bottom || height); | ||
} | ||
function withinBoundingBox(x, y, width, height, box) { | ||
return ( | ||
x > (box.left || 0) && | ||
x < (box.right || width) && | ||
y > (box.top || 0) && | ||
y < (box.bottom || height) | ||
); | ||
} | ||
function withinComparedArea(x, y, width, height) { | ||
var isIncluded = true; | ||
function withinComparedArea(x, y, width, height) { | ||
var isIncluded = true; | ||
if (boundingBox !== undefined && !withinBoundingBox(x, y, width, height, boundingBox)) { | ||
isIncluded = false; | ||
} | ||
if ( | ||
boundingBox !== undefined && | ||
!withinBoundingBox(x, y, width, height, boundingBox) | ||
) { | ||
isIncluded = false; | ||
} | ||
if (ignoredBox !== undefined && withinBoundingBox(x, y, width, height, ignoredBox)) { | ||
isIncluded = false; | ||
} | ||
if ( | ||
ignoredBox !== undefined && | ||
withinBoundingBox(x, y, width, height, ignoredBox) | ||
) { | ||
isIncluded = false; | ||
} | ||
return isIncluded; | ||
} | ||
return isIncluded; | ||
} | ||
var errorPixelTransform = { | ||
flat: function (px, offset) { | ||
px[offset] = errorPixelColor.red; | ||
px[offset + 1] = errorPixelColor.green; | ||
px[offset + 2] = errorPixelColor.blue; | ||
px[offset + 3] = errorPixelColor.alpha; | ||
}, | ||
movement: function (px, offset, d1, d2) { | ||
px[offset] = ((d2.r * (errorPixelColor.red / 255)) + errorPixelColor.red) / 2; | ||
px[offset + 1] = ((d2.g * (errorPixelColor.green / 255)) + errorPixelColor.green) / 2; | ||
px[offset + 2] = ((d2.b * (errorPixelColor.blue / 255)) + errorPixelColor.blue) / 2; | ||
px[offset + 3] = d2.a; | ||
}, | ||
flatDifferenceIntensity: function (px, offset, d1, d2) { | ||
px[offset] = errorPixelColor.red; | ||
px[offset + 1] = errorPixelColor.green; | ||
px[offset + 2] = errorPixelColor.blue; | ||
px[offset + 3] = colorsDistance(d1, d2); | ||
}, | ||
movementDifferenceIntensity: function (px, offset, d1, d2) { | ||
var ratio = colorsDistance(d1, d2) / 255 * 0.8; | ||
var errorPixelTransform = { | ||
flat: function(px, offset) { | ||
px[offset] = errorPixelColor.red; | ||
px[offset + 1] = errorPixelColor.green; | ||
px[offset + 2] = errorPixelColor.blue; | ||
px[offset + 3] = errorPixelColor.alpha; | ||
}, | ||
movement: function(px, offset, d1, d2) { | ||
px[offset] = | ||
(d2.r * (errorPixelColor.red / 255) + errorPixelColor.red) / | ||
2; | ||
px[offset + 1] = | ||
(d2.g * (errorPixelColor.green / 255) + | ||
errorPixelColor.green) / | ||
2; | ||
px[offset + 2] = | ||
(d2.b * (errorPixelColor.blue / 255) + | ||
errorPixelColor.blue) / | ||
2; | ||
px[offset + 3] = d2.a; | ||
}, | ||
flatDifferenceIntensity: function(px, offset, d1, d2) { | ||
px[offset] = errorPixelColor.red; | ||
px[offset + 1] = errorPixelColor.green; | ||
px[offset + 2] = errorPixelColor.blue; | ||
px[offset + 3] = colorsDistance(d1, d2); | ||
}, | ||
movementDifferenceIntensity: function(px, offset, d1, d2) { | ||
var ratio = colorsDistance(d1, d2) / 255 * 0.8; | ||
px[offset] = ((1 - ratio) * (d2.r * (errorPixelColor.red / 255)) + ratio * errorPixelColor.red); | ||
px[offset + 1] = ((1 - ratio) * (d2.g * (errorPixelColor.green / 255)) + ratio * errorPixelColor.green); | ||
px[offset + 2] = ((1 - ratio) * (d2.b * (errorPixelColor.blue / 255)) + ratio * errorPixelColor.blue); | ||
px[offset + 3] = d2.a; | ||
}, | ||
diffOnly: function (px, offset, d1, d2) { | ||
px[offset] = d2.r; | ||
px[offset + 1] = d2.g; | ||
px[offset + 2] = d2.b; | ||
px[offset + 3] = d2.a; | ||
} | ||
}; | ||
px[offset] = | ||
(1 - ratio) * (d2.r * (errorPixelColor.red / 255)) + | ||
ratio * errorPixelColor.red; | ||
px[offset + 1] = | ||
(1 - ratio) * (d2.g * (errorPixelColor.green / 255)) + | ||
ratio * errorPixelColor.green; | ||
px[offset + 2] = | ||
(1 - ratio) * (d2.b * (errorPixelColor.blue / 255)) + | ||
ratio * errorPixelColor.blue; | ||
px[offset + 3] = d2.a; | ||
}, | ||
diffOnly: function(px, offset, d1, d2) { | ||
px[offset] = d2.r; | ||
px[offset + 1] = d2.g; | ||
px[offset + 2] = d2.b; | ||
px[offset + 3] = d2.a; | ||
} | ||
}; | ||
var errorPixel = errorPixelTransform.flat; | ||
var errorType; | ||
var boundingBox; | ||
var ignoredBox; | ||
var largeImageThreshold = 1200; | ||
var useCrossOrigin = true; | ||
var data = {}; | ||
var images = []; | ||
var updateCallbackArray = []; | ||
var errorPixel = errorPixelTransform.flat; | ||
var errorType; | ||
var boundingBox; | ||
var ignoredBox; | ||
var largeImageThreshold = 1200; | ||
var useCrossOrigin = true; | ||
var data = {}; | ||
var images = []; | ||
var updateCallbackArray = []; | ||
var tolerance = { // between 0 and 255 | ||
red: 16, | ||
green: 16, | ||
blue: 16, | ||
alpha: 16, | ||
minBrightness: 16, | ||
maxBrightness: 240 | ||
}; | ||
var tolerance = { | ||
// between 0 and 255 | ||
red: 16, | ||
green: 16, | ||
blue: 16, | ||
alpha: 16, | ||
minBrightness: 16, | ||
maxBrightness: 240 | ||
}; | ||
var ignoreAntialiasing = false; | ||
var ignoreColors = false; | ||
var scaleToSameSize = false; | ||
var ignoreAntialiasing = false; | ||
var ignoreColors = false; | ||
var scaleToSameSize = false; | ||
function triggerDataUpdate(){ | ||
var len = updateCallbackArray.length; | ||
var i; | ||
for(i=0;i<len;i++){ | ||
if (typeof updateCallbackArray[i] === 'function'){ | ||
updateCallbackArray[i](data); | ||
} | ||
} | ||
} | ||
function triggerDataUpdate() { | ||
var len = updateCallbackArray.length; | ||
var i; | ||
for (i = 0; i < len; i++) { | ||
if (typeof updateCallbackArray[i] === "function") { | ||
updateCallbackArray[i](data); | ||
} | ||
} | ||
} | ||
function loop(w, h, callback){ | ||
var x,y; | ||
function loop(w, h, callback) { | ||
var x; | ||
var y; | ||
for (x=0;x<w;x++){ | ||
for (y=0;y<h;y++){ | ||
callback(x, y); | ||
} | ||
} | ||
} | ||
for (x = 0; x < w; x++) { | ||
for (y = 0; y < h; y++) { | ||
callback(x, y); | ||
} | ||
} | ||
} | ||
function parseImage(sourceImageData, width, height){ | ||
function parseImage(sourceImageData, width, height) { | ||
var pixelCount = 0; | ||
var redTotal = 0; | ||
var greenTotal = 0; | ||
var blueTotal = 0; | ||
var alphaTotal = 0; | ||
var brightnessTotal = 0; | ||
var whiteTotal = 0; | ||
var blackTotal = 0; | ||
var pixelCount = 0; | ||
var redTotal = 0; | ||
var greenTotal = 0; | ||
var blueTotal = 0; | ||
var alphaTotal = 0; | ||
var brightnessTotal = 0; | ||
var whiteTotal = 0; | ||
var blackTotal = 0; | ||
loop(width, height, function(horizontalPos, verticalPos) { | ||
var offset = (verticalPos * width + horizontalPos) * 4; | ||
var red = sourceImageData[offset]; | ||
var green = sourceImageData[offset + 1]; | ||
var blue = sourceImageData[offset + 2]; | ||
var alpha = sourceImageData[offset + 3]; | ||
var brightness = getBrightness(red, green, blue); | ||
loop(width, height, function(horizontalPos, verticalPos){ | ||
var offset = (verticalPos*width + horizontalPos) * 4; | ||
var red = sourceImageData[offset]; | ||
var green = sourceImageData[offset + 1]; | ||
var blue = sourceImageData[offset + 2]; | ||
var alpha = sourceImageData[offset + 3]; | ||
var brightness = getBrightness(red,green,blue); | ||
if (red === green && red === blue && alpha) { | ||
if (red === 0) { | ||
blackTotal++; | ||
} else if (red === 255) { | ||
whiteTotal++; | ||
} | ||
} | ||
if (red == green && red == blue && alpha) { | ||
if (red == 0) { | ||
blackTotal++ | ||
} else if (red == 255) { | ||
whiteTotal++ | ||
} | ||
} | ||
pixelCount++; | ||
pixelCount++; | ||
redTotal += red / 255 * 100; | ||
greenTotal += green / 255 * 100; | ||
blueTotal += blue / 255 * 100; | ||
alphaTotal += (255 - alpha) / 255 * 100; | ||
brightnessTotal += brightness / 255 * 100; | ||
}); | ||
redTotal += red / 255 * 100; | ||
greenTotal += green / 255 * 100; | ||
blueTotal += blue / 255 * 100; | ||
alphaTotal += (255 - alpha) / 255 * 100; | ||
brightnessTotal += brightness / 255 * 100; | ||
}); | ||
data.red = Math.floor(redTotal / pixelCount); | ||
data.green = Math.floor(greenTotal / pixelCount); | ||
data.blue = Math.floor(blueTotal / pixelCount); | ||
data.alpha = Math.floor(alphaTotal / pixelCount); | ||
data.brightness = Math.floor(brightnessTotal / pixelCount); | ||
data.white = Math.floor(whiteTotal / pixelCount * 100); | ||
data.black = Math.floor(blackTotal / pixelCount * 100); | ||
data.red = Math.floor(redTotal / pixelCount); | ||
data.green = Math.floor(greenTotal / pixelCount); | ||
data.blue = Math.floor(blueTotal / pixelCount); | ||
data.alpha = Math.floor(alphaTotal / pixelCount); | ||
data.brightness = Math.floor(brightnessTotal / pixelCount); | ||
data.white = Math.floor(whiteTotal / pixelCount * 100); | ||
data.black = Math.floor(blackTotal / pixelCount * 100); | ||
triggerDataUpdate(); | ||
} | ||
triggerDataUpdate(); | ||
} | ||
function loadImageData(fileDataForImage, callback) { | ||
var fileReader; | ||
var hiddenImage = new Img(); | ||
function loadImageData( fileData, callback ){ | ||
var fileReader; | ||
var hiddenImage = new Img(); | ||
if (!hiddenImage.setAttribute) { | ||
hiddenImage.setAttribute = function setAttribute() {}; | ||
} | ||
if (!hiddenImage.setAttribute) { | ||
hiddenImage.setAttribute = function setAttribute() { }; | ||
} | ||
if (useCrossOrigin) { | ||
hiddenImage.setAttribute("crossorigin", "anonymous"); | ||
} | ||
if(useCrossOrigin) { | ||
hiddenImage.setAttribute('crossorigin', 'anonymous'); | ||
} | ||
hiddenImage.onerror = function (err) { | ||
hiddenImage.onerror = function(err) { | ||
hiddenImage.onload = null; | ||
hiddenImage.onerror = null; //fixes pollution between calls | ||
images.push({ error : err ? err + "" : "Image load error." }); | ||
callback(); | ||
}; | ||
hiddenImage.onerror = null; // fixes pollution between calls | ||
images.push({ error: err ? err + "" : "Image load error." }); | ||
callback(); | ||
}; | ||
hiddenImage.onload = function() { | ||
hiddenImage.onload = null; //fixes pollution between calls | ||
hiddenImage.onload = function() { | ||
hiddenImage.onload = null; // fixes pollution between calls | ||
hiddenImage.onerror = null; | ||
var hiddenCanvas = document.createElement('canvas'); | ||
var imageData; | ||
var hiddenCanvas = document.createElement("canvas"); | ||
var imageData; | ||
// don't assign to hiddenImage, see https://github.com/Huddle/Resemble.js/pull/87/commits/300d43352a2845aad289b254bfbdc7cd6a37e2d7 | ||
var width = hiddenImage.width; | ||
var height = hiddenImage.height; | ||
// don't assign to hiddenImage, see https://github.com/Huddle/Resemble.js/pull/87/commits/300d43352a2845aad289b254bfbdc7cd6a37e2d7 | ||
var width = hiddenImage.width; | ||
var height = hiddenImage.height; | ||
if( scaleToSameSize && images.length == 1 ){ | ||
width = images[0].width; | ||
height = images[0].height; | ||
} | ||
if (scaleToSameSize && images.length === 1) { | ||
width = images[0].width; | ||
height = images[0].height; | ||
} | ||
hiddenCanvas.width = width; | ||
hiddenCanvas.height = height; | ||
hiddenCanvas.width = width; | ||
hiddenCanvas.height = height; | ||
hiddenCanvas.getContext('2d').drawImage(hiddenImage, 0, 0, width, height); | ||
imageData = hiddenCanvas.getContext('2d').getImageData(0, 0, width, height); | ||
hiddenCanvas | ||
.getContext("2d") | ||
.drawImage(hiddenImage, 0, 0, width, height); | ||
imageData = hiddenCanvas | ||
.getContext("2d") | ||
.getImageData(0, 0, width, height); | ||
images.push(imageData); | ||
images.push(imageData); | ||
callback(imageData, width, height); | ||
}; | ||
callback(imageData, width, height); | ||
}; | ||
if (typeof fileData === 'string') { | ||
hiddenImage.src = fileData; | ||
if (hiddenImage.complete && hiddenImage.naturalWidth > 0) { | ||
hiddenImage.onload(); | ||
} | ||
} else if (typeof fileData.data !== 'undefined' | ||
&& typeof fileData.width === 'number' | ||
&& typeof fileData.height === 'number') { | ||
if (typeof fileDataForImage === "string") { | ||
hiddenImage.src = fileDataForImage; | ||
if (hiddenImage.complete && hiddenImage.naturalWidth > 0) { | ||
hiddenImage.onload(); | ||
} | ||
} else if ( | ||
typeof fileDataForImage.data !== "undefined" && | ||
typeof fileDataForImage.width === "number" && | ||
typeof fileDataForImage.height === "number" | ||
) { | ||
images.push(fileDataForImage); | ||
images.push(fileData); | ||
callback( | ||
fileDataForImage, | ||
fileDataForImage.width, | ||
fileDataForImage.height | ||
); | ||
} else if ( | ||
typeof Buffer !== "undefined" && | ||
fileDataForImage instanceof Buffer | ||
) { | ||
// If we have Buffer, assume we're on Node+Canvas and its supported | ||
hiddenImage.src = fileDataForImage; | ||
} else { | ||
fileReader = new FileReader(); | ||
fileReader.onload = function(event) { | ||
hiddenImage.src = event.target.result; | ||
}; | ||
fileReader.readAsDataURL(fileDataForImage); | ||
} | ||
} | ||
callback(fileData, fileData.width, fileData.height); | ||
} else if (typeof Buffer !== 'undefined' && fileData instanceof Buffer){ | ||
// If we have Buffer, assume we're on Node+Canvas and its supported | ||
hiddenImage.src = fileData; | ||
} else { | ||
fileReader = new FileReader(); | ||
fileReader.onload = function (event) { | ||
hiddenImage.src = event.target.result; | ||
}; | ||
fileReader.readAsDataURL(fileData); | ||
} | ||
} | ||
function isColorSimilar(a, b, color) { | ||
var absDiff = Math.abs(a - b); | ||
function isColorSimilar(a, b, color){ | ||
if (typeof a === "undefined") { | ||
return false; | ||
} | ||
if (typeof b === "undefined") { | ||
return false; | ||
} | ||
var absDiff = Math.abs(a - b); | ||
if (a === b) { | ||
return true; | ||
} else if (absDiff < tolerance[color]) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
if(typeof a === 'undefined'){ | ||
return false; | ||
} | ||
if(typeof b === 'undefined'){ | ||
return false; | ||
} | ||
function isPixelBrightnessSimilar(d1, d2) { | ||
var alpha = isColorSimilar(d1.a, d2.a, "alpha"); | ||
var brightness = isColorSimilar( | ||
d1.brightness, | ||
d2.brightness, | ||
"minBrightness" | ||
); | ||
return brightness && alpha; | ||
} | ||
if(a === b){ | ||
return true; | ||
} else if ( absDiff < tolerance[color] ) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
function getBrightness(r, g, b) { | ||
return 0.3 * r + 0.59 * g + 0.11 * b; | ||
} | ||
function isPixelBrightnessSimilar(d1, d2){ | ||
var alpha = isColorSimilar(d1.a, d2.a, 'alpha'); | ||
var brightness = isColorSimilar(d1.brightness, d2.brightness, 'minBrightness'); | ||
return brightness && alpha; | ||
} | ||
function isRGBSame(d1, d2) { | ||
var red = d1.r === d2.r; | ||
var green = d1.g === d2.g; | ||
var blue = d1.b === d2.b; | ||
return red && green && blue; | ||
} | ||
function getBrightness(r,g,b){ | ||
return 0.3*r + 0.59*g + 0.11*b; | ||
} | ||
function isRGBSimilar(d1, d2) { | ||
var red = isColorSimilar(d1.r, d2.r, "red"); | ||
var green = isColorSimilar(d1.g, d2.g, "green"); | ||
var blue = isColorSimilar(d1.b, d2.b, "blue"); | ||
var alpha = isColorSimilar(d1.a, d2.a, "alpha"); | ||
function isRGBSame(d1,d2){ | ||
var red = d1.r === d2.r; | ||
var green = d1.g === d2.g; | ||
var blue = d1.b === d2.b; | ||
return red && green && blue; | ||
} | ||
return red && green && blue && alpha; | ||
} | ||
function isRGBSimilar(d1, d2){ | ||
var red = isColorSimilar(d1.r,d2.r,'red'); | ||
var green = isColorSimilar(d1.g,d2.g,'green'); | ||
var blue = isColorSimilar(d1.b,d2.b,'blue'); | ||
var alpha = isColorSimilar(d1.a, d2.a, 'alpha'); | ||
function isContrasting(d1, d2) { | ||
return ( | ||
Math.abs(d1.brightness - d2.brightness) > | ||
tolerance.maxBrightness | ||
); | ||
} | ||
return red && green && blue && alpha; | ||
} | ||
function getHue(red, green, blue) { | ||
var r = red / 255; | ||
var g = green / 255; | ||
var b = blue / 255; | ||
var max = Math.max(r, g, b); | ||
var min = Math.min(r, g, b); | ||
var h; | ||
var d; | ||
function isContrasting(d1, d2){ | ||
return Math.abs(d1.brightness - d2.brightness) > tolerance.maxBrightness; | ||
} | ||
if (max === min) { | ||
h = 0; // achromatic | ||
} else { | ||
d = max - min; | ||
switch (max) { | ||
case r: | ||
h = (g - b) / d + (g < b ? 6 : 0); | ||
break; | ||
case g: | ||
h = (b - r) / d + 2; | ||
break; | ||
case b: | ||
h = (r - g) / d + 4; | ||
break; | ||
default: | ||
h /= 6; | ||
} | ||
} | ||
function getHue(r,g,b){ | ||
return h; | ||
} | ||
r = r / 255; | ||
g = g / 255; | ||
b = b / 255; | ||
var max = Math.max(r, g, b), min = Math.min(r, g, b); | ||
var h; | ||
var d; | ||
function isAntialiased( | ||
sourcePix, | ||
pix, | ||
cacheSet, | ||
verticalPos, | ||
horizontalPos, | ||
width | ||
) { | ||
var offset; | ||
var distance = 1; | ||
var i; | ||
var j; | ||
var hasHighContrastSibling = 0; | ||
var hasSiblingWithDifferentHue = 0; | ||
var hasEquivalentSibling = 0; | ||
if (max == min){ | ||
h = 0; // achromatic | ||
} else{ | ||
d = max - min; | ||
switch(max){ | ||
case r: h = (g - b) / d + (g < b ? 6 : 0); break; | ||
case g: h = (b - r) / d + 2; break; | ||
case b: h = (r - g) / d + 4; break; | ||
} | ||
h /= 6; | ||
} | ||
addHueInfo(sourcePix); | ||
return h; | ||
} | ||
for (i = distance * -1; i <= distance; i++) { | ||
for (j = distance * -1; j <= distance; j++) { | ||
if (i === 0 && j === 0) { | ||
// ignore source pixel | ||
} else { | ||
offset = | ||
((verticalPos + j) * width + (horizontalPos + i)) * | ||
4; | ||
function isAntialiased(sourcePix, data, cacheSet, verticalPos, horizontalPos, width){ | ||
var offset; | ||
var distance = 1; | ||
var i; | ||
var j; | ||
var hasHighContrastSibling = 0; | ||
var hasSiblingWithDifferentHue = 0; | ||
var hasEquivalentSibling = 0; | ||
if (!getPixelInfo(targetPix, pix, offset, cacheSet)) { | ||
continue; | ||
} | ||
addHueInfo(sourcePix); | ||
addBrightnessInfo(targetPix); | ||
addHueInfo(targetPix); | ||
for (i = distance*-1; i <= distance; i++){ | ||
for (j = distance*-1; j <= distance; j++){ | ||
if (isContrasting(sourcePix, targetPix)) { | ||
hasHighContrastSibling++; | ||
} | ||
if(i===0 && j===0){ | ||
// ignore source pixel | ||
} else { | ||
if (isRGBSame(sourcePix, targetPix)) { | ||
hasEquivalentSibling++; | ||
} | ||
offset = ((verticalPos+j)*width + (horizontalPos+i)) * 4; | ||
if (Math.abs(targetPix.h - sourcePix.h) > 0.3) { | ||
hasSiblingWithDifferentHue++; | ||
} | ||
if(!getPixelInfo(targetPix , data, offset, cacheSet)){ | ||
continue; | ||
} | ||
if ( | ||
hasSiblingWithDifferentHue > 1 || | ||
hasHighContrastSibling > 1 | ||
) { | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
addBrightnessInfo(targetPix); | ||
addHueInfo(targetPix); | ||
if (hasEquivalentSibling < 2) { | ||
return true; | ||
} | ||
if( isContrasting(sourcePix, targetPix) ){ | ||
hasHighContrastSibling++; | ||
} | ||
return false; | ||
} | ||
if( isRGBSame(sourcePix,targetPix) ){ | ||
hasEquivalentSibling++; | ||
} | ||
function copyPixel(px, offset, pix) { | ||
if (errorType === "diffOnly") { | ||
return; | ||
} | ||
if( Math.abs(targetPix.h - sourcePix.h) > 0.3 ){ | ||
hasSiblingWithDifferentHue++; | ||
} | ||
px[offset] = pix.r; // r | ||
px[offset + 1] = pix.g; // g | ||
px[offset + 2] = pix.b; // b | ||
px[offset + 3] = pix.a * pixelTransparency; // a | ||
} | ||
if( hasSiblingWithDifferentHue > 1 || hasHighContrastSibling > 1){ | ||
return true; | ||
} | ||
} | ||
} | ||
} | ||
function copyGrayScalePixel(px, offset, pix) { | ||
if (errorType === "diffOnly") { | ||
return; | ||
} | ||
if(hasEquivalentSibling < 2){ | ||
return true; | ||
} | ||
px[offset] = pix.brightness; // r | ||
px[offset + 1] = pix.brightness; // g | ||
px[offset + 2] = pix.brightness; // b | ||
px[offset + 3] = pix.a * pixelTransparency; // a | ||
} | ||
return false; | ||
} | ||
function getPixelInfo(dst, pix, offset) { | ||
if (pix.length > offset) { | ||
dst.r = pix[offset]; | ||
dst.g = pix[offset + 1]; | ||
dst.b = pix[offset + 2]; | ||
dst.a = pix[offset + 3]; | ||
function copyPixel(px, offset, data){ | ||
if (errorType === 'diffOnly') { | ||
return; | ||
} | ||
return true; | ||
} | ||
px[offset] = data.r; //r | ||
px[offset + 1] = data.g; //g | ||
px[offset + 2] = data.b; //b | ||
px[offset + 3] = data.a * pixelTransparency; //a | ||
} | ||
return false; | ||
} | ||
function copyGrayScalePixel(px, offset, data){ | ||
if (errorType === 'diffOnly') { | ||
return; | ||
} | ||
function addBrightnessInfo(pix) { | ||
pix.brightness = getBrightness(pix.r, pix.g, pix.b); // 'corrected' lightness | ||
} | ||
px[offset] = data.brightness; //r | ||
px[offset + 1] = data.brightness; //g | ||
px[offset + 2] = data.brightness; //b | ||
px[offset + 3] = data.a * pixelTransparency; //a | ||
} | ||
function addHueInfo(pix) { | ||
pix.h = getHue(pix.r, pix.g, pix.b); | ||
} | ||
function getPixelInfo(dst, data, offset) { | ||
if (data.length > offset) { | ||
dst.r = data[offset]; | ||
dst.g = data[offset + 1]; | ||
dst.b = data[offset + 2]; | ||
dst.a = data[offset + 3]; | ||
function analyseImages(img1, img2, width, height) { | ||
var hiddenCanvas = document.createElement("canvas"); | ||
return true; | ||
} | ||
var data1 = img1.data; | ||
var data2 = img2.data; | ||
return false; | ||
} | ||
hiddenCanvas.width = width; | ||
hiddenCanvas.height = height; | ||
function addBrightnessInfo(data){ | ||
data.brightness = getBrightness(data.r,data.g,data.b); // 'corrected' lightness | ||
} | ||
var context = hiddenCanvas.getContext("2d"); | ||
var imgd = context.createImageData(width, height); | ||
var pix = imgd.data; | ||
function addHueInfo(data){ | ||
data.h = getHue(data.r,data.g,data.b); | ||
} | ||
var mismatchCount = 0; | ||
var diffBounds = { | ||
top: height, | ||
left: width, | ||
bottom: 0, | ||
right: 0 | ||
}; | ||
var updateBounds = function(x, y) { | ||
diffBounds.left = Math.min(x, diffBounds.left); | ||
diffBounds.right = Math.max(x, diffBounds.right); | ||
diffBounds.top = Math.min(y, diffBounds.top); | ||
diffBounds.bottom = Math.max(y, diffBounds.bottom); | ||
}; | ||
function analyseImages(img1, img2, width, height){ | ||
var time = Date.now(); | ||
var hiddenCanvas = document.createElement('canvas'); | ||
var skip; | ||
var data1 = img1.data; | ||
var data2 = img2.data; | ||
if ( | ||
!!largeImageThreshold && | ||
ignoreAntialiasing && | ||
(width > largeImageThreshold || height > largeImageThreshold) | ||
) { | ||
skip = 6; | ||
} | ||
hiddenCanvas.width = width; | ||
hiddenCanvas.height = height; | ||
var pixel1 = { r: 0, g: 0, b: 0, a: 0 }; | ||
var pixel2 = { r: 0, g: 0, b: 0, a: 0 }; | ||
var context = hiddenCanvas.getContext('2d'); | ||
var imgd = context.createImageData(width,height); | ||
var targetPix = imgd.data; | ||
loop(width, height, function(horizontalPos, verticalPos) { | ||
if (skip) { | ||
// only skip if the image isn't small | ||
if ( | ||
verticalPos % skip === 0 || | ||
horizontalPos % skip === 0 | ||
) { | ||
return; | ||
} | ||
} | ||
var mismatchCount = 0; | ||
var diffBounds = { | ||
top: height, | ||
left: width, | ||
bottom: 0, | ||
right: 0 | ||
}; | ||
var updateBounds = function(x, y) { | ||
diffBounds.left = Math.min(x, diffBounds.left); | ||
diffBounds.right = Math.max(x, diffBounds.right); | ||
diffBounds.top = Math.min(y, diffBounds.top); | ||
diffBounds.bottom = Math.max(y, diffBounds.bottom); | ||
}; | ||
var offset = (verticalPos * width + horizontalPos) * 4; | ||
var isWithinComparedArea = withinComparedArea( | ||
horizontalPos, | ||
verticalPos, | ||
width, | ||
height | ||
); | ||
var time = Date.now(); | ||
if ( | ||
!getPixelInfo(pixel1, data1, offset, 1) || | ||
!getPixelInfo(pixel2, data2, offset, 2) | ||
) { | ||
return; | ||
} | ||
var skip; | ||
if (ignoreColors) { | ||
addBrightnessInfo(pixel1); | ||
addBrightnessInfo(pixel2); | ||
if(!!largeImageThreshold && ignoreAntialiasing && (width > largeImageThreshold || height > largeImageThreshold)){ | ||
skip = 6; | ||
} | ||
if ( | ||
isPixelBrightnessSimilar(pixel1, pixel2) || | ||
!isWithinComparedArea | ||
) { | ||
copyGrayScalePixel(pix, offset, pixel2); | ||
} else { | ||
errorPixel(pix, offset, pixel1, pixel2); | ||
mismatchCount++; | ||
updateBounds(horizontalPos, verticalPos); | ||
} | ||
return; | ||
} | ||
var pixel1 = {r: 0, g: 0, b: 0, a: 0}; | ||
var pixel2 = { r: 0, g: 0, b: 0, a: 0 }; | ||
if (isRGBSimilar(pixel1, pixel2) || !isWithinComparedArea) { | ||
copyPixel(pix, offset, pixel1); | ||
} else if ( | ||
ignoreAntialiasing && | ||
(addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry. | ||
addBrightnessInfo(pixel2), | ||
isAntialiased( | ||
pixel1, | ||
data1, | ||
1, | ||
verticalPos, | ||
horizontalPos, | ||
width | ||
) || | ||
isAntialiased( | ||
pixel2, | ||
data2, | ||
2, | ||
verticalPos, | ||
horizontalPos, | ||
width | ||
)) | ||
) { | ||
if ( | ||
isPixelBrightnessSimilar(pixel1, pixel2) || | ||
!isWithinComparedArea | ||
) { | ||
copyGrayScalePixel(pix, offset, pixel2); | ||
} else { | ||
errorPixel(pix, offset, pixel1, pixel2); | ||
mismatchCount++; | ||
updateBounds(horizontalPos, verticalPos); | ||
} | ||
} else { | ||
errorPixel(pix, offset, pixel1, pixel2); | ||
mismatchCount++; | ||
updateBounds(horizontalPos, verticalPos); | ||
} | ||
}); | ||
loop(width, height, function(horizontalPos, verticalPos){ | ||
data.rawMisMatchPercentage = mismatchCount / (height * width) * 100; | ||
data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2); | ||
data.diffBounds = diffBounds; | ||
data.analysisTime = Date.now() - time; | ||
if(skip){ // only skip if the image isn't small | ||
if(verticalPos % skip === 0 || horizontalPos % skip === 0){ | ||
return; | ||
} | ||
} | ||
data.getImageDataUrl = function(text) { | ||
var barHeight = 0; | ||
var offset = (verticalPos*width + horizontalPos) * 4; | ||
var isWithinComparedArea = withinComparedArea(horizontalPos, verticalPos, width, height); | ||
if (text) { | ||
barHeight = addLabel(text, context, hiddenCanvas); | ||
} | ||
if (!getPixelInfo(pixel1, data1, offset, 1) || !getPixelInfo(pixel2, data2, offset, 2)) { | ||
return; | ||
} | ||
context.putImageData(imgd, 0, barHeight); | ||
if (ignoreColors){ | ||
return hiddenCanvas.toDataURL("image/png"); | ||
}; | ||
addBrightnessInfo(pixel1); | ||
addBrightnessInfo(pixel2); | ||
if (hiddenCanvas.toBuffer) { | ||
data.getBuffer = function(includeOriginal) { | ||
if (includeOriginal) { | ||
var imageWidth = hiddenCanvas.width + 2; | ||
hiddenCanvas.width = imageWidth * 3; | ||
context.putImageData(img1, 0, 0); | ||
context.putImageData(img2, imageWidth, 0); | ||
context.putImageData(imgd, imageWidth * 2, 0); | ||
} else { | ||
context.putImageData(imgd, 0, 0); | ||
} | ||
return hiddenCanvas.toBuffer(); | ||
}; | ||
} | ||
} | ||
if( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea ){ | ||
copyGrayScalePixel(targetPix, offset, pixel2); | ||
} else { | ||
errorPixel(targetPix, offset, pixel1, pixel2); | ||
mismatchCount++; | ||
updateBounds(horizontalPos, verticalPos); | ||
} | ||
return; | ||
} | ||
function addLabel(text, context, hiddenCanvas) { | ||
var textPadding = 2; | ||
if( isRGBSimilar(pixel1, pixel2) || !isWithinComparedArea ){ | ||
copyPixel(targetPix, offset, pixel1); | ||
context.font = "12px sans-serif"; | ||
} else if( ignoreAntialiasing && ( | ||
addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry. | ||
addBrightnessInfo(pixel2), | ||
isAntialiased(pixel1, data1, 1, verticalPos, horizontalPos, width) || | ||
isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width) | ||
)){ | ||
var textWidth = context.measureText(text).width + textPadding * 2; | ||
var barHeight = 22; | ||
if( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea ){ | ||
copyGrayScalePixel(targetPix, offset, pixel2); | ||
} else { | ||
errorPixel(targetPix, offset, pixel1, pixel2); | ||
mismatchCount++; | ||
updateBounds(horizontalPos, verticalPos); | ||
} | ||
} else { | ||
errorPixel(targetPix, offset, pixel1, pixel2); | ||
mismatchCount++; | ||
updateBounds(horizontalPos, verticalPos); | ||
} | ||
if (textWidth > hiddenCanvas.width) { | ||
hiddenCanvas.width = textWidth; | ||
} | ||
}); | ||
hiddenCanvas.height += barHeight; | ||
data.rawMisMatchPercentage = (mismatchCount / (height*width) * 100); | ||
data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2); | ||
data.diffBounds = diffBounds; | ||
data.analysisTime = Date.now() - time; | ||
context.fillStyle = "#666"; | ||
context.fillRect(0, 0, hiddenCanvas.width, barHeight - 4); | ||
context.fillStyle = "#fff"; | ||
context.fillRect(0, barHeight - 4, hiddenCanvas.width, 4); | ||
data.getImageDataUrl = function(text){ | ||
var barHeight = 0; | ||
context.fillStyle = "#fff"; | ||
context.textBaseline = "top"; | ||
context.font = "12px sans-serif"; | ||
context.fillText(text, textPadding, 1); | ||
if(text){ | ||
barHeight = addLabel(text,context,hiddenCanvas); | ||
} | ||
return barHeight; | ||
} | ||
context.putImageData(imgd, 0, barHeight); | ||
function normalise(img, w, h) { | ||
var c; | ||
var context; | ||
return hiddenCanvas.toDataURL("image/png"); | ||
}; | ||
if (img.height < h || img.width < w) { | ||
c = document.createElement("canvas"); | ||
c.width = w; | ||
c.height = h; | ||
context = c.getContext("2d"); | ||
context.putImageData(img, 0, 0); | ||
return context.getImageData(0, 0, w, h); | ||
} | ||
if (hiddenCanvas.toBuffer) { | ||
data.getBuffer = function(includeOriginal) { | ||
if (includeOriginal) { | ||
var imageWidth = hiddenCanvas.width + 2; | ||
hiddenCanvas.width = imageWidth * 3; | ||
context.putImageData(img1, 0, 0); | ||
context.putImageData(img2, imageWidth, 0); | ||
context.putImageData(imgd, imageWidth * 2, 0); | ||
} else { | ||
context.putImageData(imgd, 0, 0); | ||
} | ||
return hiddenCanvas.toBuffer(); | ||
} | ||
} | ||
} | ||
return img; | ||
} | ||
function addLabel(text, context, hiddenCanvas){ | ||
var textPadding = 2; | ||
function outputSettings(options) { | ||
var key; | ||
context.font = '12px sans-serif'; | ||
if (options.errorColor) { | ||
for (key in options.errorColor) { | ||
if (options.hasOwnProperty(key)) { | ||
errorPixelColor[key] = | ||
options.errorColor[key] === void 0 | ||
? errorPixelColor[key] | ||
: options.errorColor[key]; | ||
} | ||
} | ||
} | ||
var textWidth = context.measureText(text).width + textPadding*2; | ||
var barHeight = 22; | ||
if (options.errorType && errorPixelTransform[options.errorType]) { | ||
errorPixel = errorPixelTransform[options.errorType]; | ||
errorType = options.errorType; | ||
} | ||
if(textWidth > hiddenCanvas.width){ | ||
hiddenCanvas.width = textWidth; | ||
} | ||
if ( | ||
options.errorPixel && | ||
typeof options.errorPixel === "function" | ||
) { | ||
errorPixel = options.errorPixel; | ||
} | ||
hiddenCanvas.height += barHeight; | ||
pixelTransparency = isNaN(Number(options.transparency)) | ||
? pixelTransparency | ||
: options.transparency; | ||
context.fillStyle = "#666"; | ||
context.fillRect(0,0,hiddenCanvas.width,barHeight -4); | ||
context.fillStyle = "#fff"; | ||
context.fillRect(0,barHeight -4,hiddenCanvas.width, 4); | ||
if (options.largeImageThreshold !== undefined) { | ||
largeImageThreshold = options.largeImageThreshold; | ||
} | ||
context.fillStyle = "#fff"; | ||
context.textBaseline = "top"; | ||
context.font = '12px sans-serif'; | ||
context.fillText(text, textPadding, 1); | ||
if (options.useCrossOrigin !== undefined) { | ||
useCrossOrigin = options.useCrossOrigin; | ||
} | ||
return barHeight; | ||
} | ||
if (options.boundingBox !== undefined) { | ||
boundingBox = options.boundingBox; | ||
} | ||
function normalise(img, w, h){ | ||
var c; | ||
var context; | ||
if (options.ignoredBox !== undefined) { | ||
ignoredBox = options.ignoredBox; | ||
} | ||
} | ||
if(img.height < h || img.width < w){ | ||
c = document.createElement('canvas'); | ||
c.width = w; | ||
c.height = h; | ||
context = c.getContext('2d'); | ||
context.putImageData(img, 0, 0); | ||
return context.getImageData(0, 0, w, h); | ||
} | ||
function compare(one, two) { | ||
if (globalOutputSettings !== oldGlobalSettings) { | ||
outputSettings(globalOutputSettings); | ||
} | ||
return img; | ||
} | ||
function onceWeHaveBoth() { | ||
var width; | ||
var height; | ||
if (images.length === 2) { | ||
if (images[0].error || images[1].error) { | ||
data = {}; | ||
data.error = images[0].error | ||
? images[0].error | ||
: images[1].error; | ||
triggerDataUpdate(); | ||
return; | ||
} | ||
width = | ||
images[0].width > images[1].width | ||
? images[0].width | ||
: images[1].width; | ||
height = | ||
images[0].height > images[1].height | ||
? images[0].height | ||
: images[1].height; | ||
function outputSettings(options){ | ||
var key; | ||
var undefined; | ||
if ( | ||
images[0].width === images[1].width && | ||
images[0].height === images[1].height | ||
) { | ||
data.isSameDimensions = true; | ||
} else { | ||
data.isSameDimensions = false; | ||
} | ||
if(options.errorColor){ | ||
for (key in options.errorColor) { | ||
errorPixelColor[key] = options.errorColor[key] === undefined ? errorPixelColor[key] : options.errorColor[key]; | ||
} | ||
} | ||
data.dimensionDifference = { | ||
width: images[0].width - images[1].width, | ||
height: images[0].height - images[1].height | ||
}; | ||
if(options.errorType && errorPixelTransform[options.errorType] ){ | ||
errorPixel = errorPixelTransform[options.errorType]; | ||
errorType = options.errorType; | ||
} | ||
analyseImages( | ||
normalise(images[0], width, height), | ||
normalise(images[1], width, height), | ||
width, | ||
height | ||
); | ||
if(options.errorPixel && typeof options.errorPixel === "function") { | ||
errorPixel = options.errorPixel; | ||
} | ||
triggerDataUpdate(); | ||
} | ||
} | ||
pixelTransparency = isNaN(Number(options.transparency)) ? pixelTransparency : options.transparency; | ||
images = []; | ||
loadImageData(one, onceWeHaveBoth); | ||
loadImageData(two, onceWeHaveBoth); | ||
} | ||
if (options.largeImageThreshold !== undefined) { | ||
largeImageThreshold = options.largeImageThreshold; | ||
} | ||
function getCompareApi(param) { | ||
var secondFileData; | ||
var hasMethod = typeof param === "function"; | ||
if (options.useCrossOrigin !== undefined) { | ||
useCrossOrigin = options.useCrossOrigin; | ||
} | ||
if (!hasMethod) { | ||
// assume it's file data | ||
secondFileData = param; | ||
} | ||
if (options.boundingBox !== undefined) { | ||
boundingBox = options.boundingBox; | ||
} | ||
var self = { | ||
scaleToSameSize: function() { | ||
scaleToSameSize = true; | ||
if (options.ignoredBox !== undefined) { | ||
ignoredBox = options.ignoredBox; | ||
} | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
useOriginalSize: function() { | ||
scaleToSameSize = false; | ||
} | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
ignoreNothing: function() { | ||
tolerance.red = 0; | ||
tolerance.green = 0; | ||
tolerance.blue = 0; | ||
tolerance.alpha = 0; | ||
tolerance.minBrightness = 0; | ||
tolerance.maxBrightness = 255; | ||
function compare(one, two){ | ||
if (globalOutputSettings !== oldGlobalSettings) { | ||
outputSettings(globalOutputSettings); | ||
} | ||
ignoreAntialiasing = false; | ||
ignoreColors = false; | ||
function onceWeHaveBoth(){ | ||
var width; | ||
var height; | ||
if(images.length === 2){ | ||
if( images[0].error || images[1].error ){ | ||
data = {}; | ||
data.error = images[0].error ? images[0].error : images[1].error; | ||
triggerDataUpdate(); | ||
return; | ||
} | ||
width = images[0].width > images[1].width ? images[0].width : images[1].width; | ||
height = images[0].height > images[1].height ? images[0].height : images[1].height; | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
ignoreLess: function() { | ||
tolerance.red = 16; | ||
tolerance.green = 16; | ||
tolerance.blue = 16; | ||
tolerance.alpha = 16; | ||
tolerance.minBrightness = 16; | ||
tolerance.maxBrightness = 240; | ||
if( (images[0].width === images[1].width) && (images[0].height === images[1].height) ){ | ||
data.isSameDimensions = true; | ||
} else { | ||
data.isSameDimensions = false; | ||
} | ||
ignoreAntialiasing = false; | ||
ignoreColors = false; | ||
data.dimensionDifference = { width: images[0].width - images[1].width, height: images[0].height - images[1].height }; | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
ignoreAntialiasing: function() { | ||
tolerance.red = 32; | ||
tolerance.green = 32; | ||
tolerance.blue = 32; | ||
tolerance.alpha = 32; | ||
tolerance.minBrightness = 64; | ||
tolerance.maxBrightness = 96; | ||
analyseImages( normalise(images[0],width, height), normalise(images[1],width, height), width, height); | ||
ignoreAntialiasing = true; | ||
ignoreColors = false; | ||
triggerDataUpdate(); | ||
} | ||
} | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
ignoreColors: function() { | ||
tolerance.alpha = 16; | ||
tolerance.minBrightness = 16; | ||
tolerance.maxBrightness = 240; | ||
images = []; | ||
loadImageData(one, onceWeHaveBoth); | ||
loadImageData(two, onceWeHaveBoth); | ||
} | ||
ignoreAntialiasing = false; | ||
ignoreColors = true; | ||
function getCompareApi(param){ | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
ignoreAlpha: function() { | ||
tolerance.red = 16; | ||
tolerance.green = 16; | ||
tolerance.blue = 16; | ||
tolerance.alpha = 255; | ||
tolerance.minBrightness = 16; | ||
tolerance.maxBrightness = 240; | ||
var secondFileData, | ||
hasMethod = typeof param === 'function'; | ||
ignoreAntialiasing = false; | ||
ignoreColors = false; | ||
if( !hasMethod ){ | ||
// assume it's file data | ||
secondFileData = param; | ||
} | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
repaint: function() { | ||
if (hasMethod) { | ||
param(); | ||
} | ||
return self; | ||
}, | ||
outputSettings: function(options) { | ||
outputSettings(options); | ||
return self; | ||
}, | ||
onComplete: function(callback) { | ||
updateCallbackArray.push(callback); | ||
var self = { | ||
scaleToSameSize: function(){ | ||
scaleToSameSize = true; | ||
var wrapper = function() { | ||
compare(fileData, secondFileData); | ||
}; | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
useOriginalSize: function(){ | ||
scaleToSameSize = false; | ||
wrapper(); | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
ignoreNothing: function(){ | ||
return getCompareApi(wrapper); | ||
} | ||
}; | ||
tolerance.red = 0; | ||
tolerance.green = 0; | ||
tolerance.blue = 0; | ||
tolerance.alpha = 0; | ||
tolerance.minBrightness = 0; | ||
tolerance.maxBrightness = 255; | ||
return self; | ||
} | ||
ignoreAntialiasing = false; | ||
ignoreColors = false; | ||
var rootSelf = { | ||
onComplete: function(callback) { | ||
updateCallbackArray.push(callback); | ||
loadImageData(fileData, function(imageData, width, height) { | ||
parseImage(imageData.data, width, height); | ||
}); | ||
}, | ||
compareTo: function(secondFileData) { | ||
return getCompareApi(secondFileData); | ||
}, | ||
outputSettings: function(options) { | ||
outputSettings(options); | ||
return rootSelf; | ||
} | ||
}; | ||
return rootSelf; | ||
}; | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
ignoreLess: function(){ | ||
function applyIgnore(api, ignore) { | ||
switch (ignore) { | ||
case "nothing": | ||
api.ignoreNothing(); | ||
break; | ||
case "less": | ||
api.ignoreLess(); | ||
break; | ||
case "antialiasing": | ||
api.ignoreAntialiasing(); | ||
break; | ||
case "colors": | ||
api.ignoreColors(); | ||
break; | ||
case "alpha": | ||
api.ignoreAlpha(); | ||
break; | ||
default: | ||
throw new Error("Invalid ignore: " + ignore); | ||
} | ||
} | ||
tolerance.red = 16; | ||
tolerance.green = 16; | ||
tolerance.blue = 16; | ||
tolerance.alpha = 16; | ||
tolerance.minBrightness = 16; | ||
tolerance.maxBrightness = 240; | ||
resemble.compare = function(image1, image2, options, cb) { | ||
let callback; | ||
let opt; | ||
ignoreAntialiasing = false; | ||
ignoreColors = false; | ||
if (typeof options === "function") { | ||
callback = options; | ||
opt = {}; | ||
} else { | ||
callback = cb; | ||
opt = options || {}; | ||
} | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
ignoreAntialiasing: function(){ | ||
var res = resemble(image1); | ||
var compare; | ||
tolerance.red = 32; | ||
tolerance.green = 32; | ||
tolerance.blue = 32; | ||
tolerance.alpha = 32; | ||
tolerance.minBrightness = 64; | ||
tolerance.maxBrightness = 96; | ||
if (opt.output) { | ||
res.outputSettings(opt.output); | ||
} | ||
ignoreAntialiasing = true; | ||
ignoreColors = false; | ||
compare = res.compareTo(image2); | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
ignoreColors: function(){ | ||
if (opt.scaleToSameSize) { | ||
compare.scaleToSameSize(); | ||
} | ||
tolerance.alpha = 16; | ||
tolerance.minBrightness = 16; | ||
tolerance.maxBrightness = 240; | ||
if (typeof opt.ignore === "string") { | ||
applyIgnore(compare, opt.ignore); | ||
} else if (opt.ignore && opt.ignore.forEach) { | ||
opt.ignore.forEach(function(v) { | ||
applyIgnore(compare, v); | ||
}); | ||
} | ||
ignoreAntialiasing = false; | ||
ignoreColors = true; | ||
compare.onComplete(function(data) { | ||
if (data.error) { | ||
callback(data.error); | ||
} else { | ||
callback(null, data); | ||
} | ||
}); | ||
}; | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
ignoreAlpha: function() { | ||
tolerance.red = 16; | ||
tolerance.green = 16; | ||
tolerance.blue = 16; | ||
tolerance.alpha = 255; | ||
tolerance.minBrightness = 16; | ||
tolerance.maxBrightness = 240; | ||
ignoreAntialiasing = false; | ||
ignoreColors = false; | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
repaint: function(){ | ||
if(hasMethod) { param(); } | ||
return self; | ||
}, | ||
outputSettings: function(options) { | ||
outputSettings(options); | ||
return self; | ||
}, | ||
onComplete: function( callback ){ | ||
updateCallbackArray.push(callback); | ||
var wrapper = function(){ | ||
compare(fileData, secondFileData); | ||
}; | ||
wrapper(); | ||
return getCompareApi(wrapper); | ||
} | ||
}; | ||
return self; | ||
} | ||
var rootSelf = { | ||
onComplete: function( callback ){ | ||
updateCallbackArray.push(callback); | ||
loadImageData(fileData, function(imageData, width, height){ | ||
parseImage(imageData.data, width, height); | ||
}); | ||
}, | ||
compareTo: function(secondFileData){ | ||
return getCompareApi(secondFileData); | ||
}, | ||
outputSettings: function(options) { | ||
outputSettings(options); | ||
return rootSelf; | ||
} | ||
}; | ||
return rootSelf; | ||
}; | ||
function applyIgnore(api, ignore) { | ||
switch (ignore) { | ||
case 'nothing': | ||
api.ignoreNothing(); | ||
break; | ||
case 'less': | ||
api.ignoreLess(); | ||
break; | ||
case 'antialiasing': | ||
api.ignoreAntialiasing(); | ||
break; | ||
case 'colors': | ||
api.ignoreColors(); | ||
break; | ||
case 'alpha': | ||
api.ignoreAlpha(); | ||
break; | ||
default: | ||
throw new Error('Invalid ignore: ' + ignore); | ||
break; | ||
} | ||
} | ||
resemble.compare = function (image1, image2, options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = undefined; | ||
} | ||
var res = resemble(image1), opt = options || {}, compare; | ||
if (opt.output) { | ||
res.outputSettings(opt.output); | ||
} | ||
compare = res.compareTo(image2); | ||
if (opt.scaleToSameSize) { | ||
compare.scaleToSameSize(); | ||
} | ||
if (typeof opt.ignore === 'string') { | ||
applyIgnore(compare, opt.ignore); | ||
} else if (opt.ignore && opt.ignore.forEach) { | ||
opt.ignore.forEach(function (v) { | ||
applyIgnore(compare, v); | ||
}); | ||
} | ||
compare.onComplete(function(data) { | ||
if (data.error) { | ||
callback(data.error); | ||
} else { | ||
callback(null, data); | ||
} | ||
}); | ||
}; | ||
resemble.outputSettings = setGlobalOutputSettings; | ||
return resemble; | ||
})); | ||
resemble.outputSettings = setGlobalOutputSettings; | ||
return resemble; | ||
}); |
Sorry, the diff of this file is not supported yet
90350
20
890
220
12