-
Notifications
You must be signed in to change notification settings - Fork 2
Comparison with other tools
How packJPG stacks up against the other lossless JPEG recompressors and adjacent codecs. Numbers below are measured on a representative 6-file / ~3.7 MB JPEG corpus; use them as ballpark — your mileage will vary by content.
| Tool | Ratio vs packJPG | Decode speed | Status |
|---|---|---|---|
| packJPG v4.0e | reference (-21 % vs raw JPEG) | reference | active LTS |
| Brunsli | -1 to -2 % (worse) | 2-3× faster | actively maintained (Google) |
| Lepton | ≈ identical | comparable | archived 2023 (Dropbox) |
JXL --lossless_jpeg |
+4.27 % (worse) | n/a (different format) | actively maintained (libjxl) |
Short answer: packJPG is on the Pareto frontier for ratio. If you need maximum compression and the format-lock-in is acceptable, packJPG is the right tool. If you need fast streaming decode, Brunsli is worth the small ratio cost.
Measured on a 6-file 3.76 MB corpus of mixed natural-photo JPEGs:
| File | Original (.jpg) |
packJPG v4.0c (.pjg) |
cjxl --lossless_jpeg=1 -e 9
|
jxl/pjg ratio |
|---|---|---|---|---|
| 0028B2CCB | 438,466 | 292,697 | 309,278 | 105.66 % |
| 03BBDEEFD | 733,040 | 625,361 | 651,808 | 104.23 % |
| 042888CB3 | 509,183 | 394,037 | 411,868 | 104.53 % |
| 042B9B813 | 516,642 | 411,133 | 427,736 | 104.04 % |
| 06FDB6EDE | 325,339 | 257,455 | 263,799 | 102.46 % |
| 0D5362BB7 | 1,241,507 | 1,059,680 | 1,105,625 | 104.34 % |
| TOTAL | 3,764,177 | 3,040,363 (80.77 %) | 3,170,114 (84.22 %) | +4.27 % |
JXL's lossless-JPEG mode targets ~20 % off baseline; packJPG hits ~19 % on the same files but with a more aggressive entropy coder, netting it ahead by ~4 % on this corpus. JXL -e 10 (max effort) is 0.1 % worse than -e 9 — so the gap isn't a tuning artifact.
- Entropy coder: custom binary arithmetic coder with PPM order-2 context model.
- Transforms: strips Huffman, separates DC from AC, splits AC by zigzag position, predicts DC from neighbours (averaged + diagonal-variance), Lakhani edge predictor for AC.
- Cross-component: v4.0+ uses Y's bit-length as an extra context for Cb/Cr in 4:4:4 sub-formats.
-
Format: custom
.pjg, version byte + sub-markers.
- Entropy coder: rANS with 18-symbol alphabet, 10-bit precision tables.
- Transforms: similar coefficient repacking to packJPG.
- Strength: decode speed (single-state rANS is ~3-5× faster than binary arithmetic).
- Trade-off: fixed alphabet limit forces multi-stage encoding for symbols > 18, costing some compression density.
- Maintenance: active (commits May 2026 in the upstream repo).
- Entropy coder: VP8-style binary arithmetic.
- Transforms: richer than packJPG — pixel-domain DC predictor (IDCT of neighbour blocks), Lakhani edge predictor, neighbour-presence templates, neighbour nonzero counts as context.
- Strength: designed for streaming decode (resumable, bounded memory).
- Trade-off: Per the NSDI '17 paper (Horn et al.), ratio is ≈ within 0.5 % of packJPG. The win is in streaming throughput, not size.
-
Maintenance: archived 2023-02-14. Microsoft maintains a Rust port at
microsoft/lepton_jpeg_rust.
- Entropy coder: rANS with meta-adaptive (MA) context trees — DAGs of context selectors signaled per-image.
- Transforms: runs DCT coefficients through JXL's VarDCT entropy stage.
-
Format: outputs
.jxl(not interchangeable with.pjg); decoders decode either to the original JPEG or to native JXL display. - Maintenance: actively maintained (libjxl 0.11+, contributions through 2025-2026).
| Need | Pick |
|---|---|
| Maximum ratio, archival use | packJPG |
| Fastest decode, small ratio penalty | Brunsli |
| Streaming JPEG transcoding | Lepton (Rust port) |
| Future-proof image format (not just JPEG) | JPEG XL |
| Already in the JXL ecosystem | cjxl --lossless_jpeg |
For backups and "download original" hosted images where bit-exact recovery matters, packJPG. For HTTP delivery of recompressed images, JXL or WebP. For high-throughput cold storage (Dropbox-style), Lepton's Rust port.
JPEG redundancy lives mostly in:
- The Huffman entropy stage (table-coded, sub-optimal vs adaptive arithmetic).
- Inter-block correlation between DCT coefficients of neighbouring 8×8 blocks.
packJPG's PPM order-2 model captures (1) and most of (2). Five empirical attempts during 2026-04 / 2026-05 to push further (SITX-style 2-way DC ensemble, SITX-style 2-way AC bpos ensemble in 4 weight variants, pre-trained PPM priors at 3 strengths) all lost ratio relative to v4.0c. PPM order-2 with adaptive escape turns out to be very hard to beat on this signal.
External evidence backs the plateau: the NSDI '17 Lepton paper notes Lepton is "roughly equivalent" to packJPG on ratio; JXL with its meta-adaptive context trees still trails by ~4 % on tested corpora; Brunsli explicitly accepts a ratio loss in exchange for decode speed.
This is why the v4.0 line is positioned as LTS — the recompression ratio has plateaued, so releases focus on stability, tooling, and embedding rather than format changes. The line is format-stable since v4.0b; anything that would break the .pjg format would land in a future v4.1.
Sample command for the JXL comparison:
# Encode with cjxl
cjxl --lossless_jpeg=1 -e 9 photo.jpg photo.jxl
# Encode with packJPG
packJPG a photo.jpg
# Compare
ls -l photo.jpg photo.jxl photo.pjg
For ratio benchmarks across a corpus, run the encode in a loop and sum file sizes. The -vp flag in packJPG gives a progress bar; cjxl has its own --quiet etc.