Skip to main content

blazediff

High-performance image diffing with block-based optimization and SIMD acceleration.

Crates.io npm PyPI License: MIT

Features

  • Block-based optimization - Skip identical regions for massive speedups on similar images
  • SIMD acceleration - Native SSE4.1 (x86) and NEON (ARM) implementations
  • Multiple formats - PNG, JPEG, and QOI support, via blazediff-shared
  • Perceptual diffing - YIQ-based color difference with antialiasing detection
  • In-house PNG codec - optional blazediff_png, faster than spng on every fixture, with byte-exact decode parity; opt-in via BLAZEDIFF_PNG_ENABLED
  • Cross-platform - Linux, macOS, and Windows support
  • Multi-language - Native Rust crate, Node.js (N-API), and Python (PyO3) bindings - all sharing the same core

Installation

Rust (CLI + library)

cargo install blazediff

Node.js - @blazediff/core-native

npm install @blazediff/core-native

N-API bindings shipped as pre-built .node binaries for macOS, Linux, and Windows (arm64 + x64). Built from this crate's napi Cargo feature.

import { diff } from "@blazediff/core-native";

const result = await diff("expected.png", "actual.png", {
  output: "diff.png",
  threshold: 0.1,
});
if (result.kind === "compared" && !result.identical) {
  console.log(`${result.count} pixels differ`);
}

Python - blazediff

pip install blazediff

PyO3 bindings shipped as abi3-py38 wheels for CPython ≥ 3.8 (macOS, Linux manylinux, Windows; arm64 + x86_64). Built from this crate's python Cargo feature.

from blazediff import diff

result = diff("expected.png", "actual.png", "diff.png", threshold=0.1)
if result.kind == "compared" and not result.identical:
    print(f"{result.count} pixels differ ({result.percentage:.2f}%)")

diff(a, b, output=None, *, threshold=0.1, antialiasing=True, metric="yiq", mask=None, window=None, alpha=0.1, diff_color=None, diff_color_alt=None, aa_color=None, background="faded", compression=0, quality=90) takes file paths or encoded bytes. The result has a kind:

kind Fields
"compared" count, percentage, identical, and window (x, y, count) when window is set
"dimension-mismatch" a and b, each with width and height
"io-error" path (when known) and message

Invalid options raise ValueError.

CLI Usage

# Basic diff
blazediff image1.png image2.png -o diff.png

# With custom threshold (0.0 - 1.0)
blazediff image1.png image2.png -o diff.png -t 0.1

# pixelmatch 8 metric, a mask, and the busiest 16×16 window, as JSON
blazediff image1.png image2.png --metric oklab --mask mask.png --window 16 --json
Flag Meaning
-o, --output <path> Write the diff image (only when the images differ)
-t, --threshold <n> Color difference threshold (0-1). Default: 0.1
--antialiasing, --no-antialiasing Detect anti-aliased pixels and leave them out of the count. Default: on
--metric <yiq|oklab> Color metric. oklab is pixelmatch 8's. Default: yiq
--mask <path> Image the size of the inputs; its non-black pixels are skipped
--window <n> Also report the N×N window with the most diff pixels
-a, --alpha <n> Opacity of the faded background. Default: 0.1
--diff-color, --diff-color-alt, --aa-color <r,g,b> Output colors
--background <faded|transparent> What the diff image shows under the diff. Default: faded
-c, --compression <0-9>, -q, --quality <1-100> PNG and JPEG encoder settings
--json Print the result object as JSON

Exit codes: 0 identical, 1 the images differ or their dimensions do not match, 2 error. With --json, a result prints to stdout ({"kind":"compared","count":..,"percentage":..,"identical":..}, or {"kind":"dimension-mismatch","a":{..},"b":{..}}) and an error prints to stderr ({"kind":"io-error","path":..,"message":..}).

Library Usage

use blazediff::{diff, load_png, save_png, DiffOptions, DiffResult, Image, Metric};

let a = load_png("image1.png")?;
let b = load_png("image2.png")?;
let mut output = Image::new(a.width, a.height);
let options = DiffOptions {
    threshold: 0.1,
    metric: Metric::Oklab,
    window: Some(16),
    ..Default::default()
};

match diff(&a, &b, Some(&mut output), &options)? {
    DiffResult::Compared { count, window, .. } => {
        println!("Different pixels: {count}, busiest window: {window:?}");
        save_png(&output, "diff.png")?;
    }
    DiffResult::DimensionMismatch { a, b } => println!("Sizes differ: {a:?} vs {b:?}"),
}

DiffOptions holds threshold, antialiasing (default true), metric (Yiq or Oklab), mask (one byte per pixel, non-zero is skipped), window, and render (alpha, diff_color, diff_color_alt, aa_color, background). diff returns Err only for buffers that do not match their size and masks of the wrong length.

Structural similarity

This crate is a pixel diff: it answers where two images differ. For how alike they look — SSIM, MS-SSIM, Hitchhiker's SSIM — use blazediff-ssim, which stands alone and shares nothing with this crate but the blazediff-shared primitives. It is also what @blazediff/ssim-native wraps.

