diff --git a/Cargo.toml b/Cargo.toml index fd8f2de36b..7e94bc6e9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ rayon = { version = "1.7.0", optional = true } rgb = { version = "0.8.48", default-features = false, optional = true } tiff = { version = "0.10.3", optional = true } zune-core = { version = "0.5.0", default-features = false, optional = true } -zune-jpeg = { version = "0.5.5", optional = true } +zune-jpeg = { version = "0.5.13", optional = true } jpeg-encoder = { version = "0.7.0", optional = true, features = ["simd"] } serde = { version = "1.0.214", optional = true, features = ["derive"] } pic-scale-safe = "0.1.5" diff --git a/src/codecs/jpeg/decoder.rs b/src/codecs/jpeg/decoder.rs index 96c433f627..79a89e7744 100644 --- a/src/codecs/jpeg/decoder.rs +++ b/src/codecs/jpeg/decoder.rs @@ -125,6 +125,24 @@ impl ImageDecoder for JpegDecoder { Ok(decoder.xmp().cloned()) } + fn extended_xmp_metadata(&mut self) -> ImageResult)>> { + let options = zune_core::options::DecoderOptions::default() + .set_strict_mode(false) + .set_max_width(usize::MAX) + .set_max_height(usize::MAX); + let mut decoder = + zune_jpeg::JpegDecoder::new_with_options(ZCursor::new(&self.input), options); + decoder.decode_headers().map_err(ImageError::from_jpeg)?; + + if let Some(info) = decoder.info() { + if let (Some(guid), Some(data)) = (info.extended_xmp_guid, info.extended_xmp) { + let guid_str = String::from_utf8_lossy(&guid).into_owned(); + return Ok(Some((guid_str, data))); + } + } + Ok(None) + } + fn iptc_metadata(&mut self) -> ImageResult>> { let options = zune_core::options::DecoderOptions::default() .set_strict_mode(false) diff --git a/src/io/decoder.rs b/src/io/decoder.rs index d89c0b7862..eeb22af656 100644 --- a/src/io/decoder.rs +++ b/src/io/decoder.rs @@ -39,6 +39,15 @@ pub trait ImageDecoder { Ok(None) } + /// Returns the raw [Extended XMP](https://en.wikipedia.org/wiki/Extensible_Metadata_Platform) metadata, if present. + /// + /// This is typically used in JPEG files when the XMP data exceeds 64KB. + /// Returns `Ok(Some((guid, data)))` where `guid` is the 128-bit GUID (as a 32-character hex string) + /// and `data` is the concatenated extended XMP data. + fn extended_xmp_metadata(&mut self) -> ImageResult)>> { + Ok(None) + } + /// Returns the raw [IPTC](https://en.wikipedia.org/wiki/IPTC_Information_Interchange_Model) chunk, if it is present. /// /// For formats that don't support embedded profiles this function should always return `Ok(None)`. @@ -152,6 +161,9 @@ impl ImageDecoder for Box { fn xmp_metadata(&mut self) -> ImageResult>> { (**self).xmp_metadata() } + fn extended_xmp_metadata(&mut self) -> ImageResult)>> { + (**self).extended_xmp_metadata() + } fn iptc_metadata(&mut self) -> ImageResult>> { (**self).iptc_metadata() }