diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index 81eeafd..17884a2 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -4,7 +4,7 @@ use std::io::{self, Read, Seek}; use std::collections::{HashMap}; use super::stream::{ByteOrder, SmartReader, EndianReader}; -use ::{TiffError, TiffFormatError, TiffResult}; +use ::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult}; use self::Value::{Unsigned, List, Rational}; @@ -86,7 +86,7 @@ pub enum Type { #[allow(unused_qualifications)] -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Value { //Signed(i32), Unsigned(u32), @@ -194,7 +194,7 @@ impl Entry { } Ok(List(v)) }, - _ => Err(TiffError::UnsupportedError("Unsupported data type.".to_string())) + _ => Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedDataType)) } } } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index c06824a..49b5a94 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -3,7 +3,7 @@ use std::mem; use num_traits::{FromPrimitive, Num}; use std::collections::HashMap; -use ::{ColorType, TiffError, TiffFormatError, TiffResult}; +use ::{ColorType, TiffError, TiffFormatError, TiffUnsupportedError, TiffResult}; use self::ifd::Directory; @@ -35,8 +35,8 @@ enum DecodingBuffer<'a> { U16(&'a mut [u16]) } -#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)] -enum PhotometricInterpretation { +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] +pub enum PhotometricInterpretation { WhiteIsZero = 0, BlackIsZero = 1, RGB = 2, @@ -47,8 +47,8 @@ enum PhotometricInterpretation { CIELab = 8, } -#[derive(Clone, Copy, Debug, FromPrimitive)] -enum CompressionMethod { +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] +pub enum CompressionMethod { None = 1, Huffman = 2, Fax3 = 3, @@ -58,13 +58,13 @@ enum CompressionMethod { PackBits = 0x8005 } -#[derive(Clone, Copy, Debug, FromPrimitive)] -enum PlanarConfiguration { +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] +pub enum PlanarConfiguration { Chunky = 1, Planar = 2 } -#[derive(Clone, Copy, Debug, FromPrimitive)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] enum Predictor { None = 1, Horizontal = 2 @@ -125,9 +125,7 @@ fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType) ColorType::Gray(8) | ColorType::Gray(16) => 1, ColorType::RGB(8) | ColorType::RGB(16) => 3, ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::CMYK(8) => 4, - _ => return Err(TiffError::UnsupportedError(format!( - "Horizontal predictor for {:?} is unsupported.", color_type - ))) + _ => return Err(TiffError::UnsupportedError(TiffUnsupportedError::HorizontalPredictor(color_type))) }; Ok(match image { DecodingResult::U8(buf) => { @@ -171,9 +169,8 @@ impl Decoder { PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero if self.bits_per_sample.len() == 1 => Ok(ColorType::Gray(self.bits_per_sample[0])), - _ => Err(TiffError::UnsupportedError(format!( - "{:?} with {:?} bits per sample is unsupported", self.photometric_interpretation, self.bits_per_sample - ))) // TODO: this is bad we should not fail at this point} + // TODO: this is bad we should not fail at this point + _ => Err(TiffError::UnsupportedError(TiffUnsupportedError::InterpretationWithBits(self.photometric_interpretation, self.bits_per_sample.clone()))) } } @@ -216,18 +213,14 @@ impl Decoder { try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation)) ) { Some(val) => val, - None => return Err(TiffError::UnsupportedError( - "The image is using an unknown photometric interpretation.".to_string() - )) + None => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnknownInterpretation)) }; if let Some(val) = try!(self.find_tag_u32(ifd::Tag::Compression)) { match FromPrimitive::from_u32(val) { Some(method) => { self.compression_method = method }, - None => return Err(TiffError::UnsupportedError( - "Unknown compression method.".to_string() - )) + None => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnknownCompressionMethod)) } } if let Some(val) = try!(self.find_tag_u32(ifd::Tag::SamplesPerPixel)) { @@ -245,9 +238,7 @@ impl Decoder { } } - _ => return Err(TiffError::UnsupportedError( - format!("{} samples per pixel is supported.", self.samples) - )) + _ => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedSampleDepth(self.samples))) } Ok(self) } @@ -408,9 +399,7 @@ impl Decoder { let (bytes, reader) = try!(PackBitsReader::new(&mut self.reader, order, length as usize)); (bytes, Box::new(reader)) }, - method => return Err(TiffError::UnsupportedError(format!( - "Compression method {:?} is unsupported", method - ))) + method => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedCompressionMethod(method))) }; Ok(match (color_type, buffer) { (ColorType:: RGB(8), DecodingBuffer::U8(ref mut buffer)) | @@ -443,9 +432,7 @@ impl Decoder { } bytes } - (type_, _) => return Err(TiffError::UnsupportedError(format!( - "Color type {:?} is unsupported", type_ - ))) + (type_, _) => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedColorType(type_))), }) } @@ -463,18 +450,12 @@ impl Decoder { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { n if n <= 8 => DecodingResult::U8(Vec::with_capacity(buffer_size)), n if n <= 16 => DecodingResult::U16(Vec::with_capacity(buffer_size)), - n => return Err( - TiffError::UnsupportedError( - format!("{} bits per channel not supported", n) - ) - ) + n => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedBitsPerChannel(n))), }; if let Ok(config) = self.get_tag_u32(ifd::Tag::PlanarConfiguration) { match FromPrimitive::from_u32(config) { Some(PlanarConfiguration::Chunky) => {}, - config => return Err(TiffError::UnsupportedError( - format!("Unsupported planar configuration “{:?}”.", config) - )) + config => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedPlanarConfig(config))) } } // Safe since the uninitialized values are never read. diff --git a/src/error.rs b/src/error.rs index 2774550..2934d43 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,8 @@ use std::fmt; use std::io; use decoder::ifd::{Tag, Value}; +use decoder::{PhotometricInterpretation, CompressionMethod, PlanarConfiguration}; +use ColorType; /// Tiff error kinds. #[derive(Debug)] @@ -11,13 +13,13 @@ pub enum TiffError { FormatError(TiffFormatError), /// The Decoder does not support this image format - UnsupportedError(String), + UnsupportedError(TiffUnsupportedError), /// An I/O Error occurred while decoding the image IoError(io::Error), } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum TiffFormatError { TiffSignatureNotFound, TiffSignatureInvalid, @@ -41,6 +43,40 @@ impl fmt::Display for TiffFormatError { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum TiffUnsupportedError { + HorizontalPredictor(ColorType), + InterpretationWithBits(PhotometricInterpretation, Vec), + UnknownInterpretation, + UnknownCompressionMethod, + UnsupportedCompressionMethod(CompressionMethod), + UnsupportedSampleDepth(u8), + UnsupportedColorType(ColorType), + UnsupportedBitsPerChannel(u8), + UnsupportedPlanarConfig(Option), + UnsupportedDataType, +} + +impl fmt::Display for TiffUnsupportedError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use self::TiffUnsupportedError::*; + match *self { + HorizontalPredictor(color_type) => write!(fmt, "Horizontal predictor for {:?} is unsupported.", color_type), + InterpretationWithBits(ref photometric_interpretation, ref bits_per_sample) => { + write!(fmt, "{:?} with {:?} bits per sample is unsupported", photometric_interpretation, bits_per_sample) + }, + UnknownInterpretation => write!(fmt, "The image is using an unknown photometric interpretation."), + UnknownCompressionMethod => write!(fmt, "Unknown compression method."), + UnsupportedCompressionMethod(method) => write!(fmt, "Compression method {:?} is unsupported", method), + UnsupportedSampleDepth(samples) => write!(fmt, "{} samples per pixel is supported.", samples), + UnsupportedColorType(color_type) => write!(fmt, "Color type {:?} is unsupported", color_type), + UnsupportedBitsPerChannel(bits) => write!(fmt, "{} bits per channel not supported", bits), + UnsupportedPlanarConfig(config) => write!(fmt, "Unsupported planar configuration “{:?}”.", config), + UnsupportedDataType => write!(fmt, "Unsupported data type."), + } + } +} + impl fmt::Display for TiffError { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { diff --git a/src/lib.rs b/src/lib.rs index 6e0e2ba..2722a90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ extern crate num_traits; pub mod decoder; mod error; -pub use self::error::{TiffError, TiffFormatError, TiffResult}; +pub use self::error::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult}; /// An enumeration over supported color types and their bit depths #[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]