# pixelmatch [![Node](https://github.com/mapbox/pixelmatch/actions/workflows/node.yml/badge.svg)](https://github.com/mapbox/pixelmatch/actions/workflows/node.yml) [![](https://img.shields.io/badge/simply-awesome-brightgreen.svg)](https://github.com/mourner/projects) A small, simple and fast JavaScript pixel-level **image comparison library**, originally created to compare screenshots in tests. Features accurate **anti-aliased pixels detection** and **perceptual color difference** metrics. Inspired by [Resemble.js](https://github.com/Huddle/Resemble.js) and [Blink-diff](https://github.com/yahoo/blink-diff). Unlike these libraries, pixelmatch is just **a few hundred lines of code**, has **no dependencies**, and works on **raw typed arrays** of image data, so it's **very fast** and can be used in both Node and browsers. ```js const numDiffPixels = pixelmatch(img1, img2, diff, 800, 600, {threshold: 0.1}); ``` Implements ideas from the following papers: - [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) (2020, Björn Ottosson) — the OKLab color space used for color difference. - [Distance metrics for very large color differences](https://onlinelibrary.wiley.com/doi/10.1002/col.22451) (2019, Saeideh Abasi et al.) — the OKLab HyAB metric used to compare colors. - [Anti-aliased pixel and intensity slope detector](https://www.researchgate.net/publication/234126755_Anti-aliased_Pixel_and_Intensity_Slope_Detector) (2009, Vytautas Vyšniauskas) ## [Demo](https://observablehq.com/@mourner/pixelmatch-demo) ## Example output | expected | actual | diff | | --- | --- | --- | | ![](test/fixtures/4a.png) | ![](test/fixtures/4b.png) | ![1diff](test/fixtures/4diff.png) | | ![](test/fixtures/3a.png) | ![](test/fixtures/3b.png) | ![1diff](test/fixtures/3diff.png) | | ![](test/fixtures/6a.png) | ![](test/fixtures/6b.png) | ![1diff](test/fixtures/6diff.png) | ## API ### pixelmatch(img1, img2, output, width, height[, options]) - `img1`, `img2` — Image data of the images to compare (`Buffer`, `Uint8Array` or `Uint8ClampedArray`). **Note:** image dimensions must be equal. - `output` — Image data to write the diff to, or `null` if don't need a diff image. - `width`, `height` — Width and height of the images. Note that _all three images_ need to have the same dimensions. `options` is an object literal with the following properties: - `threshold` — Matching threshold, ranges from `0` to `1`. Smaller values make the comparison more sensitive. `0.1` by default. - `includeAA` — If `true`, disables detecting and ignoring anti-aliased pixels. `false` by default. - `alpha` — Blending factor of unchanged pixels in the diff output. Ranges from `0` for pure white to `1` for original brightness. `0.1` by default. - `aaColor` — The color of anti-aliased pixels in the diff output in `[R, G, B]` format. `[255, 255, 0]` by default. - `diffColor` — The color of differing pixels in the diff output in `[R, G, B]` format. `[255, 0, 0]` by default. - `diffColorAlt` — An alternative color to use for dark on light differences to differentiate between "added" and "removed" parts. If not provided, all differing pixels use the color specified by `diffColor`. `null` by default. - `diffMask` — Draw the diff over a transparent background (a mask), rather than over the original image. Will not draw anti-aliased pixels (if detected). - `checkerboard` — Blend semi-transparent pixels against a checkerboard pattern when comparing (`true`) rather than plain white (`false`), avoiding false matches between colors that only look alike over one background. `true` by default. - `windowSize` — If set to a finite number `N`, return the maximum number of differing pixels in any `N`×`N` sliding window instead of the total count (see below). `Infinity` by default. Compares two images, writes the output diff and returns the number of mismatched pixels. ### Windowed diff density By default the return value is the total number of differing pixels. With `windowSize: N`, it instead becomes the largest number of diff pixels found in any `N`×`N` region (`N` is clamped to the image dimensions, and anti-aliased pixels are never counted). This makes the result robust to scattered noise. Spread-out speckle (GPU dithering, sub-pixel anti-aliasing) never packs densely into a single window, while a genuine regression does. A test can then fail on density — `result / N² > tau` — which stays comparable across image sizes, so you can run a stricter threshold to catch smaller real changes without tripping over noise. The total count is just the degenerate whole-image window, so the return value is always "max diff pixels in any window". ## Command line Pixelmatch comes with a binary that works with PNG images: ```bash pixelmatch image1.png image2.png output.png 0.1 ``` ## Example usage ### Node.js ```js import fs from 'fs'; import {PNG} from 'pngjs'; import pixelmatch from 'pixelmatch'; const img1 = PNG.sync.read(fs.readFileSync('img1.png')); const img2 = PNG.sync.read(fs.readFileSync('img2.png')); const {width, height} = img1; const diff = new PNG({width, height}); pixelmatch(img1.data, img2.data, diff.data, width, height, {threshold: 0.1}); fs.writeFileSync('diff.png', PNG.sync.write(diff)); ``` ### Browsers ```js const img1 = img1Context.getImageData(0, 0, width, height); const img2 = img2Context.getImageData(0, 0, width, height); const diff = diffContext.createImageData(width, height); pixelmatch(img1.data, img2.data, diff.data, width, height, {threshold: 0.1}); diffContext.putImageData(diff, 0, 0); ``` ## Install Install with NPM: ```bash npm install pixelmatch ``` Or use in the browser from a CDN: ```html