Skip to content

Commit 89a35ef

Browse files
committed
add first-class TypeScript types
1 parent 1b4d033 commit 89a35ef

File tree

6 files changed

+113
-29
lines changed

6 files changed

+113
-29
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ node_modules
44
.nyc_output
55
coverage
66
tmp
7+
index.d.ts

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
ISC License
22

3-
Copyright (c) 2024, Mapbox
3+
Copyright (c) 2025, Mapbox
44

55
Permission to use, copy, modify, and/or distribute this software for any purpose
66
with or without fee is hereby granted, provided that the above copyright notice

index.js

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
1-
1+
/**
2+
* Compare two equally sized images, pixel by pixel.
3+
*
4+
* @param {Uint8Array | Uint8ClampedArray} img1 First image data.
5+
* @param {Uint8Array | Uint8ClampedArray} img2 Second image data.
6+
* @param {Uint8Array | Uint8ClampedArray | void} output Image data to write the diff to, if provided.
7+
* @param {number} width Input images width.
8+
* @param {number} height Input images height.
9+
*
10+
* @param {Object} [options]
11+
* @param {number} [options.threshold=0.1] Matching threshold (0 to 1); smaller is more sensitive.
12+
* @param {boolean} [options.includeAA=false] Whether to skip anti-aliasing detection.
13+
* @param {number} [options.alpha=0.1] Opacity of original image in diff output.
14+
* @param {[number, number, number]} [options.aaColor=[255, 255, 0]] Color of anti-aliased pixels in diff output.
15+
* @param {[number, number, number]} [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.
16+
* @param {[number, number, number]} [options.diffColorAlt=options.diffColor] Whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two.
17+
* @param {boolean} [options.diffMask=false] Draw the diff over a transparent background (a mask).
18+
*
19+
* @return {number} The number of mismatched pixels.
20+
*/
221
export default function pixelmatch(img1, img2, output, width, height, options = {}) {
322
const {
4-
threshold = 0.1, // matching threshold (0 to 1); smaller is more sensitive
5-
includeAA = false, // whether to skip anti-aliasing detection
6-
alpha = 0.1, // opacity of original image in diff output
7-
aaColor = [255, 255, 0], // color of anti-aliased pixels in diff output
8-
diffColor = [255, 0, 0], // color of different pixels in diff output
9-
diffColorAlt = null, // whether to detect dark on light differences between img1 and img2 and set an alternative color to differentiate between the two
10-
diffMask = false // draw the diff over a transparent background (a mask)
23+
threshold = 0.1,
24+
alpha = 0.1,
25+
aaColor = [255, 255, 0],
26+
diffColor = [255, 0, 0],
27+
includeAA, diffColorAlt, diffMask
1128
} = options;
1229

1330
if (!isPixelData(img1) || !isPixelData(img2) || (output && !isPixelData(output)))
@@ -54,8 +71,7 @@ export default function pixelmatch(img1, img2, output, width, height, options =
5471
// the color difference is above the threshold
5572
if (Math.abs(delta) > maxDelta) {
5673
// check it's a real rendering difference or just anti-aliasing
57-
if (!includeAA && (antialiased(img1, x, y, width, height, img2) ||
58-
antialiased(img2, x, y, width, height, img1))) {
74+
if (!includeAA && (antialiased(img1, x, y, width, height, img2) || antialiased(img2, x, y, width, height, img1))) {
5975
// one of the pixels is anti-aliasing; draw as yellow and do not count as difference
6076
// note that we do not include such pixels in a mask
6177
if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);
@@ -83,14 +99,22 @@ export default function pixelmatch(img1, img2, output, width, height, options =
8399
return diff;
84100
}
85101

102+
/** @param {Uint8Array | Uint8ClampedArray} arr */
86103
function isPixelData(arr) {
87104
// work around instanceof Uint8Array not working properly in some Jest environments
88-
return ArrayBuffer.isView(arr) && arr.constructor.BYTES_PER_ELEMENT === 1;
105+
return ArrayBuffer.isView(arr) && arr.BYTES_PER_ELEMENT === 1;
89106
}
90107

91-
// check if a pixel is likely a part of anti-aliasing;
92-
// based on "Anti-aliased Pixel and Intensity Slope Detector" paper by V. Vysniauskas, 2009
93-
108+
/**
109+
* Check if a pixel is likely a part of anti-aliasing;
110+
* based on "Anti-aliased Pixel and Intensity Slope Detector" paper by V. Vysniauskas, 2009
111+
* @param {Uint8Array | Uint8ClampedArray} img
112+
* @param {number} x1
113+
* @param {number} y1
114+
* @param {number} width
115+
* @param {number} height
116+
* @param {Uint8Array | Uint8ClampedArray} img2
117+
*/
94118
function antialiased(img, x1, y1, width, height, img2) {
95119
const x0 = Math.max(x1 - 1, 0);
96120
const y0 = Math.max(y1 - 1, 0);
@@ -100,7 +124,10 @@ function antialiased(img, x1, y1, width, height, img2) {
100124
let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
101125
let min = 0;
102126
let max = 0;
103-
let minX, minY, maxX, maxY;
127+
let minX = 0;
128+
let minY = 0;
129+
let maxX = 0;
130+
let maxY = 0;
104131

105132
// go through 8 adjacent pixels
106133
for (let x = x0; x <= x2; x++) {
@@ -140,7 +167,14 @@ function antialiased(img, x1, y1, width, height, img2) {
140167
(hasManySiblings(img, maxX, maxY, width, height) && hasManySiblings(img2, maxX, maxY, width, height));
141168
}
142169

143-
// check if a pixel has 3+ adjacent pixels of the same color.
170+
/**
171+
* Check if a pixel has 3+ adjacent pixels of the same color.
172+
* @param {Uint8Array | Uint8ClampedArray} img
173+
* @param {number} x1
174+
* @param {number} y1
175+
* @param {number} width
176+
* @param {number} height
177+
*/
144178
function hasManySiblings(img, x1, y1, width, height) {
145179
const x0 = Math.max(x1 - 1, 0);
146180
const y0 = Math.max(y1 - 1, 0);
@@ -167,9 +201,15 @@ function hasManySiblings(img, x1, y1, width, height) {
167201
return false;
168202
}
169203

170-
// calculate color difference according to the paper "Measuring perceived color difference
171-
// using YIQ NTSC transmission color space in mobile applications" by Y. Kotsarenko and F. Ramos
172-
204+
/**
205+
* Calculate color difference according to the paper "Measuring perceived color difference
206+
* using YIQ NTSC transmission color space in mobile applications" by Y. Kotsarenko and F. Ramos
207+
* @param {Uint8Array | Uint8ClampedArray} img1
208+
* @param {Uint8Array | Uint8ClampedArray} img2
209+
* @param {number} k
210+
* @param {number} m
211+
* @param {boolean} yOnly
212+
*/
173213
function colorDelta(img1, img2, k, m, yOnly) {
174214
const r1 = img1[k];
175215
const g1 = img1[k + 1];
@@ -209,17 +249,27 @@ function colorDelta(img1, img2, k, m, yOnly) {
209249
return y > 0 ? -delta : delta;
210250
}
211251

252+
/**
253+
* @param {Uint8Array | Uint8ClampedArray} output
254+
* @param {number} pos
255+
* @param {number} r
256+
* @param {number} g
257+
* @param {number} b
258+
*/
212259
function drawPixel(output, pos, r, g, b) {
213260
output[pos + 0] = r;
214261
output[pos + 1] = g;
215262
output[pos + 2] = b;
216263
output[pos + 3] = 255;
217264
}
218265

266+
/**
267+
* @param {Uint8Array | Uint8ClampedArray} img
268+
* @param {number} i
269+
* @param {number} alpha
270+
* @param {Uint8Array | Uint8ClampedArray} output
271+
*/
219272
function drawGrayPixel(img, i, alpha, output) {
220-
const r = img[i + 0];
221-
const g = img[i + 1];
222-
const b = img[i + 2];
223-
const val = 255 + (r * 0.29889531 + g * 0.58662247 + b * 0.11448223 - 255) * alpha * img[i + 3] / 255;
273+
const val = 255 + (img[i] * 0.29889531 + img[i + 1] * 0.58662247 + img[i + 2] * 0.11448223 - 255) * alpha * img[i + 3] / 255;
224274
drawPixel(output, i, val, val, val);
225275
}

package-lock.json

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,25 @@
44
"type": "module",
55
"description": "The smallest and fastest pixel-level image comparison library.",
66
"main": "index.js",
7+
"types": "index.d.ts",
78
"bin": {
89
"pixelmatch": "bin/pixelmatch"
910
},
1011
"files": [
11-
"bin/pixelmatch"
12+
"bin/pixelmatch",
13+
"index.d.ts"
1214
],
1315
"dependencies": {
1416
"pngjs": "^7.0.0"
1517
},
1618
"devDependencies": {
1719
"eslint": "^9.20.1",
18-
"eslint-config-mourner": "^4.0.2"
20+
"eslint-config-mourner": "^4.0.2",
21+
"typescript": "^5.7.3"
1922
},
2023
"scripts": {
2124
"pretest": "eslint",
22-
"test": "node --test"
25+
"test": "tsc && node --test"
2326
},
2427
"repository": {
2528
"type": "git",
@@ -30,7 +33,7 @@
3033
"comparison",
3134
"diff"
3235
],
33-
"author": "Vladimir Agafonkin",
36+
"author": "Volodymyr Agafonkin",
3437
"license": "ISC",
3538
"bugs": {
3639
"url": "https://github.com/mapbox/pixelmatch/issues"

tsconfig.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"allowJs": true,
4+
"checkJs": true,
5+
"strict": true,
6+
"emitDeclarationOnly": true,
7+
"declaration": true,
8+
"target": "es2017",
9+
"module": "nodenext",
10+
"moduleResolution": "nodenext"
11+
},
12+
"files": [
13+
"index.js"
14+
]
15+
}

0 commit comments

Comments
 (0)