resemblejs
Advanced tools
Comparing version 2.5.0 to 2.6.0
@@ -1,8 +0,8 @@ | ||
const resemble = require('./resemble'); | ||
var resemble = require('./resemble'); | ||
module.exports = async function(image1, image2) { | ||
module.exports = function(image1, image2, options) { | ||
return new Promise(function(resolve, reject) { | ||
resemble(image1).compareTo(image2).onComplete(function(data) { | ||
if (data.error) { | ||
reject(data.error); | ||
resemble.compare(image1, image2, options, function(err, data) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
@@ -9,0 +9,0 @@ resolve(data); |
{ | ||
"name": "resemblejs", | ||
"version": "2.5.0", | ||
"version": "2.6.0", | ||
"description": "Image analysis and comparison with HTML5", | ||
@@ -5,0 +5,0 @@ "main": "resemble.js", |
@@ -78,4 +78,4 @@ Resemble.js | ||
outputDiff: true | ||
}); | ||
// resembleControl.repaint(); | ||
}) | ||
// .repaint(); | ||
``` | ||
@@ -93,4 +93,4 @@ | ||
} | ||
}); | ||
// resembleControl.repaint(); | ||
}) | ||
// .repaint(); | ||
``` | ||
@@ -104,2 +104,47 @@ | ||
### Single callback api | ||
The resemble.compare API provides a convenience function that is used as follows: | ||
``` js | ||
const compare = require('resemblejs').compare; | ||
function getDiff(){ | ||
const options = { | ||
output: { | ||
errorColor: { | ||
red: 255, | ||
green: 0, | ||
blue: 255 | ||
}, | ||
errorType: 'movement', | ||
transparency: 0.3, | ||
largeImageThreshold: 1200, | ||
useCrossOrigin: false, | ||
outputDiff: true | ||
}, | ||
scaleToSameSize: true, | ||
ignore: ['nothing', 'less', 'antialiasing', 'colors', 'alpha'], | ||
}; | ||
// The parameters can be Node Buffers | ||
// data is the same as usual with an additional getBuffer() function | ||
compare(image1, image2, options, function (err, data) { | ||
if (err) { | ||
console.log('An error!') | ||
} else { | ||
console.log(data); | ||
/* | ||
{ | ||
misMatchPercentage : 100, // % | ||
isSameDimensions: true, // or false | ||
dimensionDifference: { width: 0, height: -1 }, // defined if dimensions are not the same | ||
getImageDataUrl: function(){} | ||
} | ||
*/ | ||
} | ||
}); | ||
``` | ||
### Node.js | ||
@@ -123,17 +168,35 @@ | ||
The API under Node is the same as on the browser with one addition, a promise based `compareImage` convenience function that is used as follows: | ||
The API under Node is the same as on the `resemble.compare` but promise based: | ||
``` js | ||
const compareImages = require('resemblejs/compareImages'); | ||
const fs = require("fs"); | ||
const fs = require("mz/fs"); | ||
async function getDiff(){ | ||
const options = { | ||
output: { | ||
errorColor: { | ||
red: 255, | ||
green: 0, | ||
blue: 255 | ||
}, | ||
errorType: 'movement', | ||
transparency: 0.3, | ||
largeImageThreshold: 1200, | ||
useCrossOrigin: false, | ||
outputDiff: true | ||
}, | ||
scaleToSameSize: true, | ||
ignore: ['nothing', 'less', 'antialiasing', 'colors', 'alpha'], | ||
}; | ||
// The parameters can be Node Buffers | ||
// data is the same as usual with an additional getBuffer() function | ||
const data = await compareImages( | ||
fs.readFileSync('./demoassets/People.jpg'), | ||
fs.readFileSync('./demoassets/People2.jpg') | ||
await fs.readFile('./demoassets/People.jpg'), | ||
await fs.readFile('./demoassets/People2.jpg'), | ||
options, | ||
); | ||
fs.writeFileSync('./output.png', data.getBuffer()); | ||
await fs.writeFile('./output.png', data.getBuffer()); | ||
@@ -140,0 +203,0 @@ } |
247
resemble.js
@@ -7,2 +7,3 @@ /* | ||
(function (root, factory) { | ||
'use strict'; | ||
if (typeof define === 'function' && define.amd) { | ||
@@ -18,78 +19,88 @@ define([], factory); | ||
var pixelTransparency = 1; | ||
var errorPixelColor = { // Color for Error Pixels. Between 0 and 255. | ||
red: 255, | ||
green: 0, | ||
blue: 255, | ||
alpha: 255 | ||
var document = typeof window != "undefined" ? window.document : { | ||
createElement: function() { | ||
// This will work as long as only createElement is used on window.document | ||
var Canvas = require('canvas-prebuilt'); | ||
return new Canvas(); | ||
} | ||
}; | ||
var targetPix = {r: 0, g: 0, b: 0, a: 0}; // isAntialiased | ||
var oldGlobalSettings = {}; | ||
var globalOutputSettings = oldGlobalSettings; | ||
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 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 withinBoundingBox(x, y, width, height) { | ||
if (!boundingBox) { | ||
return true; | ||
} | ||
var resemble = function( fileData ){ | ||
var pixelTransparency = 1; | ||
return x > (boundingBox.left || 0) && | ||
x < (boundingBox.right || width) && | ||
y > (boundingBox.top || 0) && | ||
y < (boundingBox.bottom || height); | ||
} | ||
var errorPixelColor = { // Color for Error Pixels. Between 0 and 255. | ||
red: 255, | ||
green: 0, | ||
blue: 255, | ||
alpha: 255 | ||
}; | ||
var errorPixelTransform = { | ||
flat: function (px, offset, d1, d2) { | ||
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 targetPix = {r: 0, g: 0, b: 0, a: 0}; // isAntialiased | ||
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; | ||
function colorsDistance(c1, c2){ | ||
return (Math.abs(c1.r - c2.r) + Math.abs(c1.g - c2.g) + Math.abs(c1.b - c2.b))/3; | ||
} | ||
}; | ||
var errorPixel = errorPixelTransform.flat; | ||
var errorType; | ||
var boundingBox; | ||
var largeImageThreshold = 1200; | ||
var useCrossOrigin = true; | ||
var document = typeof window != "undefined" ? window.document : { | ||
createElement: function() { | ||
// This will work as long as only createElement is used on window.document | ||
var Canvas = require('canvas-prebuilt'); | ||
return new Canvas(); | ||
function withinBoundingBox(x, y, width, height) { | ||
if (!boundingBox) { | ||
return true; | ||
} | ||
return x > (boundingBox.left || 0) && | ||
x < (boundingBox.right || width) && | ||
y > (boundingBox.top || 0) && | ||
y < (boundingBox.bottom || height); | ||
} | ||
}; | ||
var resemble = function( fileData ){ | ||
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; | ||
} | ||
}; | ||
var errorPixel = errorPixelTransform.flat; | ||
var errorType; | ||
var boundingBox; | ||
var largeImageThreshold = 1200; | ||
var useCrossOrigin = true; | ||
var data = {}; | ||
@@ -190,3 +201,2 @@ var images = []; | ||
if(useCrossOrigin) { | ||
@@ -401,3 +411,3 @@ hiddenImage.setAttribute('crossorigin', 'anonymous'); | ||
function getPixelInfo(dst, data, offset, cacheSet) { | ||
function getPixelInfo(dst, data, offset) { | ||
if (data.length > offset) { | ||
@@ -593,3 +603,41 @@ dst.r = data[offset]; | ||
function outputSettings(options){ | ||
var key; | ||
var undefined; | ||
if(options.errorColor){ | ||
for (key in options.errorColor) { | ||
errorPixelColor[key] = options.errorColor[key] === undefined ? errorPixelColor[key] : options.errorColor[key]; | ||
} | ||
} | ||
if(options.errorType && errorPixelTransform[options.errorType] ){ | ||
errorPixel = errorPixelTransform[options.errorType]; | ||
errorType = options.errorType; | ||
} | ||
if(options.errorPixel && typeof options.errorPixel === "function") { | ||
errorPixel = options.errorPixel; | ||
} | ||
pixelTransparency = isNaN(Number(options.transparency)) ? pixelTransparency : options.transparency; | ||
if (options.largeImageThreshold !== undefined) { | ||
largeImageThreshold = options.largeImageThreshold; | ||
} | ||
if (options.useCrossOrigin !== undefined) { | ||
useCrossOrigin = options.useCrossOrigin; | ||
} | ||
if (options.boundingBox !== undefined) { | ||
boundingBox = options.boundingBox; | ||
} | ||
} | ||
function compare(one, two){ | ||
if (globalOutputSettings !== oldGlobalSettings) { | ||
outputSettings(options); | ||
} | ||
@@ -727,2 +775,6 @@ function onceWeHaveBoth(){ | ||
}, | ||
outputSettings: function(options) { | ||
outputSettings(options); | ||
return self; | ||
}, | ||
onComplete: function( callback ){ | ||
@@ -745,3 +797,3 @@ | ||
return { | ||
var rootSelf = { | ||
onComplete: function( callback ){ | ||
@@ -755,44 +807,59 @@ updateCallbackArray.push(callback); | ||
return getCompareApi(secondFileData); | ||
}, | ||
outputSettings: function(options) { | ||
outputSettings(options); | ||
return rootSelf; | ||
} | ||
}; | ||
return rootSelf; | ||
}; | ||
resemble.outputSettings = function(options){ | ||
var key; | ||
var undefined; | ||
if(options.errorColor){ | ||
for (key in options.errorColor) { | ||
errorPixelColor[key] = options.errorColor[key] === undefined ? errorPixelColor[key] : options.errorColor[key]; | ||
} | ||
function applyIgnore(api, ignore) { | ||
switch (ignore) { | ||
case 'nothing': api.ignoreNothing(); | ||
case 'less': api.ignoreLess(); | ||
case 'antialiasing': api.ignoreAntialiasing(); | ||
case 'colors': api.ignoreColors(); | ||
case 'alpha': api.ignoreAlpha(); | ||
default: throw new Error('Invalid ignore: ' + ignore); | ||
} | ||
} | ||
if(options.errorType && errorPixelTransform[options.errorType] ){ | ||
errorPixel = errorPixelTransform[options.errorType]; | ||
errorType = options.errorType; | ||
resemble.compare = function (image1, image2, options, callback) { | ||
if (typeof options === 'function') { | ||
callback = options; | ||
options = undefined; | ||
} | ||
if(options.errorPixel && typeof options.errorPixel === "function") { | ||
errorPixel = options.errorPixel; | ||
var res = resemble(image1), opt = options || {}, compare; | ||
if (opt.output) { | ||
res.outputSettings(opt.output); | ||
} | ||
pixelTransparency = isNaN(Number(options.transparency)) ? pixelTransparency : options.transparency; | ||
compare = res.compareTo(image2); | ||
if (options.largeImageThreshold !== undefined) { | ||
largeImageThreshold = options.largeImageThreshold; | ||
if (opt.scaleToSameSize) { | ||
compare.scaleToSameSize(); | ||
} | ||
if (options.useCrossOrigin !== undefined) { | ||
useCrossOrigin = options.useCrossOrigin; | ||
if (typeof opt.ignore === 'string') { | ||
applyIgnore(compare, opt.ignore); | ||
} else if (opt.ignore && opt.ignore.forEach) { | ||
opt.ignore.forEach(function (v) { | ||
applyIgnore(compare, v); | ||
}); | ||
} | ||
if (options.boundingBox !== undefined) { | ||
boundingBox = options.boundingBox; | ||
} | ||
return this; | ||
compare.onComplete(function(data) { | ||
if (data.error) { | ||
callback(data.error); | ||
} else { | ||
callback(null, data); | ||
} | ||
}); | ||
}; | ||
resemble.outputSettings = setGlobalOutputSettings; | ||
return resemble; | ||
})); |
Sorry, the diff of this file is not supported yet
75865
703
227