1515 * @param {[number, number, number] } [options.diffColor=[255, 0, 0]] Color of different pixels in diff output.
1616 * @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.
1717 * @param {boolean } [options.diffMask=false] Draw the diff over a transparent background (a mask).
18+ * @param {boolean } [options.checkerboard=true] Whether to blend semi-transparent pixels against a checkerboard pattern (true) or plain white (false) when comparing.
1819 *
1920 * @return {number } The number of mismatched pixels.
2021 */
@@ -24,6 +25,7 @@ export default function pixelmatch(img1, img2, output, width, height, options =
2425 alpha = 0.1 ,
2526 aaColor = [ 255 , 255 , 0 ] ,
2627 diffColor = [ 255 , 0 , 0 ] ,
28+ checkerboard = true ,
2729 includeAA, diffColorAlt, diffMask
2830 } = options ;
2931
@@ -62,14 +64,14 @@ export default function pixelmatch(img1, img2, output, width, height, options =
6264 // compare each pixel of one image against the other one
6365 for ( let i = 0 , pos = 0 ; i < len ; i ++ , pos += 4 ) {
6466 // squared YUV distance between colors at this pixel position, negative if the img2 pixel is darker
65- const delta = a32 [ i ] === b32 [ i ] ? 0 : colorDelta ( img1 , img2 , pos , pos ) ;
67+ const delta = a32 [ i ] === b32 [ i ] ? 0 : colorDelta ( img1 , img2 , pos , pos , checkerboard ) ;
6668
6769 // the color difference is above the threshold
6870 if ( Math . abs ( delta ) > maxDelta ) {
6971 const x = i % width ;
7072 const y = ( i / width ) | 0 ;
7173 // check it's a real rendering difference or just anti-aliasing
72- const isExcludedAA = ! includeAA && ( antialiased ( img1 , x , y , width , height , a32 , b32 ) || antialiased ( img2 , x , y , width , height , b32 , a32 ) ) ;
74+ const isExcludedAA = ! includeAA && ( antialiased ( img1 , x , y , width , height , a32 , b32 , checkerboard ) || antialiased ( img2 , x , y , width , height , b32 , a32 , checkerboard ) ) ;
7375 if ( isExcludedAA ) {
7476 // one of the pixels is anti-aliasing; draw as yellow and do not count as difference
7577 // note that we do not include such pixels in a mask
@@ -113,8 +115,9 @@ function isPixelData(arr) {
113115 * @param {number } height
114116 * @param {Uint32Array } a32
115117 * @param {Uint32Array } b32
118+ * @param {boolean } checkerboard
116119 */
117- function antialiased ( img , x1 , y1 , width , height , a32 , b32 ) {
120+ function antialiased ( img , x1 , y1 , width , height , a32 , b32 , checkerboard ) {
118121 const x0 = Math . max ( x1 - 1 , 0 ) ;
119122 const y0 = Math . max ( y1 - 1 , 0 ) ;
120123 const x2 = Math . min ( x1 + 1 , width - 1 ) ;
@@ -139,7 +142,7 @@ function antialiased(img, x1, y1, width, height, a32, b32) {
139142 if ( x === x1 && y === y1 ) continue ;
140143
141144 // brightness delta between the center pixel and adjacent one
142- const delta = brightnessDelta ( img , pos4 , ( y * width + x ) * 4 , cr , cg , cb , ca ) ;
145+ const delta = brightnessDelta ( img , pos4 , ( y * width + x ) * 4 , cr , cg , cb , ca , checkerboard ) ;
143146
144147 // count the number of equal, darker and brighter adjacent pixels
145148 if ( delta === 0 ) {
@@ -206,8 +209,9 @@ function hasManySiblings(img, x1, y1, width, height) {
206209 * @param {Uint8Array | Uint8ClampedArray } img2
207210 * @param {number } k
208211 * @param {number } m
212+ * @param {boolean } checkerboard
209213 */
210- function colorDelta ( img1 , img2 , k , m ) {
214+ function colorDelta ( img1 , img2 , k , m , checkerboard ) {
211215 const r1 = img1 [ k ] ;
212216 const g1 = img1 [ k + 1 ] ;
213217 const b1 = img1 [ k + 2 ] ;
@@ -223,9 +227,12 @@ function colorDelta(img1, img2, k, m) {
223227 const da = a1 - a2 ;
224228
225229 if ( a1 < 255 || a2 < 255 ) { // blend pixels with background
226- const rb = 48 + 159 * ( k % 2 ) ;
227- const gb = 48 + 159 * ( ( k / 1.618033988749895 | 0 ) % 2 ) ;
228- const bb = 48 + 159 * ( ( k / 2.618033988749895 | 0 ) % 2 ) ;
230+ let rb = 255 , gb = 255 , bb = 255 ;
231+ if ( checkerboard ) {
232+ rb = 48 + 159 * ( k % 2 ) ;
233+ gb = 48 + 159 * ( ( k / 1.618033988749895 | 0 ) % 2 ) ;
234+ bb = 48 + 159 * ( ( k / 2.618033988749895 | 0 ) % 2 ) ;
235+ }
229236 dr = ( r1 * a1 - r2 * a2 - rb * da ) / 255 ;
230237 dg = ( g1 * a1 - g2 * a2 - gb * da ) / 255 ;
231238 db = ( b1 * a1 - b2 * a2 - bb * da ) / 255 ;
@@ -251,8 +258,9 @@ function colorDelta(img1, img2, k, m) {
251258 * @param {number } g1
252259 * @param {number } b1
253260 * @param {number } a1
261+ * @param {boolean } checkerboard
254262 */
255- function brightnessDelta ( img , k , m , r1 , g1 , b1 , a1 ) {
263+ function brightnessDelta ( img , k , m , r1 , g1 , b1 , a1 , checkerboard ) {
256264 const r2 = img [ m ] ;
257265 const g2 = img [ m + 1 ] ;
258266 const b2 = img [ m + 2 ] ;
@@ -266,9 +274,12 @@ function brightnessDelta(img, k, m, r1, g1, b1, a1) {
266274 if ( ! dr && ! dg && ! db && ! da ) return 0 ;
267275
268276 if ( a1 < 255 || a2 < 255 ) {
269- const rb = 48 + 159 * ( k % 2 ) ;
270- const gb = 48 + 159 * ( ( k / 1.618033988749895 | 0 ) % 2 ) ;
271- const bb = 48 + 159 * ( ( k / 2.618033988749895 | 0 ) % 2 ) ;
277+ let rb = 255 , gb = 255 , bb = 255 ;
278+ if ( checkerboard ) {
279+ rb = 48 + 159 * ( k % 2 ) ;
280+ gb = 48 + 159 * ( ( k / 1.618033988749895 | 0 ) % 2 ) ;
281+ bb = 48 + 159 * ( ( k / 2.618033988749895 | 0 ) % 2 ) ;
282+ }
272283 dr = ( r1 * a1 - r2 * a2 - rb * da ) / 255 ;
273284 dg = ( g1 * a1 - g2 * a2 - gb * da ) / 255 ;
274285 db = ( b1 * a1 - b2 * a2 - bb * da ) / 255 ;
0 commit comments