Interpret

Structured region analysis that produces human-readable change descriptions. It is not part of this crate: it lives in blazediff-interpret, which consumes what diff returns, with its own blazediff-interpret CLI.

The classifier is independent of whatever found the regions. Anything that can say where something changed can drive it: blazediff-ssim by thresholding a score map, or a caller passing boxes directly. Coarse boxes are fine — each is refined against the source pixels before any statistic is computed, so the analysis stays per-pixel.

See INTERPRET.md for the full algorithm documentation - pipeline stages, formulas, classification rules, and output format.

Performance

3-4x faster than odiff, 8x faster than pixelmatch on 4K images.

Image I/O lives in blazediff-shared, shared with the other crates; load_png, save_jpeg and friends are re-exported here unchanged. PNG I/O defaults to spng. Setting BLAZEDIFF_PNG_ENABLED=1 routes decode and stored (level 0) encode through the in-house blazediff_png codec, which is faster than spng on every fixture.

License

MIT

Metadata

Release files for blazediff 7.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for blazediff 7.0.0
File Actions
blazediff-7.0.0-cp38-abi3-win_arm64.whl CPython 3.8 abi3 Windows ARM64 Details for blazediff-7.0.0-cp38-abi3-win_arm64.whl
blazediff-7.0.0-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details for blazediff-7.0.0-cp38-abi3-win_amd64.whl
blazediff-7.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 abi3 Linux glibc 2.17+ x86-64 Details for blazediff-7.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
blazediff-7.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.8 abi3 Linux glibc 2.17+ ARM64 Details for blazediff-7.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
blazediff-7.0.0-cp38-abi3-macosx_11_0_arm64.whl CPython 3.8 abi3 macOS 11.0+ ARM64 Details for blazediff-7.0.0-cp38-abi3-macosx_11_0_arm64.whl
blazediff-7.0.0-cp38-abi3-macosx_10_12_x86_64.whl CPython 3.8 abi3 macOS 10.12+ x86-64 Details for blazediff-7.0.0-cp38-abi3-macosx_10_12_x86_64.whl

Total release size: 3.8 MB

Release files / blazediff-7.0.0-cp38-abi3-win_arm64.whl

Download URL blazediff-7.0.0-cp38-abi3-win_arm64.whl
Size 575.3 kB
Tags CPython 3.8 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
7db94f8deda279cb022a685d31128c9edaa29c12380bfae5e471063ef15472fe
BLAKE2b-256 checksum
How to use checksums
105aa0321113addbf95eaee893edb71705387b06686fff4979ce670d1cf4b88a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.16.0

Release files / blazediff-7.0.0-cp38-abi3-win_amd64.whl

Download URL blazediff-7.0.0-cp38-abi3-win_amd64.whl
Size 604.0 kB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
4fd8f1c784af26da41efc2b99ccf49ade17596fa322d8868723eee947b14a5c1
BLAKE2b-256 checksum
How to use checksums
0ba8e399b0e1ce4ed7e3c6f5aba55273558a815c560492e79e930ca3609f5a8f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.16.0

Release files / blazediff-7.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL blazediff-7.0.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 711.5 kB
Tags CPython 3.8 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
8adec31479ceb058d60fee80f8457a632dac35141001ff2c5255938f7d4b151f
BLAKE2b-256 checksum
How to use checksums
0addc205a3601a70340c287c013045b090278fde7134c95371cd5a18e2943fa3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.16.0

Release files / blazediff-7.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL blazediff-7.0.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 665.3 kB
Tags CPython 3.8 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
eb40c4b2003b2d74791586847c56ee87c6d4e00816c4fae79c1979f870a3b892
BLAKE2b-256 checksum
How to use checksums
ac2e3e2ba02f33f2c4f9554d6731fec7c1d3e9cad7d60426b6bf62e314c1de28
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.16.0

Release files / blazediff-7.0.0-cp38-abi3-macosx_11_0_arm64.whl

Download URL blazediff-7.0.0-cp38-abi3-macosx_11_0_arm64.whl
Size 595.1 kB
Tags CPython 3.8 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
3e236858664d9581870e01614ac4eecba02e64423f49b6807a9e10ea662ee5e7
BLAKE2b-256 checksum
How to use checksums
dc51eca38ee50ba6044972c502ea1253aebbd14b7bd4faf267d172d261297eae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.16.0

Release files / blazediff-7.0.0-cp38-abi3-macosx_10_12_x86_64.whl

Download URL blazediff-7.0.0-cp38-abi3-macosx_10_12_x86_64.whl
Size 629.8 kB
Tags CPython 3.8 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
804f8d78799f5d8fbe82c4f539b18320466073cdc18aca21caa2ae3fd6576c25
BLAKE2b-256 checksum
How to use checksums
8e9515f66373f0c4f85d431a3476e274396eb05562aa28ffcc1f5f1099579883
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via maturin/1.16.0

Security for blazediff 7.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page