diff --git a/Cargo.toml b/Cargo.toml index bdba5b7..cb4c7f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,6 @@ exclude = ["tests/images/*", "tests/fuzz_images/*"] [dependencies] byteorder = "1.2" lzw = "0.10" -num-derive = "0.3" -num-traits = "0.2" miniz_oxide = "0.3" [dev-dependencies] diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index 82181b0..2be016b 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -10,27 +10,42 @@ use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError}; use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational}; macro_rules! tags { - {$( - $tag:ident - $val:expr; - )*} => { - - /// TIFF tag - #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] - pub enum Tag { - $($tag,)* - Unknown(u16) + { + // Permit arbitrary meta items, which include documentation. + $( #[$enum_attr:meta] )* + $vis:vis enum $name:ident($ty:ty) $(unknown($unknown_doc:literal))* { + // Each of the `Name = Val,` permitting documentation. + $($(#[$ident_attr:meta])* $tag:ident = $val:expr,)* } - impl Tag { - pub fn from_u16(n: u16) -> Tag { - $(if n == $val { Tag::$tag } else)* { - Tag::Unknown(n) + } => { + $( #[$enum_attr] )* + #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] + pub enum $name { + $($(#[$ident_attr])* $tag,)* + // FIXME: switch to non_exhaustive once stabilized and compiler requirement new enough + #[doc(hidden)] + __NonExhaustive, + $( + #[doc = $unknown_doc] + Unknown($ty), + )* + } + + impl $name { + #[inline(always)] + fn __from_inner_type(n: $ty) -> Result { + match n { + $( $val => Ok($name::$tag), )* + n => Err(n), } } - pub fn to_u16(&self) -> u16 { + + #[inline(always)] + fn __to_inner_type(&self) -> $ty { match *self { - $( Tag::$tag => $val, )* - Tag::Unknown(n) => n, + $( $name::$tag => $val, )* + $( $name::Unknown(n) => { $unknown_doc; n }, )* + $name::__NonExhaustive => unreachable!(), } } } @@ -39,51 +54,65 @@ macro_rules! tags { // Note: These tags appear in the order they are mentioned in the TIFF reference tags! { +/// TIFF tags +pub enum Tag(u16) unknown("A private or extension tag") { // Baseline tags: - Artist 315; + Artist = 315, // grayscale images PhotometricInterpretation 1 or 3 - BitsPerSample 258; - CellLength 265; // TODO add support - CellWidth 264; // TODO add support + BitsPerSample = 258, + CellLength = 265, // TODO add support + CellWidth = 264, // TODO add support // palette-color images (PhotometricInterpretation 3) - ColorMap 320; // TODO add support - Compression 259; // TODO add support for 2 and 32773 - Copyright 33_432; - DateTime 306; - ExtraSamples 338; // TODO add support - FillOrder 266; // TODO add support - FreeByteCounts 289; // TODO add support - FreeOffsets 288; // TODO add support - GrayResponseCurve 291; // TODO add support - GrayResponseUnit 290; // TODO add support - HostComputer 316; - ImageDescription 270; - ImageLength 257; - ImageWidth 256; - Make 271; - MaxSampleValue 281; // TODO add support - MinSampleValue 280; // TODO add support - Model 272; - NewSubfileType 254; // TODO add support - Orientation 274; // TODO add support - PhotometricInterpretation 262; - PlanarConfiguration 284; - ResolutionUnit 296; // TODO add support - RowsPerStrip 278; - SamplesPerPixel 277; - Software 305; - StripByteCounts 279; - StripOffsets 273; - SubfileType 255; // TODO add support - Threshholding 263; // TODO add support - XResolution 282; - YResolution 283; + ColorMap = 320, // TODO add support + Compression = 259, // TODO add support for 2 and 32773 + Copyright = 33_432, + DateTime = 306, + ExtraSamples = 338, // TODO add support + FillOrder = 266, // TODO add support + FreeByteCounts = 289, // TODO add support + FreeOffsets = 288, // TODO add support + GrayResponseCurve = 291, // TODO add support + GrayResponseUnit = 290, // TODO add support + HostComputer = 316, + ImageDescription = 270, + ImageLength = 257, + ImageWidth = 256, + Make = 271, + MaxSampleValue = 281, // TODO add support + MinSampleValue = 280, // TODO add support + Model = 272, + NewSubfileType = 254, // TODO add support + Orientation = 274, // TODO add support + PhotometricInterpretation = 262, + PlanarConfiguration = 284, + ResolutionUnit = 296, // TODO add support + RowsPerStrip = 278, + SamplesPerPixel = 277, + Software = 305, + StripByteCounts = 279, + StripOffsets = 273, + SubfileType = 255, // TODO add support + Threshholding = 263, // TODO add support + XResolution = 282, + YResolution = 283, // Advanced tags - Predictor 317; + Predictor = 317, +} } -#[derive(Clone, Copy, Debug, FromPrimitive)] -pub enum Type { +impl Tag { + pub fn from_u16(val: u16) -> Self { + Self::__from_inner_type(val).unwrap_or_else(Tag::Unknown) + } + + pub fn to_u16(&self) -> u16 { + Self::__to_inner_type(self) + } +} + +tags! { +/// The type of an IFD entry (a 2 byte field). +pub enum Type(u16) { BYTE = 1, ASCII = 2, SHORT = 3, @@ -94,6 +123,18 @@ pub enum Type { SLONG = 9, SRATIONAL = 10, } +} + +impl Type { + pub fn from_u16(val: u16) -> Option { + Self::__from_inner_type(val).ok() + } + + pub fn to_u16(&self) -> u16 { + Self::__to_inner_type(self) + } +} + #[allow(unused_qualifications)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -104,6 +145,8 @@ pub enum Value { Rational(u32, u32), SRational(i32, i32), Ascii(String), + #[doc(hidden)] // Do not match against this. + __NonExhaustive, } impl Value { diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 67e9c88..a3aff91 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,4 +1,3 @@ -use num_traits::{FromPrimitive, Num}; use std::collections::HashMap; use std::io::{self, Read, Seek}; use std::cmp; @@ -9,6 +8,7 @@ use self::ifd::Directory; use self::stream::{ByteOrder, EndianReader, LZWReader, DeflateReader, PackBitsReader, SmartReader}; +#[macro_use] pub mod ifd; mod stream; @@ -80,8 +80,8 @@ impl<'a> DecodingBuffer<'a> { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] -pub enum PhotometricInterpretation { +tags! { +pub enum PhotometricInterpretation(u16) { WhiteIsZero = 0, BlackIsZero = 1, RGB = 2, @@ -91,9 +91,10 @@ pub enum PhotometricInterpretation { YCbCr = 6, CIELab = 8, } +} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] -pub enum CompressionMethod { +tags! { +pub enum CompressionMethod(u16) { None = 1, Huffman = 2, Fax3 = 3, @@ -104,18 +105,61 @@ pub enum CompressionMethod { OldDeflate = 0x80B2, PackBits = 0x8005, } +} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] -pub enum PlanarConfiguration { +tags! { +pub enum PlanarConfiguration(u16) { Chunky = 1, Planar = 2, } +} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] -enum Predictor { +tags! { +enum Predictor(u16) { None = 1, Horizontal = 2, } +} + +impl PhotometricInterpretation { + pub fn from_u16(val: u16) -> Option { + Self::__from_inner_type(val).ok() + } + + pub fn to_u16(&self) -> u16 { + Self::__to_inner_type(self) + } +} + +impl CompressionMethod { + pub fn from_u16(val: u16) -> Option { + Self::__from_inner_type(val).ok() + } + + pub fn to_u16(&self) -> u16 { + Self::__to_inner_type(self) + } +} + +impl PlanarConfiguration { + pub fn from_u16(val: u16) -> Option { + Self::__from_inner_type(val).ok() + } + + pub fn to_u16(&self) -> u16 { + Self::__to_inner_type(self) + } +} + +impl Predictor { + pub fn from_u16(val: u16) -> Option { + Self::__from_inner_type(val).ok() + } + + pub fn to_u16(&self) -> u16 { + Self::__to_inner_type(self) + } +} #[derive(Debug)] struct StripDecodeState { @@ -191,7 +235,7 @@ impl Wrapping for u16 { fn rev_hpredict_nsamp(image: &mut [T], size: (u32, u32), samples: usize) where - T: Num + Copy + Wrapping, + T: Copy + Wrapping, { let width = size.0 as usize; let height = size.1 as usize; @@ -334,8 +378,9 @@ impl Decoder { self.width = self.get_tag_u32(ifd::Tag::ImageWidth)?; self.height = self.get_tag_u32(ifd::Tag::ImageLength)?; self.strip_decoder = None; - self.photometric_interpretation = match FromPrimitive::from_u32( - self.get_tag_u32(ifd::Tag::PhotometricInterpretation)? + // TODO: error on non-SHORT value. + self.photometric_interpretation = match PhotometricInterpretation::from_u16( + self.get_tag_u32(ifd::Tag::PhotometricInterpretation)? as u16 ) { Some(val) => val, None => { @@ -344,8 +389,9 @@ impl Decoder { )) } }; + // TODO: error on non-SHORT value. if let Some(val) = self.find_tag_u32(ifd::Tag::Compression)? { - match FromPrimitive::from_u32(val) { + match CompressionMethod::from_u16(val as u16) { Some(method) => self.compression_method = method, None => { return Err(TiffError::UnsupportedError( @@ -454,7 +500,7 @@ impl Decoder { // Value 4 bytes either a pointer the value itself fn read_entry(&mut self) -> TiffResult> { let tag = ifd::Tag::from_u16(self.read_short()?); - let type_: ifd::Type = match FromPrimitive::from_u16(self.read_short()?) { + let type_ = match ifd::Type::from_u16(self.read_short()?) { Some(t) => t, None => { // Unknown type. Skip this entry according to spec. @@ -720,7 +766,8 @@ impl Decoder { )); } if let Ok(predictor) = self.get_tag_u32(ifd::Tag::Predictor) { - match FromPrimitive::from_u32(predictor) { + // TODO: error on non-SHORT value. + match Predictor::from_u16(predictor as u16) { Some(Predictor::None) => (), Some(Predictor::Horizontal) => { rev_hpredict( @@ -734,6 +781,7 @@ impl Decoder { predictor, ))) } + Some(Predictor::__NonExhaustive) => unreachable!(), } } Ok(()) diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index ab626cf..f5b662c 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -441,7 +441,7 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { } self.ifd - .insert(tag.to_u16(), (::FIELD_TYPE as u16, value.count(), bytes)); + .insert(tag.to_u16(), (::FIELD_TYPE.to_u16(), value.count(), bytes)); } fn write_directory(&mut self) -> TiffResult { @@ -568,7 +568,7 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { encoder.write_tag(Tag::Compression, 1u16); encoder.write_tag(Tag::BitsPerSample, ::BITS_PER_SAMPLE); - encoder.write_tag(Tag::PhotometricInterpretation, ::TIFF_VALUE as u16); + encoder.write_tag(Tag::PhotometricInterpretation, ::TIFF_VALUE.to_u16()); encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32); diff --git a/src/lib.rs b/src/lib.rs index fe194e0..8550be3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,9 +9,6 @@ extern crate byteorder; extern crate lzw; extern crate miniz_oxide; -#[macro_use] -extern crate num_derive; -extern crate num_traits; pub mod decoder; pub mod encoder;