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 outputssim: perceptual similarity score in[0.0, 1.0]
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 diff, ssim, compare
# 1) Pixel-level diff + diff PNG
# returns: (diff_png_bytes, diff_count, width, height)
diff_png, diff_count, width, height = diff(baseline_png, current_png)
# 2) Perceptual similarity
score = ssim(baseline_png, current_png)
# 3) One-call gate (count + SSIM), no diff image encoding overhead
# returns: (diff_count, ssim, width, height, maybe_diff_png)
diff_count, score, width, height, _ = compare(
baseline_png,
current_png,
return_diff=False,
)
API at a glance
| Function | Input | Output | Use when |
|---|---|---|---|
diff |
PNG bytes | (diff_png, diff_count, width, height) |
You need a visual diff artifact |
diff_count |
PNG bytes | (diff_count, width, height) |
You only need the mismatch count |
ssim |
PNG bytes | float |
You need perceptual similarity |
compare |
PNG bytes | (diff_count, ssim, width, height, optional_diff_png) |
You want both metrics in one call |
diff_rgba |
RGBA bytes + sizes | (diff_rgba, diff_count, width, height) |
You already decoded images in Python/Rust |
diff_count_rgba |
RGBA bytes + sizes | (diff_count, width, height) |
Count-only on pre-decoded buffers |
ssim_rgba |
RGBA bytes + sizes | float |
SSIM on pre-decoded buffers |
compare_rgba |
RGBA bytes + sizes | (diff_count, ssim, width, height, optional_diff_rgba) |
Combined metrics on pre-decoded buffers |
diff_batch |
list[(baseline_png, current_png)] |
list[diff result] |
Run many diffs in one call |
diff_count_batch |
list[(baseline_png, current_png)] |
list[count result] |
Batch count-only checks |
ssim_batch |
list[(baseline_png, current_png)] |
list[float] |
Batch SSIM checks |
compare_batch |
list[(baseline_png, current_png)] |
list[compare result] |
Batch combined checks |
Behavior
- High-level APIs accept PNG bytes and decode internally.
- Smaller images are padded to the larger dimensions with transparent pixels.
diffalways generates a diff image.diff_countandcompare(..., return_diff=False)skip diff-image generation.- SSIM uses 11x11 uniform windows with reflect padding.
- For images smaller than 11x11, SSIM falls back to global SSIM.
- No SSIM visualization image is produced.
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 benchruns 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 callssim_breakdown.rs: decode/pad vs core SSIM vs API callcombined_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_countis cheaper thandiffwhen 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pixelhog-1.0.0.tar.gz.
File metadata
- Download URL: pixelhog-1.0.0.tar.gz
- Upload date:
- Size: 20.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c52eb35d02dffd539f9c9570ad8b06f514f14287583036ea92c37227f6c90d74
|
|
| MD5 |
9ac223fd1753725fc965bdd148438a48
|
|
| BLAKE2b-256 |
d956f462f024d9342a8c22edc319c4ef69eccce1067f571120ac7b9985aefeba
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-win_amd64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-win_amd64.whl
- Upload date:
- Size: 390.3 kB
- Tags: CPython 3.12+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12f09811f77d9d5b364926cc128db423dea01781e586006ed4450c54e9adab1d
|
|
| MD5 |
f02c5e5e4a648800f64bb12a08282e53
|
|
| BLAKE2b-256 |
83b1f01f99bcfdf16d4a1dc55b5c0c2bebc70df76cacaa065ba569201da14d5c
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 702.7 kB
- Tags: CPython 3.12+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
091a3f222e0792efdae5e5170ed89e95ccc264a6486d5529dd9fddd97e32baf1
|
|
| MD5 |
bf153f5928621b4fa5431b158618e905
|
|
| BLAKE2b-256 |
3b20e636acaaa82f34817567579311857095d4acd2353f2cad5f2e518b1dc8d7
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 648.1 kB
- Tags: CPython 3.12+, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
20e73ad915e25229cf41dc637a9ea81dc55cecdb4ec16ef6467e2d18127fb2ba
|
|
| MD5 |
09c5998916149b4ecf4fb2f68dab2b4e
|
|
| BLAKE2b-256 |
08b5602e77e784e39061a2fd10e3ae8d57566861b94d19f3c1191341caac3b2a
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 506.5 kB
- Tags: CPython 3.12+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b69cacd91f7286084ff787f14ccc208e13ab337c13ba63ea52a738b84ee93863
|
|
| MD5 |
da8dbfbc3dcc5a4dcc56cabf3f2d8440
|
|
| BLAKE2b-256 |
2f4f3d191ce7e1874dd51bea8e0daed075c237f59680dd53464f6db70eeeb36b
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 471.8 kB
- Tags: CPython 3.12+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e706c23e9c7a58c38fbad531380cc5f7de22f5d4dd9d209b4f3af6b3778f165
|
|
| MD5 |
6ff793db2553e8a06969f218f7eee838
|
|
| BLAKE2b-256 |
acfa557469fafd80389e077fabc16d80e9034bdf8cf78cddc30fcc80265c463f
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 441.5 kB
- Tags: CPython 3.12+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c0c08067e14ea3baeadaf0cc830d5fa0829b69ab6be9f99a74b807e877958ec
|
|
| MD5 |
7a78dd97252de0d1e3813ce7bf03a8eb
|
|
| BLAKE2b-256 |
d44aa7053f4c590fa337c601de2af7ce43beea7a95c7429d18dabe3160f4d5a0
|
File details
Details for the file pixelhog-1.0.0-cp312-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pixelhog-1.0.0-cp312-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 453.3 kB
- Tags: CPython 3.12+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6809cdb8242e7f934adaad8c1849ee6a2da75a84b8ed7b7648b693c7ee023dea
|
|
| MD5 |
cbcbecd6515b5432181b49dd75f71f91
|
|
| BLAKE2b-256 |
5e91b5f58c8abc2f931a8f3b298148ee66f8ea1bfde0371a23fd792172091b34
|