mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-08 19:42:12 +00:00
jpeg: conformance tests against the libjpeg-turbo test images
Commit testorig.jpg, testimgari.jpg and testorig12.jpg with a jpegtran Huffman transcode of testimgari.jpg and libjpeg-turbo's 12-bit decode of testorig12.jpg. The arithmetic-coded image must match its transcode exactly; the 8-bit and 12-bit decodes are compared against zune-jpeg and libjpeg-turbo within a small tolerance. Replaces the ignored conformance_samples test.
This commit is contained in:
1 parent
6354ef2728
commit
f28de79037
10 files changed
+407
-23
No files matched your search
@@ -19,29 +19,6 @@ fn u16_samples(img: &Decoded) -> &[u16] {
|
||||
}
|
||||
}
|
||||
|
||||
/// Local check against the conformance samples (never committed): set `CRAFT_JPEG_SAMPLES` to a
|
||||
/// directory holding testorig.jpg, testorig12.jpg and testimgari.jpg.
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn conformance_samples() {
|
||||
let dir = std::env::var("CRAFT_JPEG_SAMPLES").unwrap();
|
||||
let read = |n: &str| std::fs::read(format!("{dir}/{n}")).unwrap();
|
||||
let (ref8, dimensions) = zune_decode(&read("testorig.jpg"));
|
||||
for (name, sixteen) in [("testorig12.jpg", true), ("testimgari.jpg", false)] {
|
||||
let img = decode_default(&read(name)).unwrap();
|
||||
assert_eq!((img.width, img.height), dimensions, "{name}");
|
||||
assert_eq!(matches!(img.samples, Samples::U16(_)), sixteen, "{name}");
|
||||
assert!(!img.damaged, "{name}");
|
||||
let px: Vec<f32> = match &img.samples {
|
||||
Samples::U16(v) => v.iter().map(|&v| v as f32 / 257.0).collect(),
|
||||
Samples::U8(v) => v.iter().map(|&v| v as f32).collect(),
|
||||
};
|
||||
let mad = px.iter().zip(&ref8).map(|(a, &b)| (a - b as f32).abs()).sum::<f32>() / px.len() as f32;
|
||||
eprintln!("{name}: mean abs diff vs testorig.jpg {mad}");
|
||||
assert!(mad < 3.0, "{name}: {mad}");
|
||||
}
|
||||
}
|
||||
|
||||
// --- A test-only arithmetic encoder (T.81 D.1, F.1.4 and G.1.3), mirroring the decoder ---
|
||||
|
||||
struct Enc {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
//! Decodes of the libjpeg-turbo test images (tests/data, see SOURCE.md there).
|
||||
|
||||
use craft_jpeg::{Decoded, Limits, Samples, decode};
|
||||
|
||||
fn fixture(name: &str) -> Vec<u8> {
|
||||
let path = format!("{}/tests/data/{name}", env!("CARGO_MANIFEST_DIR"));
|
||||
std::fs::read(&path).unwrap_or_else(|e| panic!("{path}: {e}"))
|
||||
}
|
||||
|
||||
fn decode_fixture(name: &str) -> Decoded {
|
||||
let img = decode(&fixture(name), &Limits::default(), None).unwrap_or_else(|e| panic!("{name}: {e}"));
|
||||
assert_eq!((img.width, img.height, img.components), (227, 149, 3), "{name}");
|
||||
assert!(!img.damaged, "{name}");
|
||||
img
|
||||
}
|
||||
|
||||
/// Mean and maximum absolute difference.
|
||||
fn diff(a: impl Iterator<Item = f64>, b: impl Iterator<Item = f64>) -> (f64, f64) {
|
||||
let (mut sum, mut max, mut n) = (0.0, 0.0f64, 0usize);
|
||||
for (a, b) in a.zip(b) {
|
||||
let d = (a - b).abs();
|
||||
sum += d;
|
||||
max = max.max(d);
|
||||
n += 1;
|
||||
}
|
||||
(sum / n.max(1) as f64, max)
|
||||
}
|
||||
|
||||
/// testimgari-huffman.jpg is testimgari.jpg transcoded by jpegtran: the same coefficients, only
|
||||
/// the entropy coding differs, so the samples must be identical.
|
||||
#[test]
|
||||
fn arithmetic_coded_image_matches_its_huffman_transcode() {
|
||||
let huffman = decode_fixture("testimgari-huffman.jpg");
|
||||
let arithmetic = decode_fixture("testimgari.jpg");
|
||||
assert!(matches!(huffman.samples, Samples::U8(_)));
|
||||
assert!(huffman.samples == arithmetic.samples, "testimgari.jpg decodes differently from testimgari-huffman.jpg");
|
||||
}
|
||||
|
||||
/// The 8-bit path against zune-jpeg. Both use centered linear chroma upsampling; the residual is
|
||||
/// float against integer IDCT and color conversion.
|
||||
#[test]
|
||||
fn baseline_image_matches_zune_jpeg() {
|
||||
let bytes = fixture("testorig.jpg");
|
||||
let mut zune = zune_jpeg::JpegDecoder::new(zune_jpeg::zune_core::bytestream::ZCursor::new(&bytes[..]));
|
||||
let reference = zune.decode().unwrap_or_else(|e| panic!("zune-jpeg: {e:?}"));
|
||||
let img = decode_fixture("testorig.jpg");
|
||||
let Samples::U8(px) = &img.samples else { panic!("testorig.jpg: expected 8-bit samples") };
|
||||
assert_eq!(px.len(), reference.len());
|
||||
let (mean, max) = diff(px.iter().map(|&v| f64::from(v)), reference.iter().map(|&v| f64::from(v)));
|
||||
eprintln!("testorig.jpg vs zune-jpeg: mean {mean:.3}, max {max}");
|
||||
assert!(mean < MAX_MEAN_8 && max <= MAX_ABS_8, "mean {mean}, max {max}");
|
||||
}
|
||||
|
||||
// Observed: mean 0.52, max 3.
|
||||
const MAX_MEAN_8: f64 = 0.75;
|
||||
const MAX_ABS_8: f64 = 4.0;
|
||||
|
||||
/// Parse a binary PPM with 16-bit big-endian samples.
|
||||
fn ppm16(bytes: &[u8]) -> (u32, u32, u32, Vec<u16>) {
|
||||
let mut fields = Vec::new();
|
||||
let mut at = 0;
|
||||
while fields.len() < 4 {
|
||||
while bytes.get(at).is_some_and(u8::is_ascii_whitespace) {
|
||||
at += 1;
|
||||
}
|
||||
let start = at;
|
||||
while bytes.get(at).is_some_and(|b| !b.is_ascii_whitespace()) {
|
||||
at += 1;
|
||||
}
|
||||
fields.push(std::str::from_utf8(&bytes[start..at]).unwrap_or_default().to_owned());
|
||||
}
|
||||
assert_eq!(fields[0], "P6");
|
||||
let num = |s: &str| s.parse::<u32>().unwrap_or_else(|e| panic!("PPM header {s}: {e}"));
|
||||
let (w, h, maxval) = (num(&fields[1]), num(&fields[2]), num(&fields[3]));
|
||||
let data = &bytes[at + 1..];
|
||||
let px: Vec<u16> = data.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||
assert_eq!(px.len(), (w * h * 3) as usize);
|
||||
(w, h, maxval, px)
|
||||
}
|
||||
|
||||
/// testorig12.jpg against libjpeg-turbo's decode (testorig12.ppm, 12-bit RGB; SOURCE.md says how
|
||||
/// it was made). libjpeg-turbo uses an integer IDCT and integer color conversion, craft-jpeg
|
||||
/// floats; the comparison is on the 12-bit scale.
|
||||
#[test]
|
||||
fn twelve_bit_image_matches_libjpeg_turbo() {
|
||||
let (w, h, maxval, reference) = ppm16(&fixture("testorig12.ppm"));
|
||||
assert_eq!((w, h, maxval), (227, 149, 4095));
|
||||
let img = decode_fixture("testorig12.jpg");
|
||||
let Samples::U16(px) = &img.samples else { panic!("testorig12.jpg: expected 16-bit samples") };
|
||||
assert_eq!(px.len(), reference.len());
|
||||
let (mean, max) = diff(px.iter().map(|&v| f64::from(v) * 4095.0 / 65535.0), reference.iter().map(|&v| f64::from(v)));
|
||||
eprintln!("testorig12.jpg vs libjpeg-turbo (12-bit units): mean {mean:.3}, max {max:.2}");
|
||||
assert!(mean < MAX_MEAN_12 && max <= MAX_ABS_12, "mean {mean}, max {max}");
|
||||
}
|
||||
|
||||
// Observed: mean 0.50, max 2.46 (of 4095).
|
||||
const MAX_MEAN_12: f64 = 0.75;
|
||||
const MAX_ABS_12: f64 = 4.0;
|
||||
@@ -0,0 +1,258 @@
|
||||
libjpeg-turbo note: This file has been modified by The libjpeg-turbo Project
|
||||
to include only information relevant to libjpeg-turbo, to wordsmith certain
|
||||
sections, and to remove impolitic language that existed in the libjpeg v8
|
||||
README. It is included only for reference. Please see README.md for
|
||||
information specific to libjpeg-turbo.
|
||||
|
||||
|
||||
The Independent JPEG Group's JPEG software
|
||||
==========================================
|
||||
|
||||
This distribution contains a release of the Independent JPEG Group's free JPEG
|
||||
software. You are welcome to redistribute this software and to use it for any
|
||||
purpose, subject to the conditions under LEGAL ISSUES, below.
|
||||
|
||||
This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
|
||||
Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
|
||||
Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
|
||||
and other members of the Independent JPEG Group.
|
||||
|
||||
IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
|
||||
(also known as JPEG, together with ITU-T SG16).
|
||||
|
||||
|
||||
DOCUMENTATION ROADMAP
|
||||
=====================
|
||||
|
||||
This file contains the following sections:
|
||||
|
||||
OVERVIEW General description of JPEG and the IJG software.
|
||||
LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
|
||||
REFERENCES Where to learn more about JPEG.
|
||||
ARCHIVE LOCATIONS Where to find newer versions of this software.
|
||||
FILE FORMAT WARS Software *not* to get.
|
||||
TO DO Plans for future IJG releases.
|
||||
|
||||
Other documentation files in the distribution are:
|
||||
|
||||
User documentation:
|
||||
usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
|
||||
rdjpgcom, and wrjpgcom.
|
||||
*.1 Unix-style man pages for programs (same info as usage.txt).
|
||||
wizard.txt Advanced usage instructions for JPEG wizards only.
|
||||
change.log Version-to-version change highlights.
|
||||
Programmer and internal documentation:
|
||||
libjpeg.txt How to use the JPEG library in your own programs.
|
||||
example.c Sample code for calling the JPEG library.
|
||||
structure.txt Overview of the JPEG library's internal structure.
|
||||
coderules.txt Coding style rules --- please read if you contribute code.
|
||||
|
||||
Please read at least usage.txt. Some information can also be found in the JPEG
|
||||
FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find
|
||||
out where to obtain the FAQ article.
|
||||
|
||||
If you want to understand how the JPEG code works, we suggest reading one or
|
||||
more of the REFERENCES, then looking at the documentation files (in roughly
|
||||
the order listed) before diving into the code.
|
||||
|
||||
|
||||
OVERVIEW
|
||||
========
|
||||
|
||||
This package contains C software to implement JPEG image encoding, decoding,
|
||||
and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
|
||||
method for full-color and grayscale images. JPEG's strong suit is compressing
|
||||
photographic images or other types of images that have smooth color and
|
||||
brightness transitions between neighboring pixels. Images with sharp lines or
|
||||
other abrupt features may not compress well with JPEG, and a higher JPEG
|
||||
quality may have to be used to avoid visible compression artifacts with such
|
||||
images.
|
||||
|
||||
JPEG is normally lossy, meaning that the output pixels are not necessarily
|
||||
identical to the input pixels. However, on photographic content and other
|
||||
"smooth" images, very good compression ratios can be obtained with no visible
|
||||
compression artifacts, and extremely high compression ratios are possible if
|
||||
you are willing to sacrifice image quality (by reducing the "quality" setting
|
||||
in the compressor.)
|
||||
|
||||
This software implements JPEG baseline, extended-sequential, progressive, and
|
||||
lossless compression processes. Provision is made for supporting all variants
|
||||
of these processes, although some uncommon parameter settings aren't
|
||||
implemented yet. We have made no provision for supporting the hierarchical
|
||||
processes defined in the standard.
|
||||
|
||||
We provide a set of library routines for reading and writing JPEG image files,
|
||||
plus two sample applications "cjpeg" and "djpeg", which use the library to
|
||||
perform conversion between JPEG and some other popular image file formats.
|
||||
The library is intended to be reused in other applications.
|
||||
|
||||
In order to support file conversion and viewing software, we have included
|
||||
considerable functionality beyond the bare JPEG coding/decoding capability;
|
||||
for example, the color quantization modules are not strictly part of JPEG
|
||||
decoding, but they are essential for output to colormapped file formats or
|
||||
colormapped displays. These extra functions can be compiled out of the
|
||||
library if not required for a particular application.
|
||||
|
||||
We have also included "jpegtran", a utility for lossless transcoding between
|
||||
different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
|
||||
applications for inserting and extracting textual comments in JFIF files.
|
||||
|
||||
The emphasis in designing this software has been on achieving portability and
|
||||
flexibility, while also making it fast enough to be useful. In particular,
|
||||
the software is not intended to be read as a tutorial on JPEG. (See the
|
||||
REFERENCES section for introductory material.) Rather, it is intended to
|
||||
be reliable, portable, industrial-strength code. We do not claim to have
|
||||
achieved that goal in every aspect of the software, but we strive for it.
|
||||
|
||||
We welcome the use of this software as a component of commercial products.
|
||||
No royalty is required, but we do ask for an acknowledgement in product
|
||||
documentation, as described under LEGAL ISSUES.
|
||||
|
||||
|
||||
LEGAL ISSUES
|
||||
============
|
||||
|
||||
In plain English:
|
||||
|
||||
1. We don't promise that this software works. (But if you find any bugs,
|
||||
please let us know!)
|
||||
2. You can use this software for whatever you want. You don't have to pay us.
|
||||
3. You may not pretend that you wrote this software. If you use it in a
|
||||
program, you must acknowledge somewhere in your documentation that
|
||||
you've used the IJG code.
|
||||
|
||||
In legalese:
|
||||
|
||||
The authors make NO WARRANTY or representation, either express or implied,
|
||||
with respect to this software, its quality, accuracy, merchantability, or
|
||||
fitness for a particular purpose. This software is provided "AS IS", and you,
|
||||
its user, assume the entire risk as to its quality and accuracy.
|
||||
|
||||
This software is copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
|
||||
All Rights Reserved except as specified below.
|
||||
|
||||
Permission is hereby granted to use, copy, modify, and distribute this
|
||||
software (or portions thereof) for any purpose, without fee, subject to these
|
||||
conditions:
|
||||
(1) If any part of the source code for this software is distributed, then this
|
||||
README file must be included, with this copyright and no-warranty notice
|
||||
unaltered; and any additions, deletions, or changes to the original files
|
||||
must be clearly indicated in accompanying documentation.
|
||||
(2) If only executable code is distributed, then the accompanying
|
||||
documentation must state that "this software is based in part on the work of
|
||||
the Independent JPEG Group".
|
||||
(3) Permission for use of this software is granted only if the user accepts
|
||||
full responsibility for any undesirable consequences; the authors accept
|
||||
NO LIABILITY for damages of any kind.
|
||||
|
||||
These conditions apply to any software derived from or based on the IJG code,
|
||||
not just to the unmodified library. If you use our work, you ought to
|
||||
acknowledge us.
|
||||
|
||||
Permission is NOT granted for the use of any IJG author's name or company name
|
||||
in advertising or publicity relating to this software or products derived from
|
||||
it. This software may be referred to only as "the Independent JPEG Group's
|
||||
software".
|
||||
|
||||
We specifically permit and encourage the use of this software as the basis of
|
||||
commercial products, provided that all warranty or liability claims are
|
||||
assumed by the product vendor.
|
||||
|
||||
|
||||
REFERENCES
|
||||
==========
|
||||
|
||||
We recommend reading one or more of these references before trying to
|
||||
understand the innards of the JPEG software.
|
||||
|
||||
The best short technical introduction to the JPEG compression algorithm is
|
||||
Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
|
||||
Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
|
||||
(Adjacent articles in that issue discuss MPEG motion picture compression,
|
||||
applications of JPEG, and related topics.) If you don't have the CACM issue
|
||||
handy, a PDF file containing a revised version of Wallace's article is
|
||||
available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually
|
||||
a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
|
||||
omits the sample images that appeared in CACM, but it includes corrections
|
||||
and some added material. Note: the Wallace article is copyright ACM and IEEE,
|
||||
and it may not be used for commercial purposes.
|
||||
|
||||
A somewhat less technical, more leisurely introduction to JPEG can be found in
|
||||
"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
|
||||
M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
|
||||
good explanations and example C code for a multitude of compression methods
|
||||
including JPEG. It is an excellent source if you are comfortable reading C
|
||||
code but don't know much about data compression in general. The book's JPEG
|
||||
sample code is far from industrial-strength, but when you are ready to look
|
||||
at a full implementation, you've got one here...
|
||||
|
||||
The best currently available description of JPEG is the textbook "JPEG Still
|
||||
Image Data Compression Standard" by William B. Pennebaker and Joan L.
|
||||
Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
|
||||
Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
|
||||
standards (DIS 10918-1 and draft DIS 10918-2).
|
||||
|
||||
The original JPEG standard is divided into two parts, Part 1 being the actual
|
||||
specification, while Part 2 covers compliance testing methods. Part 1 is
|
||||
titled "Digital Compression and Coding of Continuous-tone Still Images,
|
||||
Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
|
||||
10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
|
||||
Continuous-tone Still Images, Part 2: Compliance testing" and has document
|
||||
numbers ISO/IEC IS 10918-2, ITU-T T.83.
|
||||
|
||||
The JPEG standard does not specify all details of an interchangeable file
|
||||
format. For the omitted details, we follow the "JFIF" conventions, revision
|
||||
1.02. JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and
|
||||
Recommendation ITU-T T.871 (05/2011): Information technology - Digital
|
||||
compression and coding of continuous-tone still images: JPEG File Interchange
|
||||
Format (JFIF). It is available as a free download in PDF file format from
|
||||
https://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.
|
||||
A PDF file of the older JFIF 1.02 specification is available at
|
||||
http://www.w3.org/Graphics/JPEG/jfif3.pdf.
|
||||
|
||||
The TIFF 6.0 file format specification can be obtained from
|
||||
http://mirrors.ctan.org/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation
|
||||
scheme found in the TIFF 6.0 spec of 3-June-92 has a number of serious
|
||||
problems. IJG does not recommend use of the TIFF 6.0 design (TIFF Compression
|
||||
tag 6). Instead, we recommend the JPEG design proposed by TIFF Technical Note
|
||||
#2 (Compression tag 7). Copies of this Note can be obtained from
|
||||
http://www.ijg.org/files/. It is expected that the next revision
|
||||
of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
|
||||
Although IJG's own code does not support TIFF/JPEG, the free libtiff library
|
||||
uses our library to implement TIFF/JPEG per the Note.
|
||||
|
||||
|
||||
ARCHIVE LOCATIONS
|
||||
=================
|
||||
|
||||
The "official" archive site for this software is www.ijg.org.
|
||||
The most recent released version can always be found there in
|
||||
directory "files".
|
||||
|
||||
The JPEG FAQ (Frequently Asked Questions) article is a source of some
|
||||
general information about JPEG. It is available at
|
||||
http://www.faqs.org/faqs/jpeg-faq.
|
||||
|
||||
|
||||
FILE FORMAT COMPATIBILITY
|
||||
=========================
|
||||
|
||||
This software implements ITU T.81 | ISO/IEC 10918 with some extensions from
|
||||
ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).
|
||||
Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or
|
||||
a subset thereof, but there are other formats containing the name "JPEG" that
|
||||
are incompatible with the original JPEG standard or with JFIF (for instance,
|
||||
JPEG 2000 and JPEG XR). This software therefore does not support these
|
||||
formats. Indeed, one of the original reasons for developing this free software
|
||||
was to help force convergence on a common, interoperable format standard for
|
||||
JPEG files.
|
||||
|
||||
JFIF is a minimal or "low end" representation. TIFF/JPEG (TIFF revision 6.0 as
|
||||
modified by TIFF Technical Note #2) can be used for "high end" applications
|
||||
that need to record a lot of additional data about an image.
|
||||
|
||||
|
||||
TO DO
|
||||
=====
|
||||
|
||||
Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
|
||||
@@ -0,0 +1,5 @@
|
||||
4672c7f08864cd0a8c73a4fa4b66ca32b635d38464551c1ecf06564ae8c89b38 testimgari.jpg
|
||||
491679b8057739b3c8e5bacd1e918efb1691d271cbbd69820ff8d480dcb90963 testimgari-huffman.jpg
|
||||
acc6ec555d41d15b368320edaa3b20958ee6fa97cb6e4a18d1213d5ae8bec73b testorig.jpg
|
||||
34790770f76db8e60a7765b52ca4edf5f16bc21bcb8c6045ca2efef39a8a013e testorig12.jpg
|
||||
62d182ed042e243544d3d753c440ada1a6992464717311fe6efd546632f44dc4 testorig12.ppm
|
||||
@@ -0,0 +1,46 @@
|
||||
# Test images
|
||||
|
||||
The JPEG files come from libjpeg-turbo 3.0.0, `testimages/`
|
||||
(https://github.com/libjpeg-turbo/libjpeg-turbo/tree/3.0.0/testimages), under the IJG License
|
||||
(README.ijg in this directory). The other two files are derived from them as described below.
|
||||
`SHA256SUMS` lists every file.
|
||||
|
||||
| File | What it is |
|
||||
|---|---|
|
||||
| `testorig.jpg` | 227×149 YCbCr, 2×2 luma sampling, baseline Huffman (SOF0) |
|
||||
| `testimgari.jpg` | the same image, arithmetic coded (SOF9), one interleaved scan |
|
||||
| `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 |
|
||||
|
||||
`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.
|
||||
|
||||
## How the derived files were made
|
||||
|
||||
`testimgari-huffman.jpg`, with jpegtran from libjpeg-turbo 3.1.0 (Alpine 3.22,
|
||||
`libjpeg-turbo-utils-3.1.0-r0`):
|
||||
|
||||
```sh
|
||||
jpegtran -copy none testimgari.jpg > testimgari-huffman.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`:
|
||||
|
||||
```python
|
||||
import sys, imagecodecs, numpy as np
|
||||
src, dst = sys.argv[1], sys.argv[2]
|
||||
a = imagecodecs.jpeg8_decode(open(src, "rb").read())
|
||||
h, w, c = a.shape
|
||||
assert c == 3 and a.dtype == np.uint16 and a.max() <= 4095
|
||||
with open(dst, "wb") as f:
|
||||
f.write(b"P6\n%d %d\n4095\n" % (w, h))
|
||||
f.write(a.astype(">u2").tobytes())
|
||||
```
|
||||
|
||||
`djpeg -dct int testorig12.jpg` from libjpeg-turbo 3.1.0 writes a byte-identical file.
|
||||
|
||||
"This software is based in part on the work of the Independent JPEG Group."
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
Reference in new issue
Block a user