pixelmatch
Advanced tools
Comparing version 2.0.2 to 3.0.0
41
index.js
@@ -5,7 +5,13 @@ 'use strict'; | ||
function pixelmatch(img1, img2, output, width, height, threshold, includeAA) { | ||
function pixelmatch(img1, img2, output, width, height, options) { | ||
var maxDelta = 255 * 255 * 3 * (threshold === undefined ? 0.005 : threshold), | ||
if (!options) options = {}; | ||
var threshold = options.threshold === undefined ? 0.1 : options.threshold; | ||
// maximum acceptable square YUV distance between two colors | ||
var maxDelta = 255 * 255 * 3 * threshold * threshold, | ||
diff = 0; | ||
// compare each pixel of one image against the other one | ||
for (var y = 0; y < height; y++) { | ||
@@ -15,10 +21,16 @@ for (var x = 0; x < width; x++) { | ||
var pos = (y * width + x) * 4; | ||
// squared YUV distance between colors at this pixel position | ||
var delta = colorDelta(img1, img2, pos, pos); | ||
// the color difference is above the threshold | ||
if (delta > maxDelta) { | ||
if (!includeAA && (antialiased(img1, x, y, width, height, img2) || | ||
// check it's a real rendering difference or just anti-aliasing | ||
if (!options.includeAA && (antialiased(img1, x, y, width, height, img2) || | ||
antialiased(img2, x, y, width, height, img1))) { | ||
// one of the pixels is anti-aliasing; draw as yellow and do not count as difference | ||
drawPixel(output, pos, 255, 255, 0); | ||
} else { | ||
// found substantial difference not caused by anti-aliasing; draw it as red | ||
drawPixel(output, pos, 255, 0, 0); | ||
@@ -29,2 +41,3 @@ diff++; | ||
} else { | ||
// pixels are similar; draw background as grayscale image blended with white | ||
var val = 255 - 0.1 * (255 - grayPixel(img1, pos)) * img1[pos + 3] / 255; | ||
@@ -36,5 +49,9 @@ drawPixel(output, pos, val, val, val); | ||
// return the number of different pixels | ||
return diff; | ||
} | ||
// check if a pixel is likely a part of anti-aliasing; | ||
// based on "Anti-aliased Pixel and Intensity Slope Detector" paper by V. Vysniauskas, 2009 | ||
function antialiased(img, x1, y1, width, height, img2) { | ||
@@ -53,2 +70,3 @@ var x0 = Math.max(x1 - 1, 0), | ||
// go through 8 adjacent pixels | ||
for (var x = x0; x <= x2; x++) { | ||
@@ -58,5 +76,11 @@ for (var y = y0; y <= y2; y++) { | ||
// brightness delta between the center pixel and adjacent one | ||
var delta = colorDelta(img, img, pos, (y * width + x) * 4, true); | ||
// count the number of equal, darker and brighter adjacent pixels | ||
if (delta === 0) zeroes++; | ||
else if (delta < 0) negatives++; | ||
else if (delta > 0) positives++; | ||
// if found more than 2 equal siblings, it's definitely not anti-aliasing | ||
if (zeroes > 2) return false; | ||
@@ -66,5 +90,3 @@ | ||
if (delta < 0) negatives++; | ||
else if (delta > 0) positives++; | ||
// remember the darkest pixel | ||
if (delta < min) { | ||
@@ -75,2 +97,3 @@ min = delta; | ||
} | ||
// remember the brightest pixel | ||
if (delta > max) { | ||
@@ -86,4 +109,7 @@ max = delta; | ||
// if there are no both darker and brighter pixels among siblings, it's not anti-aliasing | ||
if (negatives === 0 || positives === 0) return false; | ||
// if either the darkest or the brightest pixel has more than 2 equal siblings in both images | ||
// (definitely not anti-aliased), this pixel is anti-aliased | ||
return (!antialiased(img, minX, minY, width, height) && !antialiased(img2, minX, minY, width, height)) || | ||
@@ -93,2 +119,5 @@ (!antialiased(img, maxX, maxY, width, height) && !antialiased(img2, maxX, maxY, width, height)); | ||
// calculate either the squared YUV distance between colors, | ||
// or just the brightness differene (Y component) if yOnly is true | ||
function colorDelta(img1, img2, i, j, yOnly) { | ||
@@ -95,0 +124,0 @@ var a1 = img1[i + 3] / 255, |
{ | ||
"name": "pixelmatch", | ||
"version": "2.0.2", | ||
"version": "3.0.0", | ||
"description": "The smallest and fastest pixel-level image comparison library.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -7,5 +7,5 @@ ## pixelmatch | ||
The smallest, simplest and fastest JavaScript pixel-level image comparison library, | ||
primarily designed to be used in regression tests that compare screenshots. | ||
originally created to compare screenshots in tests. | ||
Features [anti-aliased pixels detection](http://www.ee.ktu.lt/journal/2009/7/25_ISSN_1392-1215_Anti-aliased%20Pxel%20and%20Intensity%20Slope%20Detector.pdf) | ||
Features accurate [anti-aliased pixels detection](http://www.ee.ktu.lt/journal/2009/7/25_ISSN_1392-1215_Anti-aliased%20Pxel%20and%20Intensity%20Slope%20Detector.pdf) | ||
and [perceptual color metrics](https://en.wikipedia.org/wiki/YUV). | ||
@@ -15,3 +15,3 @@ | ||
and [Blink-diff](https://github.com/yahoo/blink-diff). | ||
Unlike these libraries, pixelmatch is around **120 lines of code**, | ||
Unlike these libraries, pixelmatch is around **90 lines of code**, | ||
has **no dependencies**, and works on **raw arrays** of image data, | ||
@@ -21,13 +21,24 @@ so it's **blazing fast** and can be used in **any environment** (Node or browsers). | ||
```js | ||
var numDiffPixels = pixelmatch(img1.data, img2.data, diff.data, 800, 600); | ||
var numDiffPixels = pixelmatch(img1, img2, diff, 800, 600, {threshold: 0.1}); | ||
``` | ||
### 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/1a.png) | ![](test/fixtures/1b.png) | ![1diff](test/fixtures/1diff.png) | | ||
### API | ||
#### pixelmatch(img1, img2, output, width, height[, threshold, includeAA]) | ||
#### pixelmatch(img1, img2, output, width, height[, options]) | ||
- `img1`, `img2` — Image data of the images to compare (`Buffer` or `Uint8Array`). | ||
- `output` — Image data to write the diff to. | ||
- `width`, `height` — Width and height of the images. Note that all three images need to have the same dimensions. | ||
- `threshold` — Matching threshold, ranges from `0` to `1`. Smaller values make the comparison more sensitive. `0.005` by default. | ||
- `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. | ||
@@ -42,5 +53,39 @@ | ||
```bash | ||
pixelmatch image1.png image2.png output.png 0.005 | ||
pixelmatch image1.png image2.png output.png 0.1 | ||
``` | ||
### Example usage | ||
#### Node.js | ||
```js | ||
var fs = require('fs'), | ||
PNG = require('pngjs2').PNG, | ||
pixelmatch = require('pixelmatch'); | ||
var img1 = fs.createReadStream('img1.png').pipe(new PNG()).on('parsed', doneReading); | ||
var img2 = fs.createReadStream('img2.png').pipe(new PNG()).on('parsed', doneReading); | ||
function doneReading() { | ||
if (!img1.data || !img2.data) return; | ||
var diff = new PNG({width: img1.width, height: img1.height}); | ||
pixelmatch(img1.data, img2.data, diff.data, img1.width, img1.height, {threshold: 0.1}); | ||
diff.pack().pipe(fs.createWriteStream('diff.png')); | ||
} | ||
``` | ||
#### Browsers | ||
```js | ||
var img1 = img1Ctx.getImageData(0, 0, width, height), | ||
img2 = img2Ctx.getImageData(0, 0, width, height), | ||
diff = diffCtx.createImageData(width, height); | ||
pixelmatch(img1.data, img2.data, diff.data, width, height, {threshold: 0.1}); | ||
diffCtx.putImageData(diff, 0, 0); | ||
``` | ||
### Install | ||
@@ -61,10 +106,2 @@ | ||
### Example output | ||
| expected | actual | diff | | ||
| --- | --- | --- | | ||
| ![](test/fixtures/3a.png) | ![](test/fixtures/3b.png) | ![1diff](test/fixtures/3diff.png) | | ||
| ![](test/fixtures/1a.png) | ![](test/fixtures/1b.png) | ![1diff](test/fixtures/1diff.png) | | ||
| ![](test/fixtures/2a.png) | ![](test/fixtures/2b.png) | ![1diff](test/fixtures/2diff.png) | | ||
### [Changelog](https://github.com/mapbox/pixelmatch/releases) |
@@ -9,5 +9,6 @@ 'use strict'; | ||
diffTest('1a', '1b', '1diff', 0.001, false, 144); | ||
diffTest('2a', '2b', '2diff', 0.001, false, 12600); | ||
diffTest('3a', '3b', '3diff', 0.001, false, 212); | ||
diffTest('1a', '1b', '1diff', 0.03, false, 144); | ||
diffTest('2a', '2b', '2diff', 0.03, false, 12785); | ||
diffTest('3a', '3b', '3diff', 0.03, false, 212); | ||
diffTest('4a', '4b', '4diff', 0.03, false, 36383); | ||
@@ -23,4 +24,8 @@ function diffTest(imgPath1, imgPath2, diffPath, threshold, includeAA, expectedMismatch) { | ||
var diff = new PNG({width: img1.width, height: img1.height}); | ||
var mismatch = match(img1.data, img2.data, diff.data, diff.width, diff.height, threshold, includeAA); | ||
var mismatch = match(img1.data, img2.data, diff.data, diff.width, diff.height, { | ||
threshold: threshold, | ||
includeAA: includeAA | ||
}); | ||
t.same(diff.data, expectedDiff.data, 'diff image'); | ||
@@ -27,0 +32,0 @@ t.same(mismatch, expectedMismatch, 'number of mismatched pixels'); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
946997
20
148
103