Skip to content

Commit cc630dc

Browse files
committed
optimize antialiasing detection (~17% perf improvement)
1 parent 89a35ef commit cc630dc

File tree

1 file changed

+15
-18
lines changed

1 file changed

+15
-18
lines changed

index.js

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,17 @@ export default function pixelmatch(img1, img2, output, width, height, options =
6363
for (let y = 0; y < height; y++) {
6464
for (let x = 0; x < width; x++) {
6565

66-
const pos = (y * width + x) * 4;
66+
const i = y * width + x;
67+
const pos = i * 4;
6768

6869
// squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker
69-
const delta = colorDelta(img1, img2, pos, pos, false);
70+
const delta = a32[i] === b32[i] ? 0 : colorDelta(img1, img2, pos, pos, false);
7071

7172
// the color difference is above the threshold
7273
if (Math.abs(delta) > maxDelta) {
7374
// check it's a real rendering difference or just anti-aliasing
74-
if (!includeAA && (antialiased(img1, x, y, width, height, img2) || antialiased(img2, x, y, width, height, img1))) {
75+
const isAA = antialiased(img1, x, y, width, height, a32, b32) || antialiased(img2, x, y, width, height, a32, b32);
76+
if (!includeAA && isAA) {
7577
// one of the pixels is anti-aliasing; draw as yellow and do not count as difference
7678
// note that we do not include such pixels in a mask
7779
if (output && !diffMask) drawPixel(output, pos, aaR, aaG, aaB);
@@ -113,14 +115,15 @@ function isPixelData(arr) {
113115
* @param {number} y1
114116
* @param {number} width
115117
* @param {number} height
116-
* @param {Uint8Array | Uint8ClampedArray} img2
118+
* @param {Uint32Array} a32
119+
* @param {Uint32Array} b32
117120
*/
118-
function antialiased(img, x1, y1, width, height, img2) {
121+
function antialiased(img, x1, y1, width, height, a32, b32) {
119122
const x0 = Math.max(x1 - 1, 0);
120123
const y0 = Math.max(y1 - 1, 0);
121124
const x2 = Math.min(x1 + 1, width - 1);
122125
const y2 = Math.min(y1 + 1, height - 1);
123-
const pos = (y1 * width + x1) * 4;
126+
const pos = y1 * width + x1;
124127
let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
125128
let min = 0;
126129
let max = 0;
@@ -135,7 +138,7 @@ function antialiased(img, x1, y1, width, height, img2) {
135138
if (x === x1 && y === y1) continue;
136139

137140
// brightness delta between the center pixel and adjacent one
138-
const delta = colorDelta(img, img, pos, (y * width + x) * 4, true);
141+
const delta = colorDelta(img, img, pos * 4, (y * width + x) * 4, true);
139142

140143
// count the number of equal, darker and brighter adjacent pixels
141144
if (delta === 0) {
@@ -163,13 +166,13 @@ function antialiased(img, x1, y1, width, height, img2) {
163166

164167
// if either the darkest or the brightest pixel has 3+ equal siblings in both images
165168
// (definitely not anti-aliased), this pixel is anti-aliased
166-
return (hasManySiblings(img, minX, minY, width, height) && hasManySiblings(img2, minX, minY, width, height)) ||
167-
(hasManySiblings(img, maxX, maxY, width, height) && hasManySiblings(img2, maxX, maxY, width, height));
169+
return (hasManySiblings(a32, minX, minY, width, height) && hasManySiblings(b32, minX, minY, width, height)) ||
170+
(hasManySiblings(a32, maxX, maxY, width, height) && hasManySiblings(b32, maxX, maxY, width, height));
168171
}
169172

170173
/**
171174
* Check if a pixel has 3+ adjacent pixels of the same color.
172-
* @param {Uint8Array | Uint8ClampedArray} img
175+
* @param {Uint32Array} img
173176
* @param {number} x1
174177
* @param {number} y1
175178
* @param {number} width
@@ -180,20 +183,14 @@ function hasManySiblings(img, x1, y1, width, height) {
180183
const y0 = Math.max(y1 - 1, 0);
181184
const x2 = Math.min(x1 + 1, width - 1);
182185
const y2 = Math.min(y1 + 1, height - 1);
183-
const pos = (y1 * width + x1) * 4;
186+
const pos = y1 * width + x1;
184187
let zeroes = x1 === x0 || x1 === x2 || y1 === y0 || y1 === y2 ? 1 : 0;
185188

186189
// go through 8 adjacent pixels
187190
for (let x = x0; x <= x2; x++) {
188191
for (let y = y0; y <= y2; y++) {
189192
if (x === x1 && y === y1) continue;
190-
191-
const pos2 = (y * width + x) * 4;
192-
if (img[pos] === img[pos2] &&
193-
img[pos + 1] === img[pos2 + 1] &&
194-
img[pos + 2] === img[pos2 + 2] &&
195-
img[pos + 3] === img[pos2 + 3]) zeroes++;
196-
193+
if (img[pos] === img[y * width + x]) zeroes++;
197194
if (zeroes > 2) return true;
198195
}
199196
}

0 commit comments

Comments
 (0)