Experimental strictly lossless image codec and research platform written in Rust.
lossless-compression
image-codec
rust
research-codec
predictive-coding
entropy-coding
Pressel is an experimental research codec focused on strict decoded-pixel correctness. It explores tile-adaptive reversible transforms, predictive residual coding, and entropy backends for lossless still-image compression.
Pressel is strictly lossless with respect to decoded RGBA pixel data, not original file bytes.
Pressel preserves byte-identical decoded RGBA pixels. It does not preserve the original PNG bitstream, metadata layout, compression stream, chunk ordering, or file hash. In other words, Pressel is a lossless image codec, not a PNG archiver.
Pressel can optionally preserve PNG metadata, raw ancillary chunks, or the full original PNG source file inside .prsl. Exact original PNG file recovery is only available when --preserve-source-file is used.
Pressel is a Rust project with two related goals:
- Define and test a custom strictly lossless image format,
.prsl. - Build a reproducible research environment for evaluating codec strategies and exact roundtrips.
Pressel is not PNG, JPEG-LS, WebP, QOI, or JPEG XL compatible. It borrows ideas from those codec families, but implements its own pipeline from scratch and does not copy source code from existing codecs.
The current v0.7.1 prototype prioritizes exactness and compression ratio over encode speed. For larger images, multi-core encoding is available through --cores <N>.
Pressel is strictly lossless with respect to decoded RGBA pixel data.
- Decoding must reproduce byte-identical RGBA pixels.
- Hidden RGB values inside transparent pixels must be preserved.
- No visually-lossless shortcuts are allowed.
- No approximate reconstruction is accepted.
This project treats decoded RGBA identity as the core correctness rule, rather than original PNG file-byte identity.
Pressel preserves the decoded image signal, not the original PNG file bitstream. A decoded image must return byte-identical RGBA pixels, but a regenerated PNG file may differ in file size, chunk layout, metadata, or compression structure.
Pressel is experimental research software, not a production image standard. The codec and documentation are intended to support exploration, benchmarking, and demo workflows. Claims about compression effectiveness should be validated with benchmarks rather than assumed.
- Encoder speed is still under active optimization and can be slow on larger natural images.
- The current benchmark corpus is still small and should not be treated as broad proof of superiority.
- The format is experimental and may still change before
1.0. - The current implementation targets RGBA8 decoded-pixel fidelity rather than broad format compatibility.
- Optional source-file preservation is an archival feature, not a compression feature, and will usually increase
.prslsize substantially. - Tooling around the format is still immature; there is no broader editor, browser, or ecosystem integration yet.
- Zstd is still part of the current entropy path, so the codec is not yet a pure custom entropy-coder stack.
Build the release binary:
cargo build --releaseIf you do not already have a test image, generate a synthetic sample first:
./target/release/pressel make-demo-image examples/sample.pngTo generate a different but reproducible sample, pass a seed:
./target/release/pressel make-demo-image examples/sample.png --seed 42Demo flow:
pressel encode examples/sample.png examples/sample.prsl
pressel decode examples/sample.prsl examples/restored.png
pressel verify examples/sample.png examples/sample.prsl
pressel compare examples/sample.png examples/restored.png
pressel bench examples/ --cores 4If pressel is not on your PATH, run the same commands through the built binary directly:
./target/release/pressel encode examples/sample.png examples/sample.prsl
./target/release/pressel decode examples/sample.prsl examples/restored.png
./target/release/pressel verify examples/sample.png examples/sample.prsl
./target/release/pressel compare examples/sample.png examples/restored.png
./target/release/pressel bench examples/The examples/ folder is included for local demo assets and contains guidance on adding your own non-copyrighted test images.
Use this sequence on a fresh clone:
- Build the release binary with
cargo build --release. - Generate a demo image with
./target/release/pressel make-demo-image examples/sample.png. - If you want a different repeatable pattern, use a seed such as
./target/release/pressel make-demo-image examples/sample.png --seed 42. - Encode it with
./target/release/pressel encode examples/sample.png examples/sample.prsl. - Decode it with
./target/release/pressel decode examples/sample.prsl examples/restored.png. - Verify strict equality with
./target/release/pressel verify examples/sample.png examples/sample.prsl. - Compare the source and restored images with
./target/release/pressel compare examples/sample.png examples/restored.png. - Run the benchmark with
./target/release/pressel bench examples/ --cores 4.
Both encode and bench accept an optional --cores <N> flag. If omitted, Pressel uses 1 core by default.
Expected results:
verifyshould print matching SHA-256 hashes andexact match: true.decodeshould produceexamples/restored.png.compareshould reportexact decoded RGBA match: true.benchshould writebench.csvin the repository root.
For the automated test suite, run:
cargo testThat covers strict RGBA roundtrips, transparent hidden RGB preservation, non-64-aligned dimensions, every transform, every predictor, all entropy backends, and the full encode/decode/verify flow.
pressel encode <input-image> <output.prsl> [--cores <usize>] [--preserve-png-metadata] [--preserve-png-chunks] [--preserve-source-file]
pressel decode <input.prsl> [<output.png>] [--export-png <path>] [--extract-source-file <path>]
pressel verify <input-image> <input.prsl>
pressel compare <first-image> <second-image>
pressel bench <folder> [--cores <usize>]
pressel make-demo-image <output.png> [--seed <u64>]
By default, Pressel stores only what it needs for exact decoded RGBA recovery.
- Default mode: exact RGBA only
--preserve-png-metadata: store a curated set of useful PNG metadata chunks such asgAMA,cHRM,sRGB,iCCP,pHYs,tIME,tEXt,zTXt,iTXt, andeXIf--preserve-png-chunks: store all ancillary PNG chunks with placement/order data--preserve-source-file: store the original PNG file byte-for-byte for exact extraction later as a source-preservation mode
--preserve-png-chunks subsumes --preserve-png-metadata. If both are provided, Pressel stores ancillary chunks once in chunk mode and does not duplicate metadata in a second tag.
Examples:
pressel encode image.png image.prsl --preserve-png-metadata
pressel encode image.png image.prsl --preserve-png-chunks
pressel encode image.png image.prsl --preserve-source-file
pressel decode image.prsl --extract-source-file recovered.png
pressel decode image.prsl --export-png restored-with-safe-chunks.pngWhen exporting PNG, Pressel regenerates IHDR/IDAT/IEND from the decoded image and only reattaches preserved ancillary chunks when their placement is valid and safe. Unsafe-to-copy ancillary chunks may be skipped with a warning.
.prsl v1 is a custom tile-based container for exact RGBA reconstruction.
- Extension:
.prsl - Magic bytes:
PRSL1 - Channels: RGBA8 only in v1
- Tile size: stored per file, chosen from an exact whole-image search
- Per-tile strategy selection
- SHA-256 hash of the original raw RGBA byte stream
- Optional tagged sections for preserved PNG metadata, ancillary chunks, or the full original source file
Each tile independently tries multiple reversible transform, predictor, and entropy combinations, then stores the smallest exact result. The current search space includes fixed-width bytewise transforms, an exact structured-plane transform, a seeded QOI-style pixel-cache transform, adaptive predictor maps, a weighted gradient predictor, and raw, Zstd, folded-residual, channel-split, static rANS, context-split, context-adaptive folded rANS, and context-adaptive folded arithmetic/range residual payload storage. The encoder also searches a small set of whole-image tile sizes, uses lightweight per-tile classification heuristics to steer the exact search, and can parallelize tile encoding when --cores is greater than 1.
When decoding back to PNG, Pressel reconstructs the original RGBA pixels exactly, but it does not attempt to recreate the original PNG file bytes exactly.
More detail:
pressel bench <folder> recursively scans a folder, encodes supported images to .prsl, decodes them, verifies exact RGBA identity, and writes bench.csv.
Reported metrics include:
- filename
- width and height
- original file size
.prslsize- compression ratio
- encode time
- decode time
- selected transform counts
- selected predictor counts
- selected entropy backend counts
- verification result
encode and bench default to 1 core. Use --cores <N> when you want faster encode-time experiments on larger images.
Example local results:
Core compression progression:
| Image | PNG size | Gen 1 PRSL | Gen 2 PRSL | Gen 3 PRSL | Gen 4 PRSL | Gen 5 PRSL | Exact RGBA match |
|---|---|---|---|---|---|---|---|
synthetic demo (--seed 42) |
58,770 bytes | 7,633 bytes | 6,745 bytes | 6,745 bytes | 1,895 bytes | 1,895 bytes | true |
| rural photo | 3,891,380 bytes | 2,908,487 bytes | 2,908,487 bytes | 2,907,368 bytes | 2,840,040 bytes | 2,224,193 bytes | true |
Generation 6 preservation results:
| Image | PNG size | Gen 6 default | Gen 6 + metadata | Gen 6 + chunks | Gen 6 + source file | Exact RGBA match |
|---|---|---|---|---|---|---|
synthetic demo (--seed 42) |
58,770 bytes | 1,895 bytes | 1,895 bytes | 1,895 bytes | 60,675 bytes | true |
| rural photo | 3,891,380 bytes | 2,224,772 bytes | 2,224,809 bytes | 2,224,809 bytes | 6,116,162 bytes | true |
Generation 6 is intended to show the size impact of optional PNG preservation modes:
Gen 6 default: exact RGBA onlyGen 6 + metadata: exact RGBA plus curated PNG metadata chunksGen 6 + chunks: exact RGBA plus preserved ancillary PNG chunksGen 6 + source file: exact RGBA plus the original PNG stored byte-for-byte
The generated synthetic sample does not contain meaningful preserved PNG metadata or ancillary chunks, so its Gen 6 default, Gen 6 + metadata, and Gen 6 + chunks sizes are identical. The rural photo is a better example of preservation overhead on a real PNG input.
Cross-codec comparison should be tracked separately from the generation tables above. The Pressel column below reflects the best measured generation result for each file, not a claim that every codec generation behaves the same way.
Gen 7 refers to the current best measured compression-generation result after the preservation-focused Gen 6 changes.
| File | Original PNG | ZopfliPNG | WebP Lossless | JPEG XL Lossless | Pressel |
|---|---|---|---|---|---|
| Rural with transparency | 3,891,380 bytes | 3,587,012 bytes | 2,304,702 bytes | 2,921,490 bytes | Gen 7: 2,154,396 bytes |
| Rural without transparency | 5,231,717 bytes | 4,647,854 bytes | 3,321,184 bytes | 1,868,523 bytes | Gen 7: 3,289,267 bytes |
| Synthetic | 58,770 bytes | 2,605 bytes | 4,674 bytes | 1,933 bytes | Gen 7: 1,895 bytes |
Those comparison numbers should always be reported together with the exact encoder settings used. Current comparison settings:
zopflipng --iterations=1000cwebp -lossless -q 100 -m 6 -exact -mtcjxl -d 0 -e 10 --keep_invisible=1 --num_threads=-1
Keeping those settings visible matters because codec comparisons are only meaningful when the encoder parameters are reproducible.
To measure those four generation 6 variants on the same PNG:
pressel encode examples/rural.png rural-default.prsl
pressel encode examples/rural.png rural-meta.prsl --preserve-png-metadata
pressel encode examples/rural.png rural-chunks.prsl --preserve-png-chunks
pressel encode examples/rural.png rural-source.prsl --preserve-source-fileThen inspect the resulting sizes:
ls -l rural-default.prsl rural-meta.prsl rural-chunks.prsl rural-source.prslFor the rural photo example, verify reported matching decoded RGBA hashes:
original SHA-256: 2d4ad8c726cb2a9ef105e683544b07234c669dc71d976ec4a7767c925bfce05a
decoded SHA-256: 2d4ad8c726cb2a9ef105e683544b07234c669dc71d976ec4a7767c925bfce05a
exact match: true
Pressel is designed as a research codec, not just a file converter.
This project is currently positioned as v0.7.1: a more capable research prototype with encode, decode, verify, compare, bench, and demo-image commands, documentation, strict roundtrip tests, CI, safer decode validation, an expanded reversible transform set, adaptive tile-size search, structured exact plane modeling, a seeded QOI-style pixel-cache transform, residual folding experiments, channel-separated residual coding, static rANS and context-adaptive folded rANS/range residual experiments, weighted-gradient and photo-oriented predictor experiments, lightweight per-tile classification heuristics, aggressive exact compression experiments over raw, folded, Zstd-backed, context-split, context-rANS, and context-range payloads, and optional PNG metadata/chunk/source-file preservation.
- deeper learned or multi-feature arithmetic-coded context modeling beyond the current folded context-range path
- stronger hybrid palette/cache transforms beyond the current seeded QOI-style tile mode
- richer semantic per-tile image classification and recursive split heuristics
Pressel is released under the MIT License.
- Copyright (c) 2026 Petar Stanchev
- See LICENSE