Browse Source

Merge branch 'master' into gh-pages

gh-pages
james.cryer 7 years ago
parent
commit
8e3920bbf3
  1. 7
      .dockerignore
  2. 6
      .npmignore
  3. 105
      README.md
  4. 1
      bower.json
  5. 10
      compareImages.js
  6. BIN
      demoassets/ghost1.png
  7. BIN
      demoassets/ghost2.png
  8. 87
      demoassets/main.js
  9. 37
      index.html
  10. BIN
      nodejs-tests/PeopleComparedToPeople2WithOriginal.png
  11. 8
      nodejs-tests/compareImages.test.js
  12. 108
      nodejs-tests/resemble.test.js
  13. 1339
      package-lock.json
  14. 15
      package.json
  15. 304
      resemble.js

7
.dockerignore

@ -0,0 +1,7 @@
.idea
**/node_modules
npm-debug.log
**/libs
index.html
bower.json
README.md

6
.npmignore

@ -3,4 +3,8 @@ npm-debug.log
libs
index.html
bower.json
README.md
README.md
chai-tests
nodejs-tests
.dockerignore
dockerfile

105
README.md

@ -75,8 +75,8 @@ resemble.outputSettings({
largeImageThreshold: 1200,
useCrossOrigin: false,
outputDiff: true
});
// resembleControl.repaint();
})
// .repaint();
```
It is possible to narrow down the area of comparison, by specifying a bounding box measured in pixels from the top left:
@ -89,8 +89,22 @@ resemble.outputSettings({
right: 200,
bottom: 600
}
});
// resembleControl.repaint();
})
// .repaint();
```
You can also exclude part of the image from comparison, by specifying the excluded area in pixels from the top left:
```javascript
resemble.outputSettings({
ignoredBox: {
left: 100,
top: 200,
right: 200,
bottom: 600
}
})
// .repaint();
```
By default, the comparison algorithm skips pixels when the image width or height is larger than 1200 pixels. This is there to mitigate performance issues.
@ -99,6 +113,52 @@ You can modify this behaviour by setting the `largeImageThreshold` option to a d
`useCrossOrigin` is true by default, you might need to set it to false if you're using [Data URIs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs).
### 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
#### Installation
@ -117,19 +177,44 @@ npm install canvas
#### Usage
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 compareImage = require('resemblejs/compareImages');
const compareImages = require('resemblejs/compareImages');
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());
}
getDiff();
```
#### Tests

1
bower.json

@ -1,7 +1,6 @@
{
"name": "resemblejs",
"main": "resemble.js",
"version": "2.4.0",
"homepage": "https://github.com/Huddle/Resemble.js",
"authors": [
"James Cryer <james.cryer@huddle.com>"

10
compareImages.js

@ -1,10 +1,10 @@
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 {
resolve(data);
}

BIN
demoassets/ghost1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
demoassets/ghost2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

87
demoassets/main.js

@ -60,7 +60,23 @@ $(function(){
$('#image-diff').html(diffImage);
$(diffImage).click(function(){
window.open(diffImage.src, '_blank');
var w = window.open("about:blank", "_blank");
var html = w.document.documentElement;
var body = w.document.body;
html.style.margin = 0;
html.style.padding = 0;
body.style.margin = 0;
body.style.padding = 0;
var img = w.document.createElement("img");
img.src = diffImage.src;
img.alt = "image diff";
img.style.maxWidth = "100%";
img.addEventListener("click", function() {
this.style.maxWidth = this.style.maxWidth === "100%" ? "" : "100%";
});
body.appendChild(img);
});
$('.buttons').show();
@ -134,86 +150,87 @@ $(function(){
}
else
if($this.is('#pink')){
resemble.outputSettings({
resembleControl.outputSettings({
errorColor: {
red: 255,
green: 0,
blue: 255
}
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#yellow')){
resemble.outputSettings({
resembleControl.outputSettings({
errorColor: {
red: 255,
green: 255,
blue: 0
}
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#flat')){
resemble.outputSettings({
resembleControl.outputSettings({
errorType: 'flat'
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#movement')){
resemble.outputSettings({
resembleControl.outputSettings({
errorType: 'movement'
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#flatDifferenceIntensity')){
resemble.outputSettings({
resembleControl.outputSettings({
errorType: 'flatDifferenceIntensity'
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#movementDifferenceIntensity')){
resemble.outputSettings({
resembleControl.outputSettings({
errorType: 'movementDifferenceIntensity'
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#diffOnly')){
resemble.outputSettings({
resembleControl.outputSettings({
errorType: 'diffOnly'
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#opaque')){
resemble.outputSettings({
resembleControl.outputSettings({
transparency: 1
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#transparent')){
resemble.outputSettings({
resembleControl.outputSettings({
transparency: 0.3
});
resembleControl.repaint();
}).repaint();
}
else
if($this.is('#boundingBox')){
resemble.outputSettings({
resembleControl.outputSettings({
boundingBox: {
left: $("#x1").val(),
top: $("#y1").val(),
right: $("#x2").val(),
bottom: $("#y2").val()
left: $("#bounding-box-x1").val(),
top: $("#bounding-box-y1").val(),
right: $("#bounding-box-x2").val(),
bottom: $("#bounding-box-y2").val()
}
});
resembleControl.repaint();
}).repaint();
$this.removeClass('active');
}
if($this.is('#ignoredBox')){
resembleControl.outputSettings({
ignoredBox: {
left: $("#ignored-box-x1").val(),
top: $("#ignored-box-y1").val(),
right: $("#ignored-box-x2").val(),
bottom: $("#ignored-box-y2").val()
}
}).repaint();
$this.removeClass('active');
}
});

37
index.html

@ -142,19 +142,19 @@
<div class="row">
<div class="span1">
<label>Left</label>
<input type="number" class="input-mini" id="x1" value="100" />
<input type="number" class="input-mini" id="bounding-box-x1" value="100" />
</div>
<div class="span1">
<label>Top</label>
<input type="number" class="input-mini" id="y1" value="100" />
<input type="number" class="input-mini" id="bounding-box-y1" value="100" />
</div>
<div class="span1">
<label>Right</label>
<input type="number" class="input-mini" id="x2" value="400" />
<input type="number" class="input-mini" id="bounding-box-x2" value="400" />
</div>
<div class="span1">
<label>Bottom</label>
<input type="number" class="input-mini" id="y2" value="300" />
<input type="number" class="input-mini" id="bounding-box-y2" value="300" />
</div>
<div class="span2">
<label>&nbsp;</label>
@ -162,6 +162,35 @@
</div>
</div>
</div>
<br/>
<br/>
<div class="btn-group buttons" style="display:none">
<div class="row">
<div class="span1">
<label>Left</label>
<input type="number" class="input-mini" id="ignored-box-x1" value="120" />
</div>
<div class="span1">
<label>Top</label>
<input type="number" class="input-mini" id="ignored-box-y1" value="200" />
</div>
<div class="span1">
<label>Right</label>
<input type="number" class="input-mini" id="ignored-box-x2" value="400" />
</div>
<div class="span1">
<label>Bottom</label>
<input type="number" class="input-mini" id="ignored-box-y2" value="250" />
</div>
<div class="span2">
<label>&nbsp;</label>
<button class="btn" id="ignoredBox">Set ignored box</button>
</div>
</div>
</div>
<br/>
<br/>
<div id="diff-results" style="display:none;">

BIN
nodejs-tests/PeopleComparedToPeople2WithOriginal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

8
nodejs-tests/compareImages.test.js

@ -21,6 +21,12 @@ describe('compareImages', () => {
);
expect(buffer.equals(comparison)).toBe(true);
const buffer2 = data.getBuffer(true);
const comparison2 = fs.readFileSync(
'./nodejs-tests/PeopleComparedToPeople2WithOriginal.png'
);
expect(buffer2.equals(comparison2)).toBe(true);
});
test('throws when failed', async () => {
@ -28,6 +34,6 @@ describe('compareImages', () => {
fs.readFileSync('./demoassets/People.jpg'),
'bogus data'
);
await expect(promise).rejects.toMatch('Image load error.');
await expect(promise).rejects.toMatch('Error: error while reading from input stream');
});
});

108
nodejs-tests/resemble.test.js

@ -26,33 +26,36 @@ describe('resemble', () => {
});
});
test('files', () => {
return new Promise(function(resolve, reject) {
resemble('./demoassets/People.jpg')
.compareTo('./demoassets/People2.jpg')
.onComplete(function(data) {
// console.info('Reached oncomplete for request_success');
expect(data.diffBounds).toEqual(
expect.objectContaining({
bottom: expect.any(Number),
left: expect.any(Number),
top: expect.any(Number),
right: expect.any(Number)
})
);
expect(data.diffBounds.bottom).toEqual(431);
expect(data.diffBounds.left).toEqual(22);
expect(data.diffBounds.right).toEqual(450);
expect(data.diffBounds.top).toEqual(58);
expect(data.dimensionDifference.height).toEqual(0);
expect(data.dimensionDifference.width).toEqual(0);
expect(data.isSameDimensions).toBe(true);
expect(data.misMatchPercentage).toEqual('8.66');
resolve();
});
});
});
// this doesn't work on windows
// test('files', () => {
// return new Promise(function(resolve, reject) {
// console.log('hello there how are you');
// resemble('demoassets/People.jpg')
// .compareTo('demoassets/People2.jpg')
// .onComplete(function(data) {
// // console.info('Reached oncomplete for request_success');
// expect(data.diffBounds).toEqual(
// expect.objectContaining({
// bottom: expect.any(Number),
// left: expect.any(Number),
// top: expect.any(Number),
// right: expect.any(Number)
// })
// );
//
// expect(data.diffBounds.bottom).toEqual(431);
// expect(data.diffBounds.left).toEqual(22);
// expect(data.diffBounds.right).toEqual(450);
// expect(data.diffBounds.top).toEqual(58);
// expect(data.dimensionDifference.height).toEqual(0);
// expect(data.dimensionDifference.width).toEqual(0);
// expect(data.isSameDimensions).toBe(true);
// expect(data.misMatchPercentage).toEqual('8.66');
// resolve();
// });
// });
// });
test('file not found', () => {
return new Promise(function(resolve, reject) {
@ -61,13 +64,13 @@ describe('resemble', () => {
.onComplete(function(data) {
// console.info('Reached oncomplete for request_404');
// console.log(data);
expect(data.error).toEqual('Image load error.');
expect(data.error).toEqual('Error: error while reading from input stream');
resolve();
});
});
});
test('node buffers', () => {
test('node buffers jpg', () => {
const people = fs.readFileSync('./demoassets/People.jpg');
const people2 = fs.readFileSync('./demoassets/People2.jpg');
@ -86,4 +89,51 @@ describe('resemble', () => {
});
});
});
test('node buffers png', () => {
const people = fs.readFileSync('./demoassets/ghost1.png');
const people2 = fs.readFileSync('./demoassets/ghost2.png');
return new Promise(function(resolve, reject) {
resemble(people).compareTo(people2).onComplete(function(data) {
// console.info('Reached oncomplete for base64_string');
expect(data.diffBounds.bottom).toEqual(138);
expect(data.diffBounds.left).toEqual(90);
expect(data.diffBounds.right).toEqual(157);
expect(data.diffBounds.top).toEqual(107);
expect(data.dimensionDifference.height).toEqual(0);
expect(data.dimensionDifference.width).toEqual(0);
expect(data.isSameDimensions).toBe(true);
expect(data.misMatchPercentage).toEqual('0.27');
resolve();
});
});
});
test('test partial diff with bounding box', () => {
const people = fs.readFileSync('./demoassets/ghost1.png');
const people2 = fs.readFileSync('./demoassets/ghost2.png');
return new Promise(function(resolve, reject) {
resemble.outputSettings({
boundingBox: {
left: 80,
top: 80,
right: 130,
bottom: 130
}
});
resemble(people).compareTo(people2).onComplete(function(data) {
expect(data.misMatchPercentage).toEqual('0.04');
resolve();
});
});
});
});

1339
package-lock.json generated

File diff suppressed because it is too large Load Diff

15
package.json

@ -1,6 +1,6 @@
{
"name": "resemblejs",
"version": "2.4.0",
"version": "2.9.0",
"description": "Image analysis and comparison with HTML5",
"main": "resemble.js",
"repository": {
@ -22,16 +22,17 @@
},
"homepage": "https://github.com/Huddle/Resemble.js",
"scripts": {
"test": "jest ./nodejs-tests",
"test-watch": "jest --watch ./nodejs-tests"
"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"
},
"peerDependencies": {
"canvas": "^1.6.5"
"jest-cli": "^20.0.4",
"color-convert": "^1.9.0"
},
"jest": {
"testEnvironment": "node"

304
resemble.js

@ -4,6 +4,7 @@ URL: https://github.com/Huddle/Resemble.js
*/
(function (root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof module === 'object' && module.exports) {
@ -14,82 +15,103 @@ URL: https://github.com/Huddle/Resemble.js
}(this, function () {
'use strict';
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;
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 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;
}
};
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');
return new Canvas();
function withinBoundingBox(x, y, width, height, box) {
return x > (box.left || 0) &&
x < (box.right || width) &&
y > (box.top || 0) &&
y < (box.bottom || height);
}
};
var resemble = function( fileData ){
function withinComparedArea(x, y, width, height) {
var isIncluded = true;
if (boundingBox !== undefined && !withinBoundingBox(x, y, width, height, boundingBox)) {
isIncluded = false;
}
if (ignoredBox !== undefined && withinBoundingBox(x, y, width, height, ignoredBox)) {
isIncluded = false;
}
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;
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 = [];
@ -180,19 +202,18 @@ URL: https://github.com/Huddle/Resemble.js
if (typeof Image !== 'undefined') {
hiddenImage = new Image();
} else {
var CanvasImage = require('canvas').Image;
var CanvasImage = require('canvas-prebuilt').Image;
hiddenImage = new CanvasImage();
hiddenImage.setAttribute = function setAttribute() { };
}
if(useCrossOrigin) {
hiddenImage.setAttribute('crossorigin', 'anonymous');
}
hiddenImage.onerror = function () {
hiddenImage.onerror = function (err) {
hiddenImage.onerror = null; //fixes pollution between calls
images.push({ error : "Image load error."});
images.push({ error : err ? err + "" : "Image load error." });
callback();
};
@ -395,7 +416,7 @@ URL: https://github.com/Huddle/Resemble.js
px[offset + 3] = data.a * pixelTransparency; //a
}
function getPixelInfo(dst, data, offset, cacheSet) {
function getPixelInfo(dst, data, offset) {
if (data.length > offset) {
dst.r = data[offset];
dst.g = data[offset + 1];
@ -464,7 +485,7 @@ URL: https://github.com/Huddle/Resemble.js
}
var offset = (verticalPos*width + horizontalPos) * 4;
var isWithinBoundingBox = withinBoundingBox(horizontalPos, verticalPos, width, height);
var isWithinComparedArea = withinComparedArea(horizontalPos, verticalPos, width, height);
if (!getPixelInfo(pixel1, data1, offset, 1) || !getPixelInfo(pixel2, data2, offset, 2)) {
return;
@ -475,7 +496,7 @@ URL: https://github.com/Huddle/Resemble.js
addBrightnessInfo(pixel1);
addBrightnessInfo(pixel2);
if( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinBoundingBox ){
if( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea ){
copyGrayScalePixel(targetPix, offset, pixel2);
} else {
errorPixel(targetPix, offset, pixel1, pixel2);
@ -485,8 +506,8 @@ URL: https://github.com/Huddle/Resemble.js
return;
}
if( isRGBSimilar(pixel1, pixel2) || !isWithinBoundingBox ){
copyPixel(targetPix, offset, pixel1, pixel2);
if( isRGBSimilar(pixel1, pixel2) || !isWithinComparedArea ){
copyPixel(targetPix, offset, pixel1);
} else if( ignoreAntialiasing && (
addBrightnessInfo(pixel1), // jit pixel info augmentation looks a little weird, sorry.
@ -495,7 +516,7 @@ URL: https://github.com/Huddle/Resemble.js
isAntialiased(pixel2, data2, 2, verticalPos, horizontalPos, width)
)){
if( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinBoundingBox ){
if( isPixelBrightnessSimilar(pixel1, pixel2) || !isWithinComparedArea ){
copyGrayScalePixel(targetPix, offset, pixel2);
} else {
errorPixel(targetPix, offset, pixel1, pixel2);
@ -528,8 +549,16 @@ URL: https://github.com/Huddle/Resemble.js
};
if (hiddenCanvas.toBuffer) {
data.getBuffer = function() {
context.putImageData(imgd, 0, 0);
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();
}
}
@ -578,7 +607,49 @@ URL: https://github.com/Huddle/Resemble.js
return img;
}
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;
}
if (options.ignoredBox !== undefined) {
ignoredBox = options.ignoredBox;
}
}
function compare(one, two){
if (globalOutputSettings !== oldGlobalSettings) {
outputSettings(globalOutputSettings);
}
function onceWeHaveBoth(){
var width;
@ -711,6 +782,10 @@ URL: https://github.com/Huddle/Resemble.js
if(hasMethod) { param(); }
return self;
},
outputSettings: function(options) {
outputSettings(options);
return self;
},
onComplete: function( callback ){
updateCallbackArray.push(callback);
@ -728,7 +803,7 @@ URL: https://github.com/Huddle/Resemble.js
return self;
}
return {
var rootSelf = {
onComplete: function( callback ){
updateCallbackArray.push(callback);
loadImageData(fileData, function(imageData, width, height){
@ -737,46 +812,73 @@ URL: https://github.com/Huddle/Resemble.js
},
compareTo: function(secondFileData){
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];
}
}
if(options.errorType && errorPixelTransform[options.errorType] ){
errorPixel = errorPixelTransform[options.errorType];
errorType = options.errorType;
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;
}
}
if(options.errorPixel && typeof options.errorPixel === "function") {
errorPixel = options.errorPixel;
resemble.compare = function (image1, image2, options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
pixelTransparency = isNaN(Number(options.transparency)) ? pixelTransparency : options.transparency;
var res = resemble(image1), opt = options || {}, compare;
if (options.largeImageThreshold !== undefined) {
largeImageThreshold = options.largeImageThreshold;
if (opt.output) {
res.outputSettings(opt.output);
}
if (options.useCrossOrigin !== undefined) {
useCrossOrigin = options.useCrossOrigin;
compare = res.compareTo(image2);
if (opt.scaleToSameSize) {
compare.scaleToSameSize();
}
if (options.boundingBox !== undefined) {
boundingBox = options.boundingBox;
if (typeof opt.ignore === 'string') {
applyIgnore(compare, opt.ignore);
} else if (opt.ignore && opt.ignore.forEach) {
opt.ignore.forEach(function (v) {
applyIgnore(compare, v);
});
}
return this;
compare.onComplete(function(data) {
if (data.error) {
callback(data.error);
} else {
callback(null, data);
}
});
};
resemble.outputSettings = setGlobalOutputSettings;
return resemble;
}));

Loading…
Cancel
Save