Allow Exif and other IFDs in the thumbnail image.

The Exif specfication allows Exif/GPS/Interoperability IFDs in the
thumbnail image (1st IFD) as well as in the primary one (0th IFD).

Do not define separate sets of tag constants for primary and thumbnail
images because it doubles the number of constants.  Instead, add a
flag in struct Field to distinguish them.
This commit is contained in:
KAMADA Ken'ichi 2016-12-12 21:27:35 +09:00
parent 05e5852918
commit 5cb98a8f1b
2 changed files with 23 additions and 19 deletions

View File

@ -89,15 +89,13 @@ impl fmt::Display for Tag {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Context {
/// TIFF attributes defined in the TIFF Rev. 6.0 specification.
Tiff, // 0th IFD
Tiff, // 0th/1st IFD
/// Exif attributes.
Exif, // 0th IFD -- Exif IFD
Exif, // 0th/1st IFD -- Exif IFD
/// GPS attributes.
Gps, // 0th IFD -- GPS IFD
Gps, // 0th/1st IFD -- GPS IFD
/// Interoperability attributes.
Interop, // 0th IFD -- Exif IFD -- Interoperability IFD
/// TIFF fields in the 1st IFD, which represents the thumbnail image.
Thumb, // 1st IFD
Interop, // 0th/1st IFD -- Exif IFD -- Interoperability IFD
}
struct TagInfo {
@ -149,7 +147,8 @@ generate_well_known_tag_constants!(
/// structure of Exif data and will not be returned to the user.
(InteropIFDPointer, 0xa005, "Interoperability IFD pointer"),
// TIFF attributes [EXIF23 4.6.4 Table 4 and 4.6.8 Table 17].
// TIFF primary and thumbnail attributes [EXIF23 4.6.4 Table 4,
// 4.6.8 Table 17, and 4.6.8 Table 21].
|Context::Tiff|
(ImageWidth, 0x100, "Image width"),
@ -175,16 +174,14 @@ generate_well_known_tag_constants!(
(Artist, 0x13b, "Person who created the image"),
(WhitePoint, 0x13e, "White point chromaticity"),
(PrimaryChromaticities, 0x13f, "Chromaticities of primaries"),
// (JPEGInterchangeFormat, 0x201, "Offset to JPEG SOI"),
// (JPEGInterchangeFormatLength, 0x202, "Bytes of JPEG data"),
(JPEGInterchangeFormat, 0x201, "Offset to JPEG SOI"),
(JPEGInterchangeFormatLength, 0x202, "Bytes of JPEG data"),
(YCbCrCoefficients, 0x211, "Color space transformation matrix coefficients"),
(YCbCrSubSampling, 0x212, "Subsampling ratio of Y to C"),
(YCbCrPositioning, 0x213, "Y and C positioning"),
(ReferenceBlackWhite, 0x214, "Pair of black and white reference values"),
(Copyright, 0x8298, "Copyright holder"),
// Thumbnail Tiff attributes [EXIF23 4.6.4 Table 4 and 4.6.8 Table 21].
// Exif IFD attributes [EXIF23 4.6.5 Table 7 and 4.6.8 Table 18].
|Context::Exif|

View File

@ -39,7 +39,11 @@ const TIFF_FORTY_TWO: u16 = 0x002a;
/// A TIFF field.
#[derive(Debug)]
pub struct Field<'a> {
/// The tag of this field.
pub tag: Tag,
/// False for the primary image and true for the thumbnail.
pub thumbnail: bool,
/// The value of this field.
pub value: Value<'a>,
}
@ -63,11 +67,11 @@ fn parse_exif_sub<E>(data: &[u8])
return Err(Error::InvalidFormat("Invalid forty two"));
}
let ifd_offset = E::loadu32(data, 4) as usize;
parse_ifd::<E>(data, ifd_offset, Context::Tiff)
parse_ifd::<E>(data, ifd_offset, Context::Tiff, false)
}
// Parse IFD [EXIF23 4.6.2].
fn parse_ifd<E>(data: &[u8], offset: usize, ctx: Context)
fn parse_ifd<E>(data: &[u8], offset: usize, ctx: Context, thumbnail: bool)
-> Result<Vec<Field>, Error> where E: Endian {
// Count (the number of the entries).
if data.len() < offset || data.len() - offset < 2 {
@ -108,16 +112,19 @@ fn parse_ifd<E>(data: &[u8], offset: usize, ctx: Context)
// element of the field.
let tag = Tag(ctx, tag);
if tag == tag::ExifIFDPointer {
let mut v = try!(parse_ifd::<E>(data, ofs, Context::Exif));
let mut v = try!(
parse_ifd::<E>(data, ofs, Context::Exif, thumbnail));
fields.append(&mut v);
} else if tag == tag::GPSInfoIFDPointer {
let mut v = try!(parse_ifd::<E>(data, ofs, Context::Gps));
let mut v = try!(
parse_ifd::<E>(data, ofs, Context::Gps, thumbnail));
fields.append(&mut v);
} else if tag == tag::InteropIFDPointer {
let mut v = try!(parse_ifd::<E>(data, ofs, Context::Interop));
let mut v = try!(
parse_ifd::<E>(data, ofs, Context::Interop, thumbnail));
fields.append(&mut v);
} else {
fields.push(Field { tag: tag, value: val });
fields.push(Field { tag: tag, thumbnail: thumbnail, value: val });
}
}
@ -127,11 +134,11 @@ fn parse_ifd<E>(data: &[u8], offset: usize, ctx: Context)
}
let next_ifd_offset = E::loadu32(data, offset + 2 + count * 12) as usize;
if next_ifd_offset != 0 {
if ctx != Context::Tiff {
if ctx != Context::Tiff || thumbnail {
return Err(Error::InvalidFormat("Unexpected next IFD"));
}
let mut v = try!(
parse_ifd::<E>(data, next_ifd_offset, Context::Thumb));
parse_ifd::<E>(data, next_ifd_offset, Context::Tiff, true));
fields.append(&mut v);
}