From 8cbb071261dc9031106770dace97ee2fe9347856 Mon Sep 17 00:00:00 2001 From: Sergio Gonzalez Martin Date: Mon, 17 Aug 2026 14:30:18 +0000 Subject: [PATCH 3/4] feat(jpeg): parse 12-bit Huffman headers Backport of https://github.com/etemesi254/zune-image/pull/432. --- diff --git a/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/decoder.rs b/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/decoder.rs index 8132b7d464003..8c1af6e108e58 100644 --- a/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/decoder.rs +++ b/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/decoder.rs @@ -652,6 +652,7 @@ where /// See DecodeErrors for an explanation pub fn decode(&mut self) -> Result, DecodeErrors> { self.decode_headers()?; + self.ensure_supported_sample_precision()?; if self.expects_dnl { // Height is unknown until DNL is encountered during entropy @@ -724,7 +725,7 @@ where /// /// # Returns /// - `Some(usize)`: Minimum size for a buffer needed to decode the image - /// - `None`: Indicates the image was not decoded, or image dimensions would overflow a usize + /// - `None`: Indicates headers are unavailable or image dimensions overflow `usize` /// #[must_use] pub fn output_buffer_size(&self) -> Option { @@ -1224,8 +1225,9 @@ where // choose marker let (marker, is_progressive) = match m { - Marker::SOF(0 | 1) => - (SOFMarkers::BaselineDct, false), + Marker::SOF(0) => (SOFMarkers::BaselineDct, false), + Marker::SOF(1) => + (SOFMarkers::ExtendedSequentialHuffman, false), Marker::SOF(2) => (SOFMarkers::ProgressiveDctHuffman, true), _ => unreachable!(), @@ -1508,6 +1510,15 @@ where }; } + fn ensure_supported_sample_precision(&self) -> Result<(), DecodeErrors> { + if self.info.pixel_density == 12 { + return Err(DecodeErrors::FormatStatic( + "12-bit JPEG pixel decoding is not supported" + )); + } + Ok(()) + } + /// Decode into a pre-allocated buffer /// /// It is an error if the buffer size is smaller than @@ -1706,6 +1717,8 @@ where self.decode_headers_internal()?; } + self.ensure_supported_sample_precision()?; + let expected_size = self.output_buffer_size().unwrap(); if out.len() < expected_size { @@ -1912,7 +1925,7 @@ pub struct ImageInfo { pub width: u16, /// Height of image pub height: u16, - /// PixelDensity + /// Sample precision in bits. pub pixel_density: u8, /// Start of frame markers pub sof: SOFMarkers, diff --git a/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/headers.rs b/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/headers.rs index af9ee203f5d7c..03a91b50ba900 100644 --- a/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/headers.rs +++ b/third_party/rust/chromium_crates_io/vendor/zune-jpeg-v0_5/src/headers.rs @@ -332,13 +332,20 @@ pub(crate) fn parse_start_of_frame( // Body length came from a u16 length field minus 2; +2 round-trips it. #[allow(clippy::cast_possible_truncation)] let length = (cursor.body().len() + 2) as u16; - // usually 8, but can be 12 and 16, we currently support only 8 - // so sorry about that 12 bit images + // Pixel decoding remains 8-bit only, but Huffman-coded 12-bit frame + // headers are useful to callers that inspect image metadata. let dt_precision = cursor.read_u8()?; - if dt_precision != 8 { + let supported_header_precision = dt_precision == 8 + || (dt_precision == 12 + && matches!( + sof, + SOFMarkers::ExtendedSequentialHuffman + | SOFMarkers::ProgressiveDctHuffman + )); + if !supported_header_precision { return Err(DecodeErrors::SofError(format!( - "The library can only parse 8-bit images, the image has {dt_precision} bits of precision" + "Unsupported {dt_precision}-bit sample precision for {sof:?}" ))); } -- git version 2.55.0