iqa 1.2.1

A single, ergonomic API over the patchwork of visual quality assessment metrics in the Rust ecosystem.
Documentation
[workspace]
members = ["crates/iqa-cli"]
resolver = "2"

[workspace.package]
# Single version shared by the `iqa` library and the `iqa-cli` binary; release-plz
# bumps both crates together (see release-plz.toml).
version = "1.2.1"

[package]
name = "iqa"
version.workspace = true
edition = "2024"
description = "A single, ergonomic API over the patchwork of visual quality assessment metrics in the Rust ecosystem."
license = "MIT OR Apache-2.0"
repository = "https://github.com/justin13888/iqa-rs"
keywords = ["iqa", "image-quality", "ssim", "psnr", "metrics"]
categories = ["multimedia::images", "computer-vision"]
readme = "README.md"
documentation = "https://docs.rs/iqa"
# Minimum supported Rust version. 1.85 is the edition-2024 baseline.
rust-version = "1.85"
build = "build.rs"
# Build-uniqueness key for the shared native archive (libjxl subset + Highway +
# lcms2) that `ssimulacra2` and `butteraugli` both link.
links = "iqa_native"
# The vendored submodules ship far more than build.rs compiles (tests, docs, IDE
# projects, autotools, scatterplot images). Unpruned, the package is 22.8 MiB /
# 10.0 MiB compressed — just over crates.io's 10 MiB limit, so publishing 413s.
# Drop everything that isn't a source/header the native build actually consumes:
# lcms2 needs only `include/` + `src/`, highway only `hwy/`, ssimulacra2 only
# `src/`. The verify build (default features) compiles all of it, so an
# over-exclusion fails `cargo package` rather than shipping a broken crate.
exclude = [
    "third_party/lcms2/testbed",
    "third_party/lcms2/plugins",
    "third_party/lcms2/doc",
    "third_party/lcms2/Projects",
    "third_party/lcms2/utils",
    "third_party/lcms2/m4",
    "third_party/highway/g3doc",
    "third_party/highway/docs",
    "third_party/highway/debian",
    "third_party/ssimulacra2/*.svg",
    # Reference papers (e.g. references/IWSSIM.pdf) are repo documentation, not
    # part of the crate; keep the multi-MB binaries out of the published package.
    "references/*.pdf",
]

[features]
# All metrics are enabled by default for convenience. Depend on iqa with
# `default-features = false` and opt into exactly the metrics you need to keep
# the build pure-Rust (see the README).
default = ["full", "vendored-lcms2"]
full = ["psnr", "ssim", "dssim", "ms-ssim", "iw-ssim", "psnr-hvs-m", "ciede2000", "ssimulacra2", "butteraugli"]
psnr = []
ssim = []
# PSNR-HVS-M (Ponomarenko et al. 2007): DCT-domain PSNR with a contrast-
# sensitivity function and between-coefficient contrast masking. Pure Rust.
psnr-hvs-m = []
# CIEDE2000 (Sharma et al. 2005): mean perceptual color difference (ΔE₀₀) over
# sRGB→CIELAB (D65). Pure Rust.
ciede2000 = []
# Structural dissimilarity, `(1 - SSIM) / 2`. Pure Rust; a thin transform over
# `ssim`, which it therefore enables.
dssim = ["ssim"]
# Multi-scale SSIM (Wang/Simoncelli/Bovik 2003). Pure Rust; evaluates `ssim`'s
# per-window machinery over an image pyramid, so it enables `ssim`.
ms-ssim = ["ssim"]
# Information content weighted SSIM (Wang & Li 2011). Pure Rust; a Laplacian-
# pyramid extension of MS-SSIM that pools `ssim`'s contrast-structure maps by a
# Gaussian-Scale-Mixture information weight, so it enables `ssim`.
iw-ssim = ["ssim"]
ssimulacra2 = ["dep:cc"]
# Butteraugli, also bound to vendored libjxl C++; shares the native build (and
# therefore the lcms2 backend) with `ssimulacra2`.
butteraugli = ["dep:cc"]
# lcms2 backend for the C++ metrics' color management. Mutually exclusive: enable
# exactly one (build.rs enforces the XOR with `compile_error!`). `vendored-lcms2`
# builds the library from the `third_party/lcms2` submodule (default, no system
# dependency); `system-lcms2` links a system lcms2 via pkg-config instead. Note
# this means `--all-features` is not a valid build — name the backend you want.
vendored-lcms2 = []
system-lcms2 = ["dep:pkg-config"]

[workspace.dependencies]
# Single source of truth for the `iqa` dependency requirement that `iqa-cli`
# publishes against. Keep this version in step with `workspace.package.version`
# above so a release only touches this file (`iqa-cli` inherits via
# `iqa = { workspace = true }`). The `path` resolves to the root `iqa` crate for
# local/workspace builds; the `version` is what crates.io publishes against.
iqa = { path = ".", version = "1.2.1" }

[dependencies]
thiserror = "2.0.18"
tracing = "0.1.44"

[build-dependencies]
cc = { version = "1", optional = true }
pkg-config = { version = "0.3", optional = true }

[dev-dependencies]
# Used by examples to decode PNG/JPEG files into iqa inputs, and by
# tests/butteraugli_reference.rs to read the committed PPM fixtures (the same
# files libjxl's `butteraugli_main` scores, so the cross-validation feeds both
# sides identical pixels).
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "pnm"] }

[[example]]
name = "compare"
required-features = ["psnr", "ssim", "dssim", "ms-ssim", "iw-ssim", "psnr-hvs-m", "ciede2000", "ssimulacra2", "butteraugli"]

[package.metadata.docs.rs]
# Document every metric (including the C++ ones) on docs.rs, matching the default
# build. The lcms2 backends are mutually exclusive, so `all-features` is not a
# valid build; name the metric set explicitly and pin the vendored backend so
# docs.rs needs no system library (the vendored C++ ships in the published crate).
features = ["psnr", "ssim", "dssim", "ms-ssim", "iw-ssim", "psnr-hvs-m", "ciede2000", "ssimulacra2", "butteraugli", "vendored-lcms2"]