jpeg: conformance fixtures for jpegtran's progressive and 12-bit arithmetic transcodes

This commit is contained in:
aiongg committed 2026-10-24 22:04:21 +00:00
1 parent 2628b8ac9c
commit b4e764e44c
12 files changed
+37 -1

No files matched your search

+2
View File
@@ -112,6 +112,8 @@ SOF11 (lossless) falls in that range and returns `Unsupported`.
- `tests/conformance.rs`, on libjpeg-turbo's test images in `tests/data` (provenance and how
the derived files were made: `tests/data/SOURCE.md`):
- `testimgari.jpg` (SOF9) decodes to exactly the samples of its jpegtran Huffman transcode.
- jpegtran's arithmetic and progressive arithmetic transcodes of `testorig.jpg` (one with
restarts) and `testorig12.jpg` decode to exactly the samples of their sources.
- `whitetail-ari.jpg` (SOF9 from cjpeg, a white lower part that decodes from the zeros
supplied at EOI) decodes undamaged and equal to its Huffman transcode.
- `testorig.jpg` matches `zune-jpeg`, and `testorig12.jpg` matches libjpeg-turbo's 12-bit
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+15
View File
@@ -41,6 +41,21 @@ fn arithmetic_coded_image_matches_its_huffman_transcode() {
assert!(huffman.samples == arithmetic.samples, "testimgari.jpg decodes differently from testimgari-huffman.jpg");
}
/// The arithmetic and progressive arithmetic transcodes jpegtran made of testorig.jpg and
/// testorig12.jpg hold their coefficients, so they decode to exactly the same samples.
#[test]
fn arithmetic_transcodes_match_their_huffman_sources() {
for (source, transcodes) in [
("testorig.jpg", &["testorig-ari-progressive.jpg", "testorig-ari-progressive-restart.jpg"]),
("testorig12.jpg", &["testorig12-ari.jpg", "testorig12-ari-progressive.jpg"]),
] {
let reference = decode_fixture(source);
for name in transcodes {
assert!(decode_fixture(name).samples == reference.samples, "{name} decodes differently from {source}");
}
}
}
/// libjpeg's arithmetic encoder drops the trailing zero bytes of a scan, so the white lower
/// part of whitetail-ari.jpg decodes from zeros supplied at the EOI marker. It must decode
/// whole and match its Huffman transcode.
+4
View File
@@ -5,3 +5,7 @@ acc6ec555d41d15b368320edaa3b20958ee6fa97cb6e4a18d1213d5ae8bec73b testorig.jpg
62d182ed042e243544d3d753c440ada1a6992464717311fe6efd546632f44dc4 testorig12.ppm
0031b82a06300b5b5d19ef5553cc39d3fafafa4fbc474199e6cfbc7818312a87 whitetail-ari.jpg
0f6e17a44be7a005d6610e66f91fa119388dc6b8438e95cb8816b6db58f8c365 whitetail-huffman.jpg
7e7edd9d9825c2eca1e6ff6dfafeaddec39e2464fc5d6d1ce4a378a59ec3f716 testorig-ari-progressive.jpg
cb0a2c60e6a89c68ef8cf48854dc09c77c26ffb27ac62e17d343d98f1424cc77 testorig-ari-progressive-restart.jpg
c4942c4b704d20e27c4cd3e613c6ef975dd7cfe53a756e2c209fa3ad033d8b51 testorig12-ari.jpg
18df0394115d9f8751939fb9f45a0d330df2ca849e9f8b07d0af76c09b90fcdb testorig12-ari-progressive.jpg
+16 -1
View File
@@ -13,12 +13,17 @@ libjpeg-turbo's tools, as described below.
| `testimgari-huffman.jpg` | `testimgari.jpg` losslessly transcoded to baseline Huffman (SOF0) |
| `testorig12.jpg` | 227×149 YCbCr, 12-bit extended sequential Huffman (SOF1) |
| `testorig12.ppm` | libjpeg-turbo's decode of `testorig12.jpg`: 12-bit RGB, binary PPM, maxval 4095 |
| `testorig-ari-progressive.jpg` | `testorig.jpg` transcoded to progressive arithmetic (SOF10) |
| `testorig-ari-progressive-restart.jpg` | the same with a restart interval of 3 MCU rows |
| `testorig12-ari.jpg` | `testorig12.jpg` transcoded to 12-bit arithmetic (SOF9) |
| `testorig12-ari-progressive.jpg` | `testorig12.jpg` transcoded to 12-bit progressive arithmetic (SOF10) |
| `whitetail-ari.jpg` | 512×512 gray, arithmetic coded (SOF9), noise in the top 16 rows, white below |
| `whitetail-huffman.jpg` | `whitetail-ari.jpg` losslessly transcoded to baseline Huffman (SOF0) |
`testimgari.jpg` and `testorig.jpg` share their quantization tables but not their coefficients:
libjpeg-turbo decodes them to different pixels. `testimgari-huffman.jpg` holds exactly the
coefficients of `testimgari.jpg`, so the two must decode to identical samples.
coefficients of `testimgari.jpg`, so the two must decode to identical samples. The same holds
for each jpegtran transcode below and its source.
## How the derived files were made
@@ -29,6 +34,16 @@ coefficients of `testimgari.jpg`, so the two must decode to identical samples.
jpegtran -copy none testimgari.jpg > testimgari-huffman.jpg
```
The arithmetic transcodes of `testorig.jpg` and `testorig12.jpg`, with jpegtran from
libjpeg-turbo 3.1.3 (Alpine 3.24, `libjpeg-turbo-utils`):
```sh
jpegtran -copy none -arithmetic -progressive testorig.jpg > testorig-ari-progressive.jpg
jpegtran -copy none -arithmetic -progressive -restart 3 testorig.jpg > testorig-ari-progressive-restart.jpg
jpegtran -copy none -arithmetic testorig12.jpg > testorig12-ari.jpg
jpegtran -copy none -arithmetic -progressive testorig12.jpg > testorig12-ari-progressive.jpg
```
`testorig12.ppm`, with libjpeg-turbo 3.2.0 through imagecodecs 2026.10.10 (default settings:
integer IDCT `JDCT_ISLOW`, fancy upsampling), run as
`uv run --with imagecodecs --with numpy python make.py testorig12.jpg testorig12.ppm`:
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB