Skip to main content

Rust-accelerated pixelmatch and SSIM for PNG bytes

Project description

pixelhog

Fast visual regression primitives for Python, implemented in Rust.

pixelhog compares screenshots in two complementary ways:

  • diff: exact pixel-level differences (with anti-alias handling), optional diff image output
  • ssim: perceptual similarity score in [0.0, 1.0]

It also provides spatial clustering (where on the page did things change), early-exit checks, and WebP thumbnail generation — all accessible through a stateful Comparison object that decodes images once and exposes methods on demand.

Install (local dev)

uv venv .venv --python 3.12
source .venv/bin/activate
uv pip install -U pip maturin
maturin develop --release

Quickstart

from pixelhog import Comparison, thumbnail

cmp = Comparison(baseline_png, current_png)

count = cmp.diff_count()                     # pixel mismatch count
score = cmp.ssim()                           # perceptual similarity
png   = cmp.diff_image()                     # diff visualization (PNG bytes)
thumb = cmp.current_thumbnail(width=200)     # lossless WebP thumbnail

# Spatial clustering — where did things change?
result = cmp.clusters(dilation=8, merge_gap=60)
for cluster in result.clusters:
    print(cluster.bbox.x, cluster.bbox.y, cluster.bbox.width, cluster.bbox.height)

# Early exit — fail fast if too many diffs
capped = cmp.diff_count_capped(max_diffs=1000)

# Standalone thumbnail (lossless WebP, Lanczos3 downscale, top-crop)
thumb = thumbnail(current_png, width=200, height=150)

API at a glance

Comparison

Method Returns Notes
Comparison(baseline_png, current_png) Comparison Decode pair once, call methods on demand
Comparison.from_rgba(...) Comparison Pre-decoded RGBA buffers
Comparison.batch(pairs) list[Comparison] Parallel decode
.diff_count(threshold, include_aa) int Pixel mismatch count
.diff_count_capped(max_diffs, ...) int Early-exit count
.ssim() float Structural similarity
.clusters(dilation, merge_gap, ...) ClustersResult Spatial regions of change
.diff_image(...) bytes (PNG) Diff visualization
.current_thumbnail(width, height, ...) bytes (WebP) Thumbnail of current image
.baseline_thumbnail(width, height, ...) bytes (WebP) Thumbnail of baseline image
.size_mismatch bool Whether images had different dimensions

Utilities and batch

Function Input Output Use when
thumbnail PNG bytes bytes (WebP) Single-image thumbnail (no pair needed)
diff_batch list[(baseline, current)] list[DiffResult] Parallel diff across many pairs
diff_count_batch list[(baseline, current)] list[DiffCountResult] Parallel count-only
ssim_batch list[(baseline, current)] list[float] Parallel SSIM
compare_batch list[(baseline, current)] list[CompareResult] Parallel combined metrics

Behavior

  • Comparison decodes PNG bytes once at construction; methods compute on demand.
  • Comparison.from_rgba(...) accepts pre-decoded RGBA buffers (zero-copy).
  • Smaller images are padded to the larger dimensions with transparent pixels.
  • SSIM uses 11×11 uniform windows with reflect padding; falls back to global for tiny images.
  • Clustering uses morphological dilation + two-pass CCL with optional aligned-bbox merge.

Correctness and tests

The test suite is designed to validate both algorithm fidelity and practical product behavior.

  • Rust unit/integration tests cover:
    • identical/completely different/partial-diff images
    • threshold behavior
    • different-size padding behavior
    • SSIM behavior (identical, slight change, large change, small-image fallback)
  • Canonical pixelmatch fixture tests use the official Mapbox test set:
    • 8 fixture pairs with exact expected mismatch counts
    • expected diff image comparison against golden outputs
    • decoded RGBA byte equality checks to ensure pixel-perfect output matching
  • Python integration tests cover:
    • high-level API contracts and error behavior
    • tall-page and subtle-change scenarios
    • cross-validation against a pure-Python reference implementation
      • pixel diff counts must match exactly
      • SSIM must stay within tolerance

Run the full correctness suite:

# Rust core only
cargo test -p pixelhog

# Full suite including Python integration tests
cargo test
uv run --python 3.12 --with maturin --with pytest --with pillow bash -lc \
  "maturin develop --release && pytest -q"

Benchmarks

The repo includes both Criterion benches and pipeline breakdown tools.

  • cargo bench runs Criterion API benchmarks (PNG-bytes entry points).
  • Breakdown binaries in examples/ measure where time goes:
    • breakdown.rs: decode vs core diff vs encode vs API call
    • ssim_breakdown.rs: decode/pad vs core SSIM vs API call
    • combined_estimate.rs: separate calls vs combined single-decode flow

Run:

cargo bench -p pixelhog
cargo run -p pixelhog --release --example breakdown
cargo run -p pixelhog --release --example ssim_breakdown
cargo run -p pixelhog --release --example combined_estimate

For screenshot-style workloads, the practical guidance is:

  • diff_count is cheaper than diff when you do not need an artifact.
  • compare(..., return_diff=False) avoids duplicate decode work when you need both diff-count and SSIM.

Development

# Rust tests (includes canonical Mapbox fixture tests)
cargo test

# Python extension + tests
uv run --python 3.12 --with maturin --with pytest --with pillow bash -lc \
  "maturin develop --release && pytest -q"

