From aa16ef97ab23c52b34c43e9d98d7f3cb56ad35f1 Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Fri, 17 Jan 2025 23:10:45 +0000 Subject: [PATCH] Add support for parsing `eXIf` chunk. The `eXIf` chunk was already supported in `encoder.rs`, but this commit also adds support to `decoder/stream.rs`. This commit is needed for parity with the existing PNG decoder in Blink / Chromium - see https://crbug.com/390707316 --- src/decoder/stream.rs | 24 +++++++++++++++++++++++- tests/bugfixes/F-exif-chunk-early.png | Bin 0 -> 15343 bytes tests/results.txt | 1 + tests/results_alpha.txt | 1 + tests/results_identity.txt | 1 + 5 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/bugfixes/F-exif-chunk-early.png diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 1b00968b..904d3beb 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -989,6 +989,7 @@ impl StreamingDecoder { chunk::cICP => Ok(self.parse_cicp()), chunk::mDCV => Ok(self.parse_mdcv()), chunk::cLLI => Ok(self.parse_clli()), + chunk::eXIf => Ok(self.parse_exif()), chunk::bKGD => Ok(self.parse_bkgd()), chunk::iCCP if !self.decode_options.ignore_iccp_chunk => self.parse_iccp(), chunk::tEXt if !self.decode_options.ignore_text_chunk => self.parse_text(), @@ -1487,6 +1488,16 @@ impl StreamingDecoder { Decoded::Nothing } + fn parse_exif(&mut self) -> Decoded { + // We ignore a second, duplicated eXIf chunk (if any). + let info = self.info.as_mut().unwrap(); + if info.exif_metadata.is_none() { + info.exif_metadata = Some(self.current_chunk.raw_bytes.clone().into()); + } + + Decoded::Nothing + } + fn parse_iccp(&mut self) -> Result { if self.have_idat { Err(DecodingError::Format( @@ -2125,7 +2136,7 @@ mod tests { assert!(decoder.read_info().is_ok()); } - /// Test handling of `mDCV` and `cLLI` chunks.` + /// Test handling of `mDCV` and `cLLI` chunks. #[test] fn test_mdcv_and_clli_chunks() { let decoder = crate::Decoder::new(File::open("tests/bugfixes/cicp_pq.png").unwrap()); @@ -2155,6 +2166,17 @@ mod tests { assert_relative_eq!(clli.max_frame_average_light_level as f32 / 10_000.0, 2627.0); } + /// Test handling of `eXIf` chunk. + #[test] + fn test_exif_chunk() { + let decoder = + crate::Decoder::new(File::open("tests/bugfixes/F-exif-chunk-early.png").unwrap()); + let reader = decoder.read_info().unwrap(); + let info = reader.info(); + let exif = info.exif_metadata.as_ref().unwrap().as_ref(); + assert_eq!(exif.len(), 90); + } + /// Tests what happens then [`Reader.finish`] is called twice. #[test] fn test_finishing_twice() { diff --git a/tests/bugfixes/F-exif-chunk-early.png b/tests/bugfixes/F-exif-chunk-early.png new file mode 100644 index 0000000000000000000000000000000000000000..24bd924e9e71eaaee22961c26e87de314d90f719 GIT binary patch literal 15343 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