Merge pull request #63 from image-rs/tagged

Replace FromPrimitive with our own tag macro
This commit is contained in:
HeroicKatora authored and GitHub committed 2019-11-12 20:14:25 +01:00
commit 8e1c67ee53
5 files changed
+163 -77

No files matched your search

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