looks-same
Advanced tools
Comparing version 7.3.0 to 8.0.0
@@ -5,2 +5,15 @@ # Changelog | ||
## [8.0.0](https://github.com/gemini-testing/looks-same/compare/v7.3.0...v8.0.0) (2022-09-19) | ||
### ⚠ BREAKING CHANGES | ||
* drop support of node versions less than 12 | ||
* dropped old node-style callback interface support | ||
### Features | ||
* async-await interface ([b33a6f9](https://github.com/gemini-testing/looks-same/commit/b33a6f925701a3ed6cfe9479cf3d8ad290320be5)) | ||
* increase supported node version up to 12 ([ae1e4b2](https://github.com/gemini-testing/looks-same/commit/ae1e4b265ee3f7af25e526256fdd4970b568ff7a)) | ||
## [7.3.0](https://github.com/gemini-testing/looks-same/compare/v7.2.4...v7.3.0) (2021-02-03) | ||
@@ -7,0 +20,0 @@ |
165
index.js
@@ -51,23 +51,25 @@ 'use strict'; | ||
const iterateRect = (width, height, callback, endCallback) => { | ||
const processRow = (y) => { | ||
setImmediate(() => { | ||
for (let x = 0; x < width; x++) { | ||
callback(x, y); | ||
} | ||
const iterateRect = async (width, height, callback) => { | ||
return new Promise((resolve) => { | ||
const processRow = (y) => { | ||
setImmediate(() => { | ||
for (let x = 0; x < width; x++) { | ||
callback(x, y); | ||
} | ||
y++; | ||
y++; | ||
if (y < height) { | ||
processRow(y); | ||
} else { | ||
endCallback(); | ||
} | ||
}); | ||
}; | ||
if (y < height) { | ||
processRow(y); | ||
} else { | ||
resolve(); | ||
} | ||
}); | ||
}; | ||
processRow(0); | ||
processRow(0); | ||
}); | ||
}; | ||
const buildDiffImage = (png1, png2, options, callback) => { | ||
const buildDiffImage = async (png1, png2, options) => { | ||
const width = Math.max(png1.width, png2.width); | ||
@@ -80,3 +82,3 @@ const height = Math.max(png1.height, png2.height); | ||
iterateRect(width, height, (x, y) => { | ||
await iterateRect(width, height, (x, y) => { | ||
if (x >= minWidth || y >= minHeight) { | ||
@@ -95,3 +97,5 @@ result.setPixel(x, y, highlightColor); | ||
} | ||
}, () => callback(result)); | ||
}); | ||
return result; | ||
}; | ||
@@ -143,107 +147,74 @@ | ||
module.exports = exports = async function looksSame(image1, image2, opts, callback) { | ||
if (!callback) { | ||
callback = opts; | ||
opts = {}; | ||
} | ||
module.exports = exports = async function looksSame(image1, image2, opts = {}) { | ||
opts = prepareOpts(opts); | ||
[image1, image2] = utils.formatImages(image1, image2); | ||
try { | ||
const {first, second} = await utils.readPair(image1, image2, utils.readBufferCb); | ||
const areBuffersEqual = utils.areBuffersEqual(first, second); | ||
const {first, second} = await utils.readPair(image1, image2, utils.readBufferCb); | ||
const areBuffersEqual = utils.areBuffersEqual(first, second); | ||
const refImg = {size: {width: first.width, height: first.height}}; | ||
const metaInfo = {refImg}; | ||
const refImg = {size: {width: first.width, height: first.height}}; | ||
const metaInfo = {refImg}; | ||
if (areBuffersEqual) { | ||
const diffBounds = (new DiffArea()).area; | ||
process.nextTick(() => callback(null, {equal: true, metaInfo, diffBounds, diffClusters: [diffBounds]})); | ||
if (areBuffersEqual) { | ||
const diffBounds = (new DiffArea()).area; | ||
return; | ||
} | ||
return {equal: true, metaInfo, diffBounds, diffClusters: [diffBounds]}; | ||
} | ||
if (first.width !== second.width || first.height !== second.height) { | ||
const diffBounds = getMaxDiffBounds(first, second); | ||
process.nextTick(() => callback(null, {equal: false, metaInfo, diffBounds, diffClusters: [diffBounds]})); | ||
if (first.width !== second.width || first.height !== second.height) { | ||
const diffBounds = getMaxDiffBounds(first, second); | ||
return; | ||
} | ||
return {equal: false, metaInfo, diffBounds, diffClusters: [diffBounds]}; | ||
} | ||
const {first: png1, second: png2} = await utils.readPair( | ||
{...image1, source: first.buffer}, | ||
{...image2, source: second.buffer}, | ||
utils.readPngCb | ||
); | ||
const {first: png1, second: png2} = await utils.readPair( | ||
{...image1, source: first.buffer}, | ||
{...image2, source: second.buffer}, | ||
utils.readPngCb | ||
); | ||
const comparator = createComparator(png1, png2, opts); | ||
const {stopOnFirstFail, shouldCluster, clustersSize} = opts; | ||
const comparator = createComparator(png1, png2, opts); | ||
const {stopOnFirstFail, shouldCluster, clustersSize} = opts; | ||
utils.getDiffPixelsCoords(png1, png2, comparator, {stopOnFirstFail, shouldCluster, clustersSize}, ({diffArea, diffClusters}) => { | ||
const diffBounds = diffArea.area; | ||
const equal = diffArea.isEmpty(); | ||
const {diffArea, diffClusters} = await utils.getDiffPixelsCoords(png1, png2, comparator, {stopOnFirstFail, shouldCluster, clustersSize}); | ||
const diffBounds = diffArea.area; | ||
const equal = diffArea.isEmpty(); | ||
callback(null, {equal, metaInfo, diffBounds, diffClusters}); | ||
}); | ||
} catch (err) { | ||
return callback(err); | ||
} | ||
return {equal, metaInfo, diffBounds, diffClusters}; | ||
}; | ||
exports.getDiffArea = function(image1, image2, opts, callback) { | ||
if (!callback) { | ||
callback = opts; | ||
opts = {}; | ||
} | ||
exports.getDiffArea = async function(image1, image2, opts = {}) { | ||
opts = prepareOpts(opts); | ||
[image1, image2] = utils.formatImages(image1, image2); | ||
utils | ||
.readPair(image1, image2) | ||
.then(({first, second}) => { | ||
if (first.width !== second.width || first.height !== second.height) { | ||
return process.nextTick(() => callback(null, getMaxDiffBounds(first, second))); | ||
} | ||
const {first, second} = await utils.readPair(image1, image2); | ||
const comparator = createComparator(first, second, opts); | ||
if (first.width !== second.width || first.height !== second.height) { | ||
return getMaxDiffBounds(first, second); | ||
} | ||
utils.getDiffPixelsCoords(first, second, comparator, opts, ({diffArea}) => { | ||
if (diffArea.isEmpty()) { | ||
return callback(null, null); | ||
} | ||
const comparator = createComparator(first, second, opts); | ||
callback(null, diffArea.area); | ||
}); | ||
}) | ||
.catch(error => { | ||
callback(error); | ||
}); | ||
const {diffArea} = await utils.getDiffPixelsCoords(first, second, comparator, opts); | ||
if (diffArea.isEmpty()) { | ||
return null; | ||
} | ||
return diffArea.area; | ||
}; | ||
exports.createDiff = function saveDiff(opts, callback) { | ||
exports.createDiff = async function saveDiff(opts) { | ||
opts = prepareOpts(opts); | ||
const [image1, image2] = utils.formatImages(opts.reference, opts.current); | ||
const {first, second} = await utils.readPair(image1, image2); | ||
const diffImage = await buildDiffImage(first, second, { | ||
highlightColor: parseColorString(opts.highlightColor), | ||
comparator: createComparator(first, second, opts) | ||
}); | ||
utils | ||
.readPair(image1, image2) | ||
.then(({first, second}) => { | ||
const diffOptions = { | ||
highlightColor: parseColorString(opts.highlightColor), | ||
comparator: createComparator(first, second, opts) | ||
}; | ||
buildDiffImage(first, second, diffOptions, (result) => { | ||
if (opts.diff === undefined) { | ||
result.createBuffer(callback); | ||
} else { | ||
result.save(opts.diff, callback); | ||
} | ||
}); | ||
}) | ||
.catch(error => { | ||
callback(error); | ||
}); | ||
return opts.diff === undefined | ||
? diffImage.createBuffer() | ||
: diffImage.save(opts.diff); | ||
}; | ||
@@ -250,0 +221,0 @@ |
@@ -35,18 +35,18 @@ 'use strict'; | ||
save(path, callback) { | ||
async save(path) { | ||
const writeStream = fs.createWriteStream(path); | ||
this._png.pack().pipe(writeStream); | ||
writeStream.on('error', (error) => callback(error)); | ||
writeStream.on('finish', () => callback(null)); | ||
return new Promise((resolve, reject) => { | ||
writeStream.on('error', (error) => reject(error)); | ||
writeStream.on('finish', () => resolve(null)); | ||
}); | ||
} | ||
createBuffer(callback) { | ||
this._png.pack().pipe(concat(gotDiff)); | ||
this._png.on('error', (error) => callback(error, null)); | ||
function gotDiff(data) { | ||
callback(null, data); | ||
} | ||
async createBuffer() { | ||
return new Promise((resolve, reject) => { | ||
this._png.pack().pipe(concat(resolve)); | ||
this._png.on('error', reject); | ||
}); | ||
} | ||
}; |
@@ -30,8 +30,3 @@ 'use strict'; | ||
exports.getDiffPixelsCoords = (png1, png2, predicate, opts, callback) => { | ||
if (!callback) { | ||
callback = opts; | ||
opts = {}; | ||
} | ||
exports.getDiffPixelsCoords = async (png1, png2, predicate, opts = {}) => { | ||
const stopOnFirstFail = opts.hasOwnProperty('stopOnFirstFail') ? opts.stopOnFirstFail : false; | ||
@@ -45,39 +40,41 @@ | ||
const processRow = (y) => { | ||
setImmediate(() => { | ||
for (let x = 0; x < width; x++) { | ||
const color1 = png1.getPixel(x, y); | ||
const color2 = png2.getPixel(x, y); | ||
return new Promise((resolve) => { | ||
const processRow = (y) => { | ||
setImmediate(() => { | ||
for (let x = 0; x < width; x++) { | ||
const color1 = png1.getPixel(x, y); | ||
const color2 = png2.getPixel(x, y); | ||
const result = predicate({ | ||
color1, color2, | ||
png1, png2, | ||
x, y, | ||
width, height | ||
}); | ||
const result = predicate({ | ||
color1, color2, | ||
png1, png2, | ||
x, y, | ||
width, height | ||
}); | ||
if (!result) { | ||
const {x: actX, y: actY} = png1.getActualCoord(x, y); | ||
diffArea.update(actX, actY); | ||
if (opts.shouldCluster) { | ||
diffClusters.update(actX, actY); | ||
} | ||
if (!result) { | ||
const {x: actX, y: actY} = png1.getActualCoord(x, y); | ||
diffArea.update(actX, actY); | ||
if (opts.shouldCluster) { | ||
diffClusters.update(actX, actY); | ||
} | ||
if (stopOnFirstFail) { | ||
return callback({diffArea, diffClusters: getDiffClusters(diffClusters, diffArea, opts)}); | ||
if (stopOnFirstFail) { | ||
return resolve({diffArea, diffClusters: getDiffClusters(diffClusters, diffArea, opts)}); | ||
} | ||
} | ||
} | ||
} | ||
y++; | ||
y++; | ||
if (y < height) { | ||
processRow(y); | ||
} else { | ||
callback({diffArea, diffClusters: getDiffClusters(diffClusters, diffArea, opts)}); | ||
} | ||
}); | ||
}; | ||
if (y < height) { | ||
processRow(y); | ||
} else { | ||
resolve({diffArea, diffClusters: getDiffClusters(diffClusters, diffArea, opts)}); | ||
} | ||
}); | ||
}; | ||
processRow(0); | ||
processRow(0); | ||
}); | ||
}; | ||
@@ -84,0 +81,0 @@ |
{ | ||
"name": "looks-same", | ||
"version": "7.3.0", | ||
"version": "8.0.0", | ||
"description": "Pure node.js library for comparing PNG-images, taking into account human color perception.", | ||
@@ -27,3 +27,2 @@ "main": "index.js", | ||
"gm": "^1.23.1", | ||
"matcha": "^0.7.0", | ||
"mocha": "^5.2.0", | ||
@@ -40,7 +39,6 @@ "proxyquire": "^1.7.10", | ||
"test": "npm run test-unit && npm run lint", | ||
"bench": "matcha benchmark/*", | ||
"release": "standard-version" | ||
}, | ||
"engines": { | ||
"node": ">= 8.0.0" | ||
"node": ">= 12.0.0" | ||
}, | ||
@@ -47,0 +45,0 @@ "author": "Sergey Tatarintsev <sevinf@yandex-team.ru> (https://github.com/SevInf)", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12
46574
28
1013