Skip to content

Commit dc27e0f

Browse files
committed
Implement retrieving XMP metadata for tiff
1 parent c0d1781 commit dc27e0f

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

src/codecs/tiff.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use crate::error::{
2020
use crate::metadata::Orientation;
2121
use crate::{utils, ImageDecoder, ImageEncoder, ImageFormat};
2222

23+
const TAG_XML_PACKET: Tag = Tag::Unknown(700);
24+
2325
/// Decoder for TIFF images.
2426
pub struct TiffDecoder<R>
2527
where
@@ -264,6 +266,21 @@ impl<R: BufRead + Seek> ImageDecoder for TiffDecoder<R> {
264266
}
265267
}
266268

269+
fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
270+
let Some(decoder) = &mut self.inner else {
271+
return Ok(None);
272+
};
273+
274+
let value = match decoder.get_tag(TAG_XML_PACKET) {
275+
Ok(value) => value,
276+
Err(tiff::TiffError::FormatError(tiff::TiffFormatError::RequiredTagNotFound(_))) => {
277+
return Ok(None);
278+
}
279+
Err(err) => return Err(ImageError::from_tiff_decode(err)),
280+
};
281+
value.into_u8_vec().map(|val| Some(val)).map_err(ImageError::from_tiff_decode)
282+
}
283+
267284
fn orientation(&mut self) -> ImageResult<Orientation> {
268285
if let Some(decoder) = &mut self.inner {
269286
Ok(decoder
4.33 KB
Binary file not shown.

tests/metadata.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use image::ImageDecoder;
88
use image::codecs::png::PngDecoder;
99
#[cfg(feature = "webp")]
1010
use image::codecs::webp::WebPDecoder;
11+
#[cfg(feature = "tiff")]
12+
use image::codecs::tiff::TiffDecoder;
1113

1214
extern crate glob;
1315
extern crate image;
@@ -18,6 +20,9 @@ const EXPECTED_PNG_METADATA: &str = "<?xpacket begin='\u{feff}' id='W5M0MpCehiHz
1820
const XMP_WEBP_PATH: &str = "tests/images/webp/lossless_images/simple_xmp.webp";
1921
const EXPECTED_WEBP_METADATA: &str = "<?xpacket begin='\u{feff}' id='W5M0MpCehiHzreSzNTczkc9d'?>\n<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 13.25'>\n<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n\n <rdf:Description rdf:about=''\n xmlns:dc='http://purl.org/dc/elements/1.1/'>\n <dc:subject>\n <rdf:Bag>\n <rdf:li>sunset, mountains, nature</rdf:li>\n </rdf:Bag>\n </dc:subject>\n </rdf:Description>\n</rdf:RDF>\n</x:xmpmeta>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n<?xpacket end='w'?>";
2022

23+
const XMP_TIFF_PATH: &str = "tests/images/tiff/testsuite/l1_xmp.tiff";
24+
const EXPECTED_METADATA_TIFF: &str = "<?xpacket begin='\u{feff}' id='W5M0MpCehiHzreSzNTczkc9d'?>\n<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 13.25'>\n<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n\n <rdf:Description rdf:about=''\n xmlns:dc='http://purl.org/dc/elements/1.1/'>\n <dc:subject>\n <rdf:Bag>\n <rdf:li>sunset, mountains, nature</rdf:li>\n </rdf:Bag>\n </dc:subject>\n </rdf:Description>\n</rdf:RDF>\n</x:xmpmeta>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n<?xpacket end='w'?>";
25+
2126
#[test]
2227
#[cfg(feature = "png")]
2328
fn test_read_xmp_png() -> Result<(), image::ImageError> {
@@ -46,3 +51,16 @@ fn test_read_xmp_webp() -> Result<(), image::ImageError> {
4651

4752
Ok(())
4853
}
54+
55+
#[test]
56+
fn test_read_xmp_tiff() -> Result<(), image::ImageError> {
57+
let img_path = PathBuf::from_str(XMP_TIFF_PATH).unwrap();
58+
59+
let data = fs::read(img_path)?;
60+
let mut tiff_decoder = TiffDecoder::new(std::io::Cursor::new(data))?;
61+
let metadata = tiff_decoder.xmp_metadata()?;
62+
assert!(metadata.is_some());
63+
assert_eq!(EXPECTED_METADATA_TIFF.as_bytes(), metadata.unwrap());
64+
65+
Ok(())
66+
}

0 commit comments

Comments
 (0)