# Lint/format/type-check
uv run --python 3.12 --with ruff ruff format --check .
uv run --python 3.12 --with ruff ruff check .
uv run --python 3.12 --with ty --with pytest --with pillow ty check . --python .venv

License

This repository is MIT licensed. See LICENSE.

Algorithm attribution for pixelmatch is documented in THIRD_PARTY_NOTICES.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pixelhog-1.2.0.tar.gz (32.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pixelhog-1.2.0-cp312-abi3-win_amd64.whl (610.6 kB view details)

Uploaded CPython 3.12+Windows x86-64

pixelhog-1.2.0-cp312-abi3-musllinux_1_2_x86_64.whl (916.4 kB view details)

Uploaded CPython 3.12+musllinux: musl 1.2+ x86-64

pixelhog-1.2.0-cp312-abi3-musllinux_1_2_aarch64.whl (860.0 kB view details)

Uploaded CPython 3.12+musllinux: musl 1.2+ ARM64

pixelhog-1.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (724.2 kB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ x86-64

pixelhog-1.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (683.7 kB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ ARM64

pixelhog-1.2.0-cp312-abi3-macosx_11_0_arm64.whl (648.8 kB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

pixelhog-1.2.0-cp312-abi3-macosx_10_12_x86_64.whl (660.8 kB view details)

Uploaded CPython 3.12+macOS 10.12+ x86-64

File details

Details for the file pixelhog-1.2.0.tar.gz.

File metadata

  • Download URL: pixelhog-1.2.0.tar.gz
  • Upload date:
  • Size: 32.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0.tar.gz
Algorithm Hash digest
SHA256 919b9c3f90e89307ae1de816d7860cd3fa27a59e5e2da020f02953f30ebb56fd
MD5 da7fe63be1c8aeaa89a904d8349fa21e
BLAKE2b-256 1f5e23e3cf43002b8e68e55da4b650b108909e6e38569170fc9c2611ddaf5dcf

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-win_amd64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-win_amd64.whl
  • Upload date:
  • Size: 610.6 kB
  • Tags: CPython 3.12+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 3de6ddcea4cad183052a20f3d07d38ca23ff587bc7b6ffafdff1f98f914ca06b
MD5 3df951aaab596c1485c13a6fba43053f
BLAKE2b-256 09d2c057e7c1a708ec91abd9071a068332adf5d92d064b49537c0fdf9164cfed

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-musllinux_1_2_x86_64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-musllinux_1_2_x86_64.whl
  • Upload date:
  • Size: 916.4 kB
  • Tags: CPython 3.12+, musllinux: musl 1.2+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 7ac96f4f9ee6c2505eb89412f6532e8cc9719ac730d1c156e30b22be878285cf
MD5 356df565bfa455c0e1c97b48ac887d97
BLAKE2b-256 27c0a5b1d61a18fcd060afda879fd95abb9f510d131e585cf477816c1f178ce4

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-musllinux_1_2_aarch64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-musllinux_1_2_aarch64.whl
  • Upload date:
  • Size: 860.0 kB
  • Tags: CPython 3.12+, musllinux: musl 1.2+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 05239693d9e5f844af52a082d082a8e191608f379257ce35bf5c197b52231970
MD5 8be211f546c73393e227a39c77c00a30
BLAKE2b-256 7307da9179b7f0c9b118b9ae81a9a6d1849a2acbbdc86b9f6450ad05f0bdd8d2

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 724.2 kB
  • Tags: CPython 3.12+, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 365834d17326109c63cf2da5204cb92ce84518798f9a5d08502331fe83dacb4d
MD5 6eee63cf58a0035952b6ae7748be49f0
BLAKE2b-256 797ea04a4914a17774929d8fd1e0be0da71c1c310db14a0a37fbc33437a301f4

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
  • Upload date:
  • Size: 683.7 kB
  • Tags: CPython 3.12+, manylinux: glibc 2.17+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 2a2d70c505f17295b85a77c60c7fec8cee97a3c95100232cca2f86a5a590a579
MD5 8c9ea5a24b159903f05bbd05bb4320d6
BLAKE2b-256 da07d142e38d7dc60a467b97ef8f1a92d61cb1909bb8ffb0e9c27bec55e61bb0

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 648.8 kB
  • Tags: CPython 3.12+, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f0488d22181b166871a149458cefc84d5c6bac74766898a35053dcb7c163f802
MD5 6e3c1084e3fe255b4fd84337348fcb55
BLAKE2b-256 1ae09822760802dd572b837fb381fcba8274509d76532b151f0a49ed2ca250e2

See more details on using hashes here.

File details

Details for the file pixelhog-1.2.0-cp312-abi3-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: pixelhog-1.2.0-cp312-abi3-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 660.8 kB
  • Tags: CPython 3.12+, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.9 {"installer":{"name":"uv","version":"0.11.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for pixelhog-1.2.0-cp312-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 82b33e6cddc730dd08314aea688d0f3ac50f1f52439c5655378838ce41bf3710
MD5 ac34dffa097c3edf9c06504f8abfcb8d
BLAKE2b-256 a13b860c2e4cfe1a26fdfd5c19afb4ba649710a83a9a5d0bfcdd4111068aba3b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page