A from-scratch C++ image codec for compact, progressive image streams, built around a reversible YCoCg-R transform, a 5/3 lifting pyramid, adaptive Rice/rANS entropy coding, and deterministic CPU execution.
- Deterministic CPU encoder/decoder with a small C++ API and command-line tool
- Progressive coarse-to-fine streams and arbitrary-resolution decode
- RGB/RGBA input, lossless quality-100 mode, optional 4:2:0 chroma at lossy qualities
- Compact 16-byte chunk directory and v7 rANS payloads (older v1-v6 streams decode)
- Reproducible CMake build, CTest round-trip coverage, malformed-header checks, and fuzz tooling
- Strongest measured results are on the checked-in v7 quick local-MS-SSIM proxy: CAPS beats JPEG 2000 at all three gates and has a faster encode/decode path than AVIF and JPEG 2000 in that reference run
These are measured strengths, not a claim that Brushie is the best codec overall. On the checked-in SSIMULACRA2/Butteraugli landscape, JPEG XL, WebP, and AVIF are generally smaller at comparable perceptual gates.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON
cmake --build build -j8
ctest --test-dir build --output-on-failure
# PPM works without optional dependencies
build/brushie encode input.ppm output.brbr 82 8 32
build/brushie decode output.brbr output.ppm 4096 4096 -1PNG input/output is available when CMake finds libpng. The CLI does not preserve PNG metadata or 16-bit samples.
Brushie maps RGB into reversible YCoCg-R planes, decomposes them with a 5/3 wavelet pyramid, quantizes detail by frequency and quality, and codes whole-band symbols with causal significance/sign contexts and Rice magnitudes. Chunks are ordered coarse-to-fine so a decoder can stop after a physical prefix. Quality 100 uses the reversible transform without lossy chroma subsampling.
The figure above is generated from the compact public benchmark snapshot in scripts/plot_readme_benchmarks.py:
MPLBACKEND=Agg uv run --with pandas --with matplotlib \
python scripts/plot_readme_benchmarks.pyThe left panel shows all codecs at the three local-window MS-SSIM proxy gates; Brushie beats JPEG 2000 at each gate in this quick snapshot. The right panel shows the .985 timing comparison against AVIF and JPEG 2000, where Brushie is faster. JPEG and WebP remain faster overall, and AVIF/WebP remain smaller. These proxy metrics are not a substitute for SSIMULACRA2, Butteraugli, or blinded human preference.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j8
ctest --test-dir build --output-on-failureWhere CMake is not installed, the equivalent build is:
mkdir -p build
clang++ -std=c++17 -O3 -ffast-math -Iinclude src/codec.cpp src/main.cpp -o build/brushie -pthread
# PNG I/O (optional): add -DBRUSHIE_HAVE_PNG and link libpngThe canonical C++ test is built by CMake and run with CTest:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON
cmake --build build -j8
ctest --test-dir build --output-on-failureOptional Python metric tests require NumPy (and Pillow for the broader benchmark scripts):
python3 tests/test_quality_metrics.py
python3 tests/test_enterprise_eval_helpers.pyThe CLI reads and writes PPM, and PNG (RGB or RGBA) when built with libpng:
build/brushie encode input.ppm output.brbr 45 8 64
build/brushie decode output.brbr output.ppm 4096 4096 -1RGBA PNGs round-trip losslessly at quality 100 (alpha is coded at full resolution); at lossy qualities the alpha channel keeps hard edges.
decode ... 0 emits the coarse LL layer only. -1 emits every available
layer. The decoder may request any output width and height; it reconstructs
the needed pyramid prefix and bilinearly resamples.
Quality 1..100; 100 is exactly lossless (5/3 + YCoCg-R are reversible, chroma is kept 4:4:4). Lower qualities use 4:2:0 chroma and progressively coarser steps. One-pass analytical rate hints (the actual byte count is reported):
build/brushie encode input.ppm output.brbr --target-bytes 250000 --threads 8
build/brushie encode input.ppm output.brbr --target-lpips 0.06 --threads 8--target-lpips is only a heuristic quality preset; no LPIPS model is
linked or evaluated by the deterministic CPU core, and the CLI labels the
result target_lpips_unverified. Do not treat it as an LPIPS target.
PNG support is optional and is enabled only when CMake finds libpng. A build without libpng is PPM-only; the no-CMake command below intentionally builds PPM-only. Input PNG metadata and 16-bit samples are not preserved by the optional CLI path.
For the Python metric tests, install Python 3 with NumPy (and Pillow for the broader evaluation scripts). The codec library and C++ round-trip test do not require Python.
The detailed research tables are intentionally hidden from the public source tree. The compact numbers used in the README graph are preserved in scripts/plot_readme_benchmarks.py; run that script to regenerate the image. Full benchmark sweeps can be run against a local dataset checkout with scripts/enterprise_eval.py, but their generated CSV/Markdown artifacts remain local.
