Skip to content

A C++17 port of the JavaScript pixelmatch library, providing a small pixel-level image comparison library.

License

Notifications You must be signed in to change notification settings

jwmcglynn/pixelmatch-cpp17

Repository files navigation

pixelmatch-cpp17

Build Status License: ISC codecov

A C++17 port of the JavaScript pixelmatch library, providing a small pixel-level image comparison library.

Features accurate anti-aliased pixels detection and perceptual color difference metrics.

Based on mapbox/pixelmatch. pixelmatch-cpp17 is around 300 lines of code, and has no dependencies, operating on RGBA-encoded buffers.

#include <pixelmatch/pixelmatch.h>

pixelmatch::Options options;
options.threshold = 0.1f;

const std::vector<uint8_t> img1 = ...;
const std::vector<uint8_t> img2 = ...;
std::vector<uint8_t> diffImage(img1.size());

const int numDiffPixels = pixelmatch::pixelmatch(img1, img2, diffImage, width, height, stride, options);

Compared to mapbox/pixelmatch-cpp, pixelmatch-cpp17 ports the latest features from the JavaScript library, and is built with production-grade practices, including thorough test coverage and fuzz-testing. Build files are included for Bazel, but contributions for other build systems are welcome.

Implements ideas from the following papers:

Example output

expected actual diff
1diff
1diff
1diff

API

pixelmatch(img1, img2, output, width, height, strideInPixels[, options])

  • img1, img2 — Image data of the images to compare, as a RGBA-encoded byte array. Note: image dimensions must be equal.
  • output — Image data to write the diff to, or std::nullopt if you 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.
  • strideInPixels — Stride of the images. Note that all three images need to have the same stride.
  • options is a struct with the following fields:
    • threshold — Matching threshold, ranges from 0.0f to 1.0f. 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 as an RGBA color. (255, 255, 0, 255) by default.
    • diffColor — The color of differing pixels in the diff output as an RGBA color (255, 0, 0, 255) 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. std::nullopt 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).

Compares two images, writes the output diff and returns the number of mismatched pixels.

Usage

Bazel

  • Bazel 7.0.0 or newer is required for bzlmod.

Add the following to your MODULE.bazel file:

bazel_dep(name = "pixelmatch-cpp17", version = "0.0.0")
git_override(
    module_name = "pixelmatch-cpp17",
    remote = "https://github.com/jwmcglynn/pixelmatch-cpp17",
    commit = "<latest commit hash>", # Ex: 2ab1b929916b97668698523a91e752413d01939c
)

Adding the dependency

Then add a dependency on @pixelmatch-cpp17:

cc_test(
    name = "my_test",
    # ...
    data = glob([
      "testdata/*.png",
    ]),
    deps = [
        "@pixelmatch-cpp17",
        # ...
    ],
)

In your test file, include pixelmatch with:

#include <pixelmatch/pixelmatch.h>

Projects using pixelmatch-cpp17

Documentation