diff --git a/src/decoder.rs b/src/decoder.rs index dca49820..664a0bdf 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -75,6 +75,8 @@ pub struct Decoder { icc_markers: Vec, + exif_data: Option>, + // Used for progressive JPEGs. coefficients: Vec>, // Bitmask of which coefficients has been completely decoded. @@ -95,6 +97,7 @@ impl Decoder { is_jfif: false, is_mjpeg: false, icc_markers: Vec::new(), + exif_data: None, coefficients: Vec::new(), coefficients_finished: [0; MAX_COMPONENTS], } @@ -124,6 +127,13 @@ impl Decoder { } } + /// Returns raw exif data, starting at the TIFF header, if the image contains any. + /// + /// The returned value will be `None` until a call to `decode` has returned `Ok`. + pub fn exif_data(&self) -> Option<&[u8]> { + self.exif_data.as_ref().map(|v| v.as_slice()) + } + /// Returns the embeded icc profile if the image contains one. pub fn icc_profile(&self) -> Option> { let mut marker_present: [Option<&IccChunk>; 256] = [None; 256]; @@ -374,6 +384,7 @@ impl Decoder { }, AppData::Avi1 => self.is_mjpeg = true, AppData::Icc(icc) => self.icc_markers.push(icc), + AppData::Exif(data) => self.exif_data = Some(data), } } }, diff --git a/src/parser.rs b/src/parser.rs index aac469f2..1c097af2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -71,6 +71,7 @@ pub enum AppData { Jfif, Avi1, Icc(IccChunk), + Exif(Vec), } // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe @@ -562,6 +563,23 @@ pub fn parse_app(reader: &mut R, marker: Marker) -> Result { + if length >= 6 { + let mut buffer = [0u8; 6]; + reader.read_exact(&mut buffer)?; + bytes_read = buffer.len(); + + // https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf + // 4.5.4 Basic Structure of JPEG Compressed Data + if &buffer == b"Exif\x00\x00" { + let mut data = vec![0; length - bytes_read]; + reader.read_exact(&mut data)?; + bytes_read += data.len(); + result = Some(AppData::Exif(data)); + } + } + } APP(2) => { if length > 14 { let mut buffer = [0u8; 14]; diff --git a/tests/lib.rs b/tests/lib.rs index d85ab241..0243296f 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -42,3 +42,18 @@ fn read_icc_profile() { // "acsp" is a mandatory string in ICC profile headers. assert_eq!(&profile[36..40], b"acsp"); } + +#[test] +fn read_exif_data() { + let path = Path::new("tests") + .join("reftest") + .join("images") + .join("ycck.jpg"); + + let mut decoder = jpeg::Decoder::new(File::open(&path).unwrap()); + decoder.decode().unwrap(); + + let exif_data = decoder.exif_data().unwrap(); + // exif data start as a TIFF header + assert_eq!(&exif_data[0..8], b"\x49\x49\x2A\x00\x08\x00\x00\x00"); +}