image-comparator
Advanced tools
Comparing version 1.4.0 to 1.5.0
61
index.js
const { | ||
MIMES, | ||
MODES, | ||
getDimensions, | ||
@@ -7,10 +9,21 @@ BYTE_COMPARERS, | ||
extractBitmapAndChannelCount, | ||
MIMES, | ||
} = require("./lib"); | ||
module.exports = { | ||
compare: async (buffer1, buffer2, comparator) => { | ||
compare: async (buffer1, buffer2, options = {}) => { | ||
const isInterformatComparison = | ||
buffer1[0] === MIMES.WEBP && buffer1[0] !== buffer2[0]; | ||
if (typeof options === "function") { | ||
console.warn( | ||
`Third argument as function deprecated. | ||
Update your code to use third argument | ||
as object with compareFunction property instead` | ||
); | ||
options = { | ||
compareFunction: options, | ||
}; | ||
} | ||
if (isInterformatComparison) { | ||
@@ -23,18 +36,38 @@ throw new Error("Interformat webp comparison not supported"); | ||
...(await Promise.all([compareImpl(buffer1), compareImpl(buffer2)])), | ||
comparator || BYTE_COMPARERS[buffer1[0]], | ||
comparator || BYTE_COMPARERS[buffer2[0]], | ||
options.compareFunction || BYTE_COMPARERS[buffer1[0]], | ||
options.compareFunction || BYTE_COMPARERS[buffer2[0]], | ||
buffer1[0] | ||
) || | ||
(!comparator && | ||
areBuffersEqual( | ||
...(await Promise.all([ | ||
grayscaleCompareImpl(buffer1), | ||
grayscaleCompareImpl(buffer2), | ||
])), | ||
(byte1, byte2) => Math.abs(byte1 - byte2) < 32, | ||
(byte1, byte2) => Math.abs(byte1 - byte2) < 32, | ||
buffer1[0] | ||
)) | ||
!!( | ||
(options.modes & MODES.CHECK_GRAYSCALE && | ||
areBuffersEqual( | ||
...(await Promise.all([ | ||
grayscaleCompareImpl(buffer1), | ||
grayscaleCompareImpl(buffer2), | ||
])), | ||
(byte1, byte2) => Math.abs(byte1 - byte2) < 32, | ||
(byte1, byte2) => Math.abs(byte1 - byte2) < 32, | ||
buffer1[0] | ||
)) || | ||
(options.modes & MODES.CHECK_HUE && | ||
new Array(254) | ||
.fill(null) | ||
.map((_, index) => { | ||
const huedBuffer = new Uint8Array( | ||
Array.from(buffer1).map((byte) => byte + index + 1) | ||
); | ||
return areBuffersEqual( | ||
huedBuffer, | ||
buffer2, | ||
BYTE_COMPARERS[buffer1[0]], | ||
BYTE_COMPARERS[buffer2[0]], | ||
buffer1[0] | ||
); | ||
}) | ||
.some(Boolean)) | ||
) | ||
); | ||
}, | ||
MODES, | ||
}; | ||
@@ -41,0 +74,0 @@ |
@@ -21,4 +21,4 @@ const MIMES = { | ||
const EXIF_MARKER = "45786966"; | ||
const EXIF_HEADER_BYTES = 6; | ||
const EXIF_MARKER = "45786966"; | ||
const APP1_DATA_SIZE_BYTES = 2; | ||
@@ -33,4 +33,10 @@ const TIFF_BYTE_ALIGN_BYTES = 2; | ||
const MODES = { | ||
CHECK_HUE: 2 >> 0, | ||
CHECK_GRAYSCALE: 2 >> 1, | ||
}; | ||
module.exports = { | ||
MIMES, | ||
MODES, | ||
EXIF_MARKER, | ||
@@ -37,0 +43,0 @@ HIT_THRESHOLD, |
const Resize = require("./Resize"); | ||
const { MIMES } = require("./enums"); | ||
const parseJpg = require("./jpgparse"); | ||
const { parse: parsePng } = require("./pngparse"); | ||
const { WebPDecoder, WebPRiffParser } = require("./webpparse"); | ||
const { parse: parsePng } = require("./pngparse"); | ||
@@ -7,0 +7,0 @@ const parseMapper = { |
{ | ||
"name": "image-comparator", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"description": "Compares images by resizing without dependencies", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -57,7 +57,5 @@ # image-comparator | ||
const areSame = await comparator.compare( | ||
imageBuffer1, | ||
imageBuffer2, | ||
compareFunction | ||
); | ||
const areSame = await comparator.compare(imageBuffer1, imageBuffer2, { | ||
compareFunction, | ||
}); | ||
@@ -87,7 +85,5 @@ if (areSame) { | ||
const areSame = await comparator.compare( | ||
imageBuffer1, | ||
imageBuffer2, | ||
compareFunction | ||
); | ||
const areSame = await comparator.compare(imageBuffer1, imageBuffer2, { | ||
compareFunction, | ||
}); | ||
@@ -104,16 +100,79 @@ if (areSame) { | ||
Hue detection: | ||
```js | ||
const fs = require("node:fs"); | ||
const comparator = require("image-comparator"); | ||
const imagePath1 = "path/to/same.png"; | ||
const imagePath2 = "path/to/same.jpg"; | ||
const imageBuffer1 = fs.readFileSync(imagePath1); | ||
const imageBuffer2 = fs.readFileSync(imagePath2); | ||
const compare = async () => { | ||
const compareFunction = (byte1, byte2) => Math.abs(byte1 - byte2) < 128; // If color difference is small enough | ||
const areSame = await comparator.compare(imageBuffer1, imageBuffer2, { | ||
compareFunction, | ||
modes: comparator.MODES.CHECK_HUE, | ||
}); | ||
if (areSame) { | ||
console.log("Images are the same"); | ||
} else { | ||
console.log("Images are different"); | ||
} | ||
}; | ||
compare(); | ||
``` | ||
Grayscale detection: | ||
```js | ||
const fs = require("node:fs"); | ||
const comparator = require("image-comparator"); | ||
const imagePath1 = "path/to/same.png"; | ||
const imagePath2 = "path/to/same.jpg"; | ||
const imageBuffer1 = fs.readFileSync(imagePath1); | ||
const imageBuffer2 = fs.readFileSync(imagePath2); | ||
const compare = async () => { | ||
const compareFunction = (byte1, byte2) => Math.abs(byte1 - byte2) < 128; // If color difference is small enough | ||
const areSame = await comparator.compare(imageBuffer1, imageBuffer2, { | ||
compareFunction, | ||
modes: comparator.MODES.CHECK_GRAYSCALE, | ||
}); | ||
if (areSame) { | ||
console.log("Images are the same"); | ||
} else { | ||
console.log("Images are different"); | ||
} | ||
}; | ||
compare(); | ||
``` | ||
# API | ||
```js | ||
compare: ( | ||
buffer1: Buffer, | ||
buffer2: Buffer, | ||
compareFunction: (byte1, byte2) => boolean | ||
) => bool; | ||
compare: (buffer1: Buffer, buffer2: Buffer, options: Options) => bool; | ||
type Options = { | ||
compareFunction: (byte1, byte2) => boolean, | ||
modes: MODES.CHECK_HUE | MODES.CHECK_GRAYSCALE, | ||
}; | ||
``` | ||
Compares two images. | ||
Compares two images. Can accept modes to detect hue or grayscale changes. | ||
Throws if WEBP image is compared with imag of another extension. | ||
Throws if WEBP image is compared with image of another extension. | ||
Warns about deprecated third argument if `compareFunction` passed outside the object as `function`. | ||
## Supported extensions | ||
@@ -133,3 +192,3 @@ | ||
- May produce false positives for comparison of images of different format origins due to inconsistent resulting bitmap size (use `compareFunction` to avoid this) | ||
- Can work with interformat images, but WEBP is not supported for this at the moment | ||
- May produce false positives for comparison of images of different format origins due to inconsistent resulting bitmap size. Use `compareFunction` in `options` third argument as mitigation. | ||
- Can work with any supported interformat images, but `WEBP` |
@@ -7,2 +7,3 @@ const assert = require("node:assert"); | ||
const { compare } = require("../index"); | ||
const { MODES } = require("../lib"); | ||
@@ -43,3 +44,5 @@ const commonImagesPath = ["test", "images"]; | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
@@ -56,3 +59,5 @@ assert.strictEqual(actual, expected); | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
@@ -62,3 +67,3 @@ assert.strictEqual(actual, expected); | ||
it("should detect same images with grayscale", async () => { | ||
it("should detect same images with grayscale with CHECK_GRAYSCALE flag", async () => { | ||
const expected = true; | ||
@@ -69,3 +74,5 @@ const commonPathSegments = [...commonPngImagesPath, "same-with-grayscale"]; | ||
const actual = await compare(image1, image2); | ||
const actual = await compare(image1, image2, { | ||
modes: MODES.CHECK_GRAYSCALE, | ||
}); | ||
@@ -108,3 +115,5 @@ assert.strictEqual(actual, expected); | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
@@ -121,6 +130,26 @@ assert.strictEqual(actual, expected); | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
assert.strictEqual(actual, expected); | ||
}); | ||
it("should detect same images with changed hue", async () => { | ||
const expected = true; | ||
const comparator = (byte1, byte2) => Math.abs(byte1 - byte2) > 255; | ||
const commonPathSegments = [ | ||
...commonJpgImagesPath, | ||
"same-with-changed-hue", | ||
]; | ||
const image1 = readFileSync(join(...commonPathSegments, "image1.jpg")); | ||
const image2 = readFileSync(join(...commonPathSegments, "image2.jpg")); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
modes: MODES.CHECK_HUE, | ||
}); | ||
assert.strictEqual(actual, expected); | ||
}); | ||
}); | ||
@@ -160,3 +189,5 @@ | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
@@ -173,3 +204,5 @@ assert.strictEqual(actual, expected); | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
@@ -233,3 +266,5 @@ assert.strictEqual(actual, expected); | ||
const actual = await compare(image1, image2, comparator); | ||
const actual = await compare(image1, image2, { | ||
compareFunction: comparator, | ||
}); | ||
@@ -236,0 +271,0 @@ assert.strictEqual(actual, expected); |
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
191134
34
3188
191