From 89656127d4bf795018bf2344ce6016ce8e9fcb4b Mon Sep 17 00:00:00 2001 From: Chris Deely Date: Thu, 19 Oct 2017 21:06:29 -0400 Subject: [PATCH 1/2] fix #10 with the addition of a `transparency` option to control the alpha of unchanged pixels --- README.md | 3 ++- index.js | 3 ++- lib/same-colors.js | 3 ++- test/data/diffs/different-0-alpha.png | Bin 0 -> 562 bytes test/data/diffs/different-50-alpha.png | Bin 0 -> 597 bytes test/test.js | 30 +++++++++++++++++++++++++ 6 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 test/data/diffs/different-0-alpha.png create mode 100644 test/data/diffs/different-50-alpha.png diff --git a/README.md b/README.md index 922314e..45d21a3 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,8 @@ await looksSame.createDiff({ current: '/path/to/current/image.png', diff: '/path/to/save/diff/to.png', highlightColor: '#ff00ff', // color to highlight the differences - strict: false, // strict comparsion + transparency: 255, //0-255, controls the alpha channel for unchanged pixels + strict: false, // strict comparison tolerance: 2.5, antialiasingTolerance: 0, ignoreAntialiasing: true, // ignore antialising by default diff --git a/index.js b/index.js index 0566ab6..24c7d65 100644 --- a/index.js +++ b/index.js @@ -77,6 +77,7 @@ const buildDiffImage = async (img1, img2, options) => { const minHeight = Math.min(img1.height, img2.height); const highlightColor = options.highlightColor; + const alphaLevel = isNaN(options.transparency) ? 255 : options.transparency; const resultBuffer = Buffer.alloc(width * height * 3); const setPixel = (buf, x, y, {R, G, B}) => { @@ -98,7 +99,7 @@ const buildDiffImage = async (img1, img2, options) => { if (!options.comparator({color1, color2, img1, img2, x, y, width, height})) { setPixel(resultBuffer, x, y, highlightColor); } else { - setPixel(resultBuffer, x, y, color1); + setPixel(resultBuffer, x, y, color1, alphaLevel); } }); diff --git a/lib/same-colors.js b/lib/same-colors.js index 6ab970e..10fc11c 100644 --- a/lib/same-colors.js +++ b/lib/same-colors.js @@ -6,5 +6,6 @@ module.exports = (data) => { return c1.R === c2.R && c1.G === c2.G - && c1.B === c2.B; + && c1.B === c2.B + && c1.A === c2.A; }; diff --git a/test/data/diffs/different-0-alpha.png b/test/data/diffs/different-0-alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..8e3b726e54d64343bc9bd4542141a317b7f2eb9e GIT binary patch literal 562 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-#^NA%Cx&(BWL^T}FfdWk9dNvV1jxdlK~3=B3ERzPNMYDuC(MQ%=Bu~mhw5?F;5kPQ;nS5g2gDap1~ zitr6kaLzAERWQ{v(KAr8<5EyiuqjGOvkG!?gK7uzY?U%fN(!v>^~=l4^~#O)@{7{- z4J|D#^$m>ljf`}GDs+o0^GXscbn}XpA%?)raY-#sF3Kz@$;{7F0GXSZlwVq6tE2?7 z2o50bEXhnm*pycc^%l^B`XCv7Lp=k1xYwo;fnwhr7vWw(ZuJ>>5Gy0I|;BNP%;^=|og#F1yO`O(6PF*MSHz=Qs zaA@Uu;i18!;mK?@sfRV>M8p4y0TKa|*xq;;i3KP!TM2P7dtGYS9R}u=sfe&mS;8pm ed5lRb}FfdWk9dNvV1jxdlK~3=B3ERzPNMYDuC(MQ%=Bu~mhw5?F;5kPQ;nS5g2gDap1~ zitr6kaLzAERWQ{v(KAr8<5EyiuqjGOvkG!?gK7uzY?U%fN(!v>^~=l4^~#O)@{7{- z4J|D#^$m>ljf`}GDs+o0^GXscbn}XpA%?)raY-#sF3Kz@$;{7F0GXSZlwVq6tE2?7 z2o50bEXhnm*pycc^%l^B`XCv7Lp=k1xY$bwTYck5fvxg@sk znR8<5r!^%~rHRj>Om33R)x8*l}d2H+Q zh2v%H)@g4Hb{UXkK-Bt`w^5gEmc61v}_ER?=Q8K_jTupOyvVLKvoP_R&Lp&}3i zX&`$&tMelF1cx_UGaT;x{nW8VseHeR&NGhAV;P0(Ta_QZ6K`|rKhSW5e*?3Ib=-Wj Qx1a>z>FVdQ&MBb@02LC=S^xk5 literal 0 HcmV?d00001 diff --git a/test/test.js b/test/test.js index b3da29b..fd68556 100644 --- a/test/test.js +++ b/test/test.js @@ -449,7 +449,37 @@ describe('createDiff', () => { expect(equal).to.equal(true); }); + it('should apply full transparency to the diff if set to 0', (done) => { + const _this = this; + looksSame.createDiff({ + reference: srcPath('ref.png'), + current: srcPath('different.png'), + diff: this.tempName, + highlightColor: '#ff00ff', + transparency: 0 + }, () => { + looksSame(imagePath('diffs/different-0-alpha.png'), _this.tempName, {strict: true}, (error, equal) => { + expect(equal).to.equal(true); + done(); + }); + }); + }); + it('should support partial transparency in the diff', (done) => { + const _this = this; + looksSame.createDiff({ + reference: srcPath('ref.png'), + current: srcPath('different.png'), + diff: this.tempName, + highlightColor: '#ff00ff', + transparency: 50 + }, () => { + looksSame(imagePath('diffs/different-50-alpha.png'), _this.tempName, {strict: true}, (error, equal) => { + expect(equal).to.equal(true); + done(); + }); + }); + }); it('should allow to build diff for taller images', async () => { await looksSame.createDiff({ reference: srcPath('ref.png'), From 5543015f0e3cf52863c771d8146bf405488ac847 Mon Sep 17 00:00:00 2001 From: Chris Deely Date: Thu, 26 Jan 2023 23:31:49 -0500 Subject: [PATCH 2/2] implement `matchingPixelAlpha` option --- README.md | 2 +- index.js | 19 +++++++++++-------- lib/image/image.js | 3 ++- test/test.js | 44 ++++++++++++++++++++++++++------------------ 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 45d21a3..f64347f 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ await looksSame.createDiff({ current: '/path/to/current/image.png', diff: '/path/to/save/diff/to.png', highlightColor: '#ff00ff', // color to highlight the differences - transparency: 255, //0-255, controls the alpha channel for unchanged pixels + matchingPixelAlpha: 255, //0-255, controls the alpha channel for unchanged pixels. setting to 0 will remove all matching pixels from the diff strict: false, // strict comparison tolerance: 2.5, antialiasingTolerance: 0, diff --git a/index.js b/index.js index 24c7d65..a2d6100 100644 --- a/index.js +++ b/index.js @@ -77,14 +77,15 @@ const buildDiffImage = async (img1, img2, options) => { const minHeight = Math.min(img1.height, img2.height); const highlightColor = options.highlightColor; - const alphaLevel = isNaN(options.transparency) ? 255 : options.transparency; - const resultBuffer = Buffer.alloc(width * height * 3); + const alphaLevel = isNaN(options.matchingPixelAlpha) ? 255 : options.matchingPixelAlpha; + const resultBuffer = Buffer.alloc(width * height * 4); - const setPixel = (buf, x, y, {R, G, B}) => { - const pixelInd = (y * width + x) * 3; + const setPixel = (buf, x, y, {R, G, B, A = 255}) => { + const pixelInd = (y * width + x) * 4; buf[pixelInd] = R; buf[pixelInd + 1] = G; buf[pixelInd + 2] = B; + buf[pixelInd + 3] = A; }; await iterateRect(width, height, (x, y) => { @@ -99,11 +100,11 @@ const buildDiffImage = async (img1, img2, options) => { if (!options.comparator({color1, color2, img1, img2, x, y, width, height})) { setPixel(resultBuffer, x, y, highlightColor); } else { - setPixel(resultBuffer, x, y, color1, alphaLevel); + setPixel(resultBuffer, x, y, {...color1, A:alphaLevel}); } }); - return img.fromBuffer(resultBuffer, {raw: {width, height, channels: 3}}); + return img.fromBuffer(resultBuffer, {raw: {width, height, channels: 4}}); }; const parseColorString = (str) => { @@ -135,7 +136,8 @@ const prepareOpts = (opts) => { return _.defaults(opts, { ignoreCaret: true, ignoreAntialiasing: true, - antialiasingTolerance: 0 + antialiasingTolerance: 0, + matchingPixelAlpha: 255 }); }; @@ -217,7 +219,8 @@ exports.createDiff = async function saveDiff(opts) { const {first, second} = await utils.readPair(image1, image2); const diffImage = await buildDiffImage(first, second, { highlightColor: parseColorString(opts.highlightColor), - comparator: createComparator(first, second, opts) + comparator: createComparator(first, second, opts), + matchingPixelAlpha: opts.matchingPixelAlpha }); return opts.diff === undefined diff --git a/lib/image/image.js b/lib/image/image.js index 0f01d4e..f56a777 100644 --- a/lib/image/image.js +++ b/lib/image/image.js @@ -23,7 +23,8 @@ module.exports = class Image extends ImageBase { return { R: this._buffer[idx], G: this._buffer[idx + 1], - B: this._buffer[idx + 2] + B: this._buffer[idx + 2], + A: this._channels === 4 ? this._buffer[idx + 3] : 255 }; } diff --git a/test/test.js b/test/test.js index fd68556..498e635 100644 --- a/test/test.js +++ b/test/test.js @@ -449,37 +449,45 @@ describe('createDiff', () => { expect(equal).to.equal(true); }); - it('should apply full transparency to the diff if set to 0', (done) => { - const _this = this; - looksSame.createDiff({ + it('should make all matching pixels fully transparent is matchingPixelAlpha set to 0', async () => { + await looksSame.createDiff({ reference: srcPath('ref.png'), current: srcPath('different.png'), diff: this.tempName, highlightColor: '#ff00ff', - transparency: 0 - }, () => { - looksSame(imagePath('diffs/different-0-alpha.png'), _this.tempName, {strict: true}, (error, equal) => { - expect(equal).to.equal(true); - done(); - }); + matchingPixelAlpha: 0 }); + + const {equal} = await looksSame(imagePath('diffs/different-0-alpha.png'), this.tempName, {strict: true}); + expect(equal).to.equal(true); }); - it('should support partial transparency in the diff', (done) => { - const _this = this; - looksSame.createDiff({ + it('should support partial matchingPixelAlpha in the diff', async () => { + await looksSame.createDiff({ reference: srcPath('ref.png'), current: srcPath('different.png'), diff: this.tempName, highlightColor: '#ff00ff', - transparency: 50 - }, () => { - looksSame(imagePath('diffs/different-50-alpha.png'), _this.tempName, {strict: true}, (error, equal) => { - expect(equal).to.equal(true); - done(); - }); + matchingPixelAlpha: 50 }); + + const {equal} = await looksSame(imagePath('diffs/different-50-alpha.png'), this.tempName, {strict: true}); + expect(equal).to.equal(true); }); + + it('should default to no transparency in the diff if the option is omitted', async () => { + await looksSame.createDiff({ + reference: srcPath('ref.png'), + current: srcPath('different.png'), + diff: this.tempName, + highlightColor: '#ff00ff', + matchingPixelAlpha: undefined + }); + + const {equal} = await looksSame(imagePath('diffs/small-magenta.png'), this.tempName, {strict: true}); + expect(equal).to.equal(true); + }); + it('should allow to build diff for taller images', async () => { await looksSame.createDiff({ reference: srcPath('ref.png'),