Add `Tag::TagName`s and deprecate `tag::TagName`s.

This commit is contained in:
KAMADA Ken'ichi 2017-10-12 22:55:56 +09:00
parent 1ad83d8a82
commit 26a64361b3
8 changed files with 77 additions and 65 deletions

View File

@ -29,7 +29,7 @@ extern crate exif;
use std::fs::File;
use std::io::BufReader;
use exif::{DateTime, Reader, Value, tag};
use exif::{DateTime, Reader, Value, Tag};
fn main() {
let file = File::open("tests/exif.jpg").unwrap();
@ -37,11 +37,11 @@ fn main() {
// To obtain a string representation, `Value::display_as` can be used
// for any tag.
let tag_list = [tag::ExifVersion,
tag::PixelXDimension,
tag::XResolution,
tag::ImageDescription,
tag::DateTime];
let tag_list = [Tag::ExifVersion,
Tag::PixelXDimension,
Tag::XResolution,
Tag::ImageDescription,
Tag::DateTime];
for &tag in tag_list.iter() {
if let Some(field) = reader.get_field(tag, false) {
println!("{}: {}", field.tag, field.value.display_as(field.tag));
@ -50,7 +50,7 @@ fn main() {
// To get unsigned integer value(s) from either of BYTE, SHORT,
// or LONG, `Value::get_uint` or `Value::iter_uint` can be used.
if let Some(field) = reader.get_field(tag::PixelXDimension, false) {
if let Some(field) = reader.get_field(Tag::PixelXDimension, false) {
if let Some(width) = field.value.get_uint(0) {
println!("Valid width of the image is {}.", width);
}
@ -58,7 +58,7 @@ fn main() {
// To convert a Rational or SRational to an f64, `Rational::to_f64`
// or `SRational::to_f64` can be used.
if let Some(field) = reader.get_field(tag::XResolution, false) {
if let Some(field) = reader.get_field(Tag::XResolution, false) {
match field.value {
Value::Rational(ref vec) if !vec.is_empty() =>
println!("X resolution is {}.", vec[0].to_f64()),
@ -67,7 +67,7 @@ fn main() {
}
// To parse a DateTime-like field, `DateTime::from_ascii` can be used.
if let Some(field) = reader.get_field(tag::DateTime, false) {
if let Some(field) = reader.get_field(Tag::DateTime, false) {
match field.value {
Value::Ascii(ref vec) if !vec.is_empty() => {
if let Ok(datetime) = DateTime::from_ascii(vec[0]) {

View File

@ -50,6 +50,8 @@
//! * Enum Error has two new variants: TooBig and NotSupported.
//! * Value::Undefined has the 2nd member to keep the offset of the value.
//! * Struct DateTime has two new fields: nanosecond and offset.
//! * The tag constants have been changed to associated constants of
//! struct `Tag`. Use `Tag::TagName` instead of `tag::TagName`.
pub use error::Error;
pub use jpeg::get_exif_attr as get_exif_attr_from_jpeg;

View File

@ -130,7 +130,6 @@ mod tests {
use std::fs::File;
use std::io::BufReader;
use value::Value;
use tag_priv::constants as tag;
use super::*;
static TIFF_ASCII: &'static [u8] =
@ -185,7 +184,7 @@ mod tests {
fn get_field() {
let file = File::open("tests/exif.jpg").unwrap();
let reader = Reader::new(&mut BufReader::new(&file)).unwrap();
assert_pat!(reader.get_field(tag::ExifVersion, false).unwrap().value,
assert_pat!(reader.get_field(Tag::ExifVersion, false).unwrap().value,
Value::Undefined(b"0230", _));
}
}

View File

@ -31,6 +31,10 @@ use value::Value;
use util::{atou16, isupper};
/// A tag of a TIFF field.
///
/// Some well-known tags are provided as associated constants of
/// this type. The constant names follow the Exif specification
/// but not the Rust naming conventions.
//
// This is not an enum to keep safety and API stability, while
// supporting unknown tag numbers. This comment is based on the
@ -130,6 +134,15 @@ macro_rules! generate_well_known_tag_constants {
// <https://github.com/rust-lang/rust/issues/25207>.
pub mod constants {
use super::{Context, Tag};
$($(
$( #[$attr] )*
#[allow(non_upper_case_globals)]
#[deprecated(since = "0.3.0", note = "use `Tag::TagName` instead of `tag::TagName`")]
pub const $name: Tag = Tag($ctx, $num);
)+)+
}
impl Tag {
$($(
$( #[$attr] )*
#[allow(non_upper_case_globals)]
@ -165,7 +178,7 @@ macro_rules! generate_well_known_tag_constants {
fn get_tag_info(tag: Tag) -> Option<&'static tag_info::TagInfo> {
match tag {
$($(
constants::$name => Some(&tag_info::$name),
Tag::$name => Some(&tag_info::$name),
)+)+
_ => None,
}
@ -1269,7 +1282,6 @@ fn d_sub_ascii(w: &mut fmt::Write, bytes: &[u8]) -> fmt::Result {
#[cfg(test)]
mod tests {
use tag;
use value::Rational;
use super::*;
@ -1283,19 +1295,19 @@ mod tests {
}
// Matching against a constant. Test if this compiles.
match Tag(Context::Tiff, 0x132) {
tag::DateTime => {},
Tag::DateTime => {},
_ => panic!("failed to match Tag"),
}
}
#[test]
fn default_value() {
assert_pat!(tag::DateTime.default_value(), None);
match tag::BitsPerSample.default_value() {
assert_pat!(Tag::DateTime.default_value(), None);
match Tag::BitsPerSample.default_value() {
Some(Value::Short(v)) => assert_eq!(v, &[8, 8, 8]),
_ => panic!(),
}
match tag::XResolution.default_value() {
match Tag::XResolution.default_value() {
Some(Value::Rational(v)) => {
assert_eq!(v.len(), 1);
assert_eq!(v[0].num, 72);
@ -1303,15 +1315,15 @@ mod tests {
},
_ => panic!(),
}
match tag::FileSource.default_value() {
match Tag::FileSource.default_value() {
Some(Value::Undefined(v, _)) => assert_eq!(v, &[3]),
_ => panic!(),
}
match tag::GPSAltitudeRef.default_value() {
match Tag::GPSAltitudeRef.default_value() {
Some(Value::Byte(v)) => assert_eq!(v, &[0]),
_ => panic!(),
}
match tag::GPSSpeedRef.default_value() {
match Tag::GPSSpeedRef.default_value() {
Some(Value::Ascii(v)) => assert_eq!(v, &[b"K"]),
_ => panic!(),
}

View File

@ -28,7 +28,6 @@ use std::fmt;
use endian::{Endian, BigEndian, LittleEndian};
use error::Error;
use tag;
use tag_priv::{Context, Tag};
use value::Value;
use value::get_type_info;
@ -120,11 +119,11 @@ fn parse_ifd<'a, E>(fields: &mut Vec<Field<'a>>, data: &'a [u8],
// recursively defined.
let tag = Tag(ctx, tag);
match tag {
tag::ExifIFDPointer => try!(parse_child_ifd::<E>(
Tag::ExifIFDPointer => try!(parse_child_ifd::<E>(
fields, data, &val, Context::Exif, thumbnail)),
tag::GPSInfoIFDPointer => try!(parse_child_ifd::<E>(
Tag::GPSInfoIFDPointer => try!(parse_child_ifd::<E>(
fields, data, &val, Context::Gps, thumbnail)),
tag::InteropIFDPointer => try!(parse_child_ifd::<E>(
Tag::InteropIFDPointer => try!(parse_child_ifd::<E>(
fields, data, &val, Context::Interop, thumbnail)),
_ => fields.push(Field { tag: tag, thumbnail: thumbnail,
value: val }),

View File

@ -81,12 +81,12 @@ impl<'a> Value<'a> {
/// # Examples
///
/// ```
/// use exif::{Value, tag};
/// use exif::{Value, Tag};
/// let val = Value::Undefined(b"0231", 0);
/// assert_eq!(format!("{}", val.display_as(tag::ExifVersion)),
/// assert_eq!(format!("{}", val.display_as(Tag::ExifVersion)),
/// "2.31");
/// let val = Value::Short(vec![2]);
/// assert_eq!(format!("{}", val.display_as(tag::ResolutionUnit)),
/// assert_eq!(format!("{}", val.display_as(Tag::ResolutionUnit)),
/// "pixels per inch");
/// ```
#[inline]

View File

@ -31,7 +31,7 @@ use std::slice;
use endian::{Endian, BigEndian, LittleEndian};
use error::Error;
use tag_priv::{Context, Tag, constants as tag};
use tag_priv::{Context, Tag};
use tiff::{Field, TIFF_BE_SIG, TIFF_LE_SIG};
use value::Value;
@ -97,17 +97,17 @@ impl<'a> Writer<'a> {
pub fn push_field(&mut self, field: &'a Field) {
match *field {
// Ignore the tags for the internal data structure.
Field { tag: tag::ExifIFDPointer, .. } |
Field { tag: tag::GPSInfoIFDPointer, .. } |
Field { tag: tag::InteropIFDPointer, .. } => {},
Field { tag: Tag::ExifIFDPointer, .. } |
Field { tag: Tag::GPSInfoIFDPointer, .. } |
Field { tag: Tag::InteropIFDPointer, .. } => {},
// These tags are synthesized from the actual strip/tile data.
Field { tag: tag::StripOffsets, .. } |
Field { tag: tag::StripByteCounts, .. } |
Field { tag: tag::TileOffsets, .. } |
Field { tag: tag::TileByteCounts, .. } => {},
Field { tag: Tag::StripOffsets, .. } |
Field { tag: Tag::StripByteCounts, .. } |
Field { tag: Tag::TileOffsets, .. } |
Field { tag: Tag::TileByteCounts, .. } => {},
// These tags are synthesized from the actual JPEG thumbnail.
Field { tag: tag::JPEGInterchangeFormat, .. } |
Field { tag: tag::JPEGInterchangeFormatLength, .. } => {},
Field { tag: Tag::JPEGInterchangeFormat, .. } |
Field { tag: Tag::JPEGInterchangeFormatLength, .. } => {},
// Other normal tags.
Field { tag: Tag(Context::Tiff, _), thumbnail: false, .. } =>
self.tiff_fields.push(field),
@ -246,13 +246,13 @@ fn synthesize_fields<W>(w: &mut W, ws: WriterState, thumbnail: bool,
if let Some(strips) = ws.strips {
strip_offsets = Field {
tag: tag::StripOffsets,
tag: Tag::StripOffsets,
thumbnail: thumbnail,
value: Value::Long(vec![0; strips.len()]),
};
ws.tiff_fields.push(&strip_offsets);
strip_byte_counts = Field {
tag: tag::StripByteCounts,
tag: Tag::StripByteCounts,
thumbnail: thumbnail,
value: Value::Long(
strips.iter().map(|s| s.len() as u32).collect()),
@ -261,13 +261,13 @@ fn synthesize_fields<W>(w: &mut W, ws: WriterState, thumbnail: bool,
}
if let Some(tiles) = ws.tiles {
tile_offsets = Field {
tag: tag::TileOffsets,
tag: Tag::TileOffsets,
thumbnail: thumbnail,
value: Value::Long(vec![0; tiles.len()]),
};
ws.tiff_fields.push(&tile_offsets);
tile_byte_counts = Field {
tag: tag::TileByteCounts,
tag: Tag::TileByteCounts,
thumbnail: thumbnail,
value: Value::Long(
tiles.iter().map(|s| s.len() as u32).collect()),
@ -276,13 +276,13 @@ fn synthesize_fields<W>(w: &mut W, ws: WriterState, thumbnail: bool,
}
if let Some(jpeg) = ws.jpeg {
jpeg_offset = Field {
tag: tag::JPEGInterchangeFormat,
tag: Tag::JPEGInterchangeFormat,
thumbnail: thumbnail,
value: Value::Long(vec![0]),
};
ws.tiff_fields.push(&jpeg_offset);
jpeg_length = Field {
tag: tag::JPEGInterchangeFormatLength,
tag: Tag::JPEGInterchangeFormatLength,
thumbnail: thumbnail,
value: Value::Long(vec![jpeg.len() as u32]),
};
@ -301,7 +301,7 @@ fn synthesize_fields<W>(w: &mut W, ws: WriterState, thumbnail: bool,
if exif_fields_len > 0 {
ws.exif_ifd_offset = try!(reserve_ifd(w, exif_fields_len));
exif_in_tiff = Field {
tag: tag::ExifIFDPointer,
tag: Tag::ExifIFDPointer,
thumbnail: thumbnail,
value: Value::Long(vec![ws.exif_ifd_offset]),
};
@ -310,7 +310,7 @@ fn synthesize_fields<W>(w: &mut W, ws: WriterState, thumbnail: bool,
if gps_fields_len > 0 {
ws.gps_ifd_offset = try!(reserve_ifd(w, gps_fields_len));
gps_in_tiff = Field {
tag: tag::GPSInfoIFDPointer,
tag: Tag::GPSInfoIFDPointer,
thumbnail: thumbnail,
value: Value::Long(vec![ws.gps_ifd_offset]),
};
@ -319,7 +319,7 @@ fn synthesize_fields<W>(w: &mut W, ws: WriterState, thumbnail: bool,
if interop_fields_len > 0 {
ws.interop_ifd_offset = try!(reserve_ifd(w, interop_fields_len));
interop_in_exif = Field {
tag: tag::InteropIFDPointer,
tag: Tag::InteropIFDPointer,
thumbnail: thumbnail,
value: Value::Long(vec![ws.interop_ifd_offset]),
};
@ -442,19 +442,19 @@ fn write_ifd_and_fields<W, E>(
try!(E::writeu32(&mut ifd, valofs));
try!(w.write_all(&valbuf));
}
if f.tag == tag::StripOffsets {
if f.tag == Tag::StripOffsets {
strip_offsets_offset = match valbuf.len() {
0...4 => ifd_offset + ifd.len() as u32 - 4,
_ => try!(get_offset(w)) - valbuf.len() as u32,
};
}
if f.tag == tag::TileOffsets {
if f.tag == Tag::TileOffsets {
tile_offsets_offset = match valbuf.len() {
0...4 => ifd_offset + ifd.len() as u32 - 4,
_ => try!(get_offset(w)) - valbuf.len() as u32,
};
}
if f.tag == tag::JPEGInterchangeFormat {
if f.tag == Tag::JPEGInterchangeFormat {
jpeg_offset = ifd_offset + ifd.len() as u32 - 4;
}
}
@ -594,7 +594,7 @@ mod tests {
#[test]
fn primary() {
let image_desc = Field {
tag: tag::ImageDescription,
tag: Tag::ImageDescription,
thumbnail: false,
value: Value::Ascii(vec![b"Sample"]),
};
@ -613,7 +613,7 @@ mod tests {
#[test]
fn primary_exif_only() {
let exif_ver = Field {
tag: tag::ExifVersion,
tag: Tag::ExifVersion,
thumbnail: false,
value: Value::Undefined(b"0231", 0),
};
@ -686,22 +686,22 @@ mod tests {
#[test]
fn primary_and_thumbnail() {
let image_desc = Field {
tag: tag::ImageDescription,
tag: Tag::ImageDescription,
thumbnail: false,
value: Value::Ascii(vec![b"Sample"]),
};
let exif_ver = Field {
tag: tag::ExifVersion,
tag: Tag::ExifVersion,
thumbnail: false,
value: Value::Undefined(b"0231", 0),
};
let gps_ver = Field {
tag: tag::GPSVersionID,
tag: Tag::GPSVersionID,
thumbnail: false,
value: Value::Byte(vec![2, 3, 0, 0]),
};
let interop_index = Field {
tag: tag::InteroperabilityIndex,
tag: Tag::InteroperabilityIndex,
thumbnail: false,
value: Value::Ascii(vec![b"ABC"]),
};
@ -738,7 +738,7 @@ mod tests {
#[test]
fn write_twice() {
let image_desc = Field {
tag: tag::ImageDescription,
tag: Tag::ImageDescription,
thumbnail: false,
value: Value::Ascii(vec![b"Sample"]),
};

View File

@ -37,7 +37,7 @@ use std::path::Path;
#[cfg(not(test))]
use exif::Error;
use exif::{Reader, Value, tag};
use exif::{Reader, Value, Tag};
use exif::experimental::Writer;
#[test]
@ -122,8 +122,8 @@ fn rwr_compare<P>(path: P) where P: AsRef<Path> {
assert_eq!(f1.tag, f2.tag);
assert_eq!(f1.thumbnail, f2.thumbnail);
match f1.tag {
tag::StripOffsets | tag::TileOffsets |
tag::JPEGInterchangeFormat => continue,
Tag::StripOffsets | Tag::TileOffsets |
Tag::JPEGInterchangeFormat => continue,
_ => {},
}
compare_field_value(&f1.value, &f2.value);
@ -177,9 +177,9 @@ fn compare_field_value(value1: &Value, value2: &Value) {
}
fn get_strips(reader: &Reader, thumbnail: bool) -> Option<Vec<&[u8]>> {
let offsets = reader.get_field(tag::StripOffsets, thumbnail)
let offsets = reader.get_field(Tag::StripOffsets, thumbnail)
.and_then(|f| f.value.iter_uint());
let counts = reader.get_field(tag::StripByteCounts, thumbnail)
let counts = reader.get_field(Tag::StripByteCounts, thumbnail)
.and_then(|f| f.value.iter_uint());
let (offsets, counts) = match (offsets, counts) {
(Some(offsets), Some(counts)) => (offsets, counts),
@ -194,9 +194,9 @@ fn get_strips(reader: &Reader, thumbnail: bool) -> Option<Vec<&[u8]>> {
}
fn get_tiles(reader: &Reader, thumbnail: bool) -> Option<Vec<&[u8]>> {
let offsets = reader.get_field(tag::TileOffsets, thumbnail)
let offsets = reader.get_field(Tag::TileOffsets, thumbnail)
.and_then(|f| f.value.iter_uint());
let counts = reader.get_field(tag::TileByteCounts, thumbnail)
let counts = reader.get_field(Tag::TileByteCounts, thumbnail)
.and_then(|f| f.value.iter_uint());
let (offsets, counts) = match (offsets, counts) {
(Some(offsets), Some(counts)) => (offsets, counts),
@ -211,9 +211,9 @@ fn get_tiles(reader: &Reader, thumbnail: bool) -> Option<Vec<&[u8]>> {
}
fn get_jpeg(reader: &Reader, thumbnail: bool) -> Option<&[u8]> {
let offset = reader.get_field(tag::JPEGInterchangeFormat, thumbnail)
let offset = reader.get_field(Tag::JPEGInterchangeFormat, thumbnail)
.and_then(|f| f.value.get_uint(0));
let len = reader.get_field(tag::JPEGInterchangeFormatLength, thumbnail)
let len = reader.get_field(Tag::JPEGInterchangeFormatLength, thumbnail)
.and_then(|f| f.value.get_uint(0));
let (offset, len) = match (offset, len) {
(Some(offset), Some(len)) => (offset as usize, len as usize),