Browse Source

Merge branch 'zol-master'

pull/104/head
james.cryer 7 years ago
parent
commit
4b94469100
  1. 3
      .gitignore
  2. 42
      README.md
  3. 104
      chai-tests/main_spec.js
  4. 5
      chai-tests/test.html
  5. 15
      dockerfile
  6. BIN
      nodejs-tests/PeopleComparedToPeople2.png
  7. 13
      nodejs-tests/compareImages.js
  8. 33
      nodejs-tests/compareImages.test.js
  9. 89
      nodejs-tests/resemble.test.js
  10. 2084
      package-lock.json
  11. 17
      package.json
  12. 33
      resemble.js
  13. 79
      tests/main_spec.js

3
.gitignore vendored

@ -1 +1,2 @@
.idea .idea
node_modules

42
README.md

@ -1,7 +1,7 @@
Resemble.js Resemble.js
========== ==========
Analyse and compare images with Javascript and HTML5. [More info & Resemble.js Demo](http://huddle.github.com/Resemble.js/). If you need NodeJS support, take a look at [node-resemble](https://github.com/ddo/node-resemble) or [node-resemble-v2](https://github.com/peter-mouland/node-resemble-v2). Analyse and compare images with Javascript and HTML5. [More info & Resemble.js Demo](http://huddle.github.com/Resemble.js/). Compatible with Node.js.
![Two image diff examples side-by-side, one pink, one yellow.](https://raw.github.com/Huddle/Resemble.js/master/demoassets/readmeimage.jpg "Visual image comparison") ![Two image diff examples side-by-side, one pink, one yellow.](https://raw.github.com/Huddle/Resemble.js/master/demoassets/readmeimage.jpg "Visual image comparison")
@ -83,6 +83,46 @@ 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). `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).
### Node.js
#### Installation
On Node, Resemble uses the `canvas` package instead of the native canvas support in the browser. In order to prevent browser users to be forced into installing canvas, it's included as a peer dependency which means you have to install it alongside resemble.
Canvas relies on some native image manipulation libraries to be install on the system. Simple, detailed instructions for OSX/Windows/Linux can be found [here](https://www.npmjs.com/package/canvas).
*Example commands for installation on OSX*
``` bash
npm install resemblejs
brew install pkg-config cairo libpng jpeg giflib
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:
``` js
const compareImage = require('resemblejs/compareImage');
// 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')
);
fs.writeFileSync('./output.png', data.getBuffer());
```
#### Tests
To run the tests on Node (using Jest), type:
``` bash
npm run test
```
-------------------------------------- --------------------------------------

104
chai-tests/main_spec.js

File diff suppressed because one or more lines are too long

5
tests/test.html → chai-tests/test.html

@ -6,7 +6,8 @@
<body> <body>
<p>Check the console for test results</p> <p>Check the console for test results</p>
<script src="../resemble.js"></script> <script src="../resemble.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.js"></script> <!--script src="//cdnjs.cloudflare.com/ajax/libs/chai/3.4.1/chai.js"></script-->
<script src="../node_modules/chai/chai.js"></script>
<script src="main_spec.js"></script> <script src="main_spec.js"></script>
</body> </body>
</html> </html>

15
dockerfile

@ -0,0 +1,15 @@
FROM node:8
RUN apt-get update \
&& apt-get install -qq libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev build-essential g++
RUN mkdir -p /opt/node/js \
&& cd /opt/node \
&& npm install canvas color-convert
WORKDIR /opt/node/js
COPY . /opt/node/js
RUN npm install
CMD ["npm", "run", "test"]

BIN
nodejs-tests/PeopleComparedToPeople2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

13
nodejs-tests/compareImages.js

@ -0,0 +1,13 @@
const resemble = require('../resemble');
module.exports = async function(image1, image2) {
return new Promise(function(resolve, reject) {
resemble(image1).compareTo(image2).onComplete(function(data) {
if (data.error) {
reject(data.error);
} else {
resolve(data);
}
});
});
};

33
nodejs-tests/compareImages.test.js

@ -0,0 +1,33 @@
const compareImages = require('./compareImages');
const fs = require('fs');
describe('compareImages', () => {
test('works with buffers', async () => {
const data = await compareImages(
fs.readFileSync('./demoassets/People.jpg'),
fs.readFileSync('./demoassets/People2.jpg')
);
expect(data.isSameDimensions).toBe(true);
expect(data.misMatchPercentage).toEqual('8.66');
const buffer = data.getBuffer();
expect(buffer).toBeInstanceOf(Buffer);
expect(buffer.length).toBe(91876);
const comparison = fs.readFileSync(
'./nodejs-tests/PeopleComparedToPeople2.png'
);
expect(buffer.equals(comparison)).toBe(true);
});
test('throws when failed', async () => {
const promise = compareImages(
fs.readFileSync('./demoassets/People.jpg'),
'bogus data'
);
await expect(promise).rejects.toMatch('Image load error.');
});
});

89
nodejs-tests/resemble.test.js

@ -0,0 +1,89 @@
const resemble = require('../resemble');
const fs = require('fs');
describe('resemble', () => {
test('base64', () => {
const people_src =
'data:image/jpeg;base64,' +
fs.readFileSync('./demoassets/People.jpg', 'base64');
const people2_src =
'data:image/jpeg;base64,' +
fs.readFileSync('./demoassets/People2.jpg', 'base64');
return new Promise(function(resolve, reject) {
resemble(people_src).compareTo(people2_src).onComplete(function(data) {
// console.info('Reached oncomplete for base64_string');
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('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();
});
});
});
test('file not found', () => {
return new Promise(function(resolve, reject) {
resemble('../demoassets/People.jpg')
.compareTo('../demoassets/404-image.jpg')
.onComplete(function(data) {
// console.info('Reached oncomplete for request_404');
// console.log(data);
expect(data.error).toEqual('Image load error.');
resolve();
});
});
});
test('node buffers', () => {
const people = fs.readFileSync('./demoassets/People.jpg');
const people2 = fs.readFileSync('./demoassets/People2.jpg');
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(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();
});
});
});
});

2084
package-lock.json generated

File diff suppressed because it is too large Load Diff

17
package.json

@ -20,5 +20,20 @@
"bugs": { "bugs": {
"url": "https://github.com/Huddle/Resemble.js/issues" "url": "https://github.com/Huddle/Resemble.js/issues"
}, },
"homepage": "https://github.com/Huddle/Resemble.js" "homepage": "https://github.com/Huddle/Resemble.js",
"scripts": {
"test": "jest ./nodejs-tests",
"test-watch": "jest --watch ./nodejs-tests"
},
"devDependencies": {
"chai": "^3.4.1",
"jest": "^20.0.4",
"jest-cli": "^20.0.4"
},
"peerDependencies": {
"canvas": "^1.6.5"
},
"jest": {
"testEnvironment": "node"
}
} }

33
resemble.js

@ -61,7 +61,13 @@ URL: https://github.com/Huddle/Resemble.js
var errorPixel = errorPixelTransform.flat; var errorPixel = errorPixelTransform.flat;
var largeImageThreshold = 1200; var largeImageThreshold = 1200;
var useCrossOrigin = true; var useCrossOrigin = true;
var document = typeof window != "undefined" ? window.document : {}; 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();
}
};
var resemble = function( fileData ){ var resemble = function( fileData ){
@ -151,16 +157,24 @@ URL: https://github.com/Huddle/Resemble.js
function loadImageData( fileData, callback ){ function loadImageData( fileData, callback ){
var fileReader; var fileReader;
var hiddenImage = new Image(); var hiddenImage;
if (typeof Image !== 'undefined') {
hiddenImage = new Image();
} else {
var CanvasImage = require('canvas').Image;
hiddenImage = new CanvasImage();
hiddenImage.setAttribute = function setAttribute() { };
}
if(useCrossOrigin) { if(useCrossOrigin) {
hiddenImage.setAttribute('crossorigin', 'anonymous'); hiddenImage.setAttribute('crossorigin', 'anonymous');
} }
hiddenImage.onerror = function () { hiddenImage.onerror = function () {
hiddenImage.onerror = null; //fixes pollution between calls hiddenImage.onerror = null; //fixes pollution between calls
images.push({ error : "Image load error."}); images.push({ error : "Image load error."});
callback(); callback();
}; };
hiddenImage.onload = function() { hiddenImage.onload = function() {
@ -201,7 +215,9 @@ URL: https://github.com/Huddle/Resemble.js
images.push(fileData); images.push(fileData);
callback(fileData, fileData.width, fileData.height); 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 { } else {
fileReader = new FileReader(); fileReader = new FileReader();
fileReader.onload = function (event) { fileReader.onload = function (event) {
@ -482,6 +498,13 @@ URL: https://github.com/Huddle/Resemble.js
return hiddenCanvas.toDataURL("image/png"); return hiddenCanvas.toDataURL("image/png");
}; };
if (hiddenCanvas.toBuffer) {
data.getBuffer = function() {
context.putImageData(imgd, 0, 0);
return hiddenCanvas.toBuffer();
}
}
} }
function addLabel(text, context, hiddenCanvas){ function addLabel(text, context, hiddenCanvas){

79
tests/main_spec.js

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save