From 0c623bc3a380e6e87150df96a5dda464a3cc141a Mon Sep 17 00:00:00 2001 From: "R.Chavignat" Date: Mon, 12 Mar 2018 23:41:06 +0100 Subject: [PATCH] Refactor a bit Rename the Image* types to Tiff* Extract the "common" types to the top level. --- src/decoder/ifd.rs | 12 ++-- src/decoder/mod.rs | 149 ++++++++---------------------------------- src/decoder/stream.rs | 3 +- src/error.rs | 53 +++++++++++++++ src/lib.rs | 22 +++++++ 5 files changed, 110 insertions(+), 129 deletions(-) create mode 100644 src/error.rs diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index a07b3a2..3e24a71 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 super::{ImageError, ImageResult}; +use ::{TiffError, TiffResult}; use self::Value::{Unsigned, List}; @@ -96,15 +96,15 @@ pub enum Value { } impl Value { - pub fn into_u32(self) -> ImageResult { + pub fn into_u32(self) -> TiffResult { match self { Unsigned(val) => Ok(val), - val => Err(ImageError::FormatError(format!( + val => Err(TiffError::FormatError(format!( "Expected unsigned integer, {:?} found.", val ))) } } - pub fn into_u32_vec(self) -> ImageResult> { + pub fn into_u32_vec(self) -> TiffResult> { match self { List(vec) => { let mut new_vec = Vec::with_capacity(vec.len()); @@ -153,7 +153,7 @@ impl Entry { } pub fn val(&self, decoder: &mut super::TIFFDecoder) - -> ImageResult { + -> TiffResult { let bo = decoder.byte_order(); match (self.type_, self.count) { // TODO check if this could give wrong results @@ -184,7 +184,7 @@ impl Entry { } Ok(List(v)) } - _ => Err(ImageError::UnsupportedError("Unsupported data type.".to_string())) + _ => Err(TiffError::UnsupportedError("Unsupported data type.".to_string())) } } } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index dd804d1..10cfd42 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1,10 +1,10 @@ -use std::error::Error; use std::io::{self, Read, Seek}; -use std::fmt; use std::mem; use num_traits::{FromPrimitive, Num}; use std::collections::HashMap; +use ::{ColorType, TiffError, TiffResult}; + use self::ifd::Directory; use self::stream::{ @@ -18,99 +18,6 @@ use self::stream::{ mod ifd; mod stream; -/// An enumeration over supported color types and their bit depths -#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)] -pub enum ColorType { - /// Pixel is grayscale - Gray(u8), - - /// Pixel contains R, G and B channels - RGB(u8), - - /// Pixel is an index into a color palette - Palette(u8), - - /// Pixel is grayscale with an alpha channel - GrayA(u8), - - /// Pixel is RGB with an alpha channel - RGBA(u8), -} - -/// An enumeration of Image errors -#[derive(Debug)] -pub enum ImageError { - /// The Image is not formatted properly - FormatError(String), - - /// The Image's dimensions are either too small or too large - DimensionError, - - /// The Decoder does not support this image format - UnsupportedError(String), - - /// The Decoder does not support this color type - UnsupportedColor(ColorType), - - /// Not enough data was provided to the Decoder - /// to decode the image - NotEnoughData, - - /// An I/O Error occurred while decoding the image - IoError(io::Error), - - /// The end of the image has been reached - ImageEnd -} - -impl fmt::Display for ImageError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - ImageError::FormatError(ref e) => write!(fmt, "Format error: {}", e), - ImageError::DimensionError => write!(fmt, "The Image's dimensions are either too \ - small or too large"), - ImageError::UnsupportedError(ref f) => write!(fmt, "The Decoder does not support the \ - image format `{}`", f), - ImageError::UnsupportedColor(ref c) => write!(fmt, "The decoder does not support \ - the color type `{:?}`", c), - ImageError::NotEnoughData => write!(fmt, "Not enough data was provided to the \ - Decoder to decode the image"), - ImageError::IoError(ref e) => e.fmt(fmt), - ImageError::ImageEnd => write!(fmt, "The end of the image has been reached") - } - } -} - -impl Error for ImageError { - fn description (&self) -> &str { - match *self { - ImageError::FormatError(..) => "Format error", - ImageError::DimensionError => "Dimension error", - ImageError::UnsupportedError(..) => "Unsupported error", - ImageError::UnsupportedColor(..) => "Unsupported color", - ImageError::NotEnoughData => "Not enough data", - ImageError::IoError(..) => "IO error", - ImageError::ImageEnd => "Image end" - } - } - - fn cause (&self) -> Option<&Error> { - match *self { - ImageError::IoError(ref e) => Some(e), - _ => None - } - } -} - -impl From for ImageError { - fn from(err: io::Error) -> ImageError { - ImageError::IoError(err) - } -} - -/// Result of an image decoding/encoding process -pub type ImageResult = Result; - /// Result of a decoding process #[derive(Debug)] pub enum DecodingResult { @@ -221,12 +128,12 @@ fn rev_hpredict_nsamp(mut image: Vec, image } -fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType) -> ImageResult { +fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType) -> TiffResult { let samples = match color_type { ColorType::Gray(8) | ColorType::Gray(16) => 1, ColorType::RGB(8) | ColorType::RGB(16) => 3, ColorType::RGBA(8) | ColorType::RGBA(16) => 4, - _ => return Err(ImageError::UnsupportedError(format!( + _ => return Err(TiffError::UnsupportedError(format!( "Horizontal predictor for {:?} is unsupported.", color_type ))) }; @@ -242,7 +149,7 @@ fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType) impl TIFFDecoder { /// Create a new decoder that decodes from the stream ```r``` - pub fn new(r: R) -> ImageResult> { + pub fn new(r: R) -> TiffResult> { TIFFDecoder { reader: SmartReader::wrap(r, ByteOrder::LittleEndian), byte_order: ByteOrder::LittleEndian, @@ -257,7 +164,7 @@ impl TIFFDecoder { }.init() } - fn colortype(&mut self) -> ImageResult { + fn colortype(&mut self) -> TiffResult { match self.photometric_interpretation { // TODO: catch also [ 8, 8, 8, _] this does not work due to a bug in rust atm PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 8, 8] => Ok(ColorType::RGBA(8)), @@ -267,13 +174,13 @@ impl TIFFDecoder { PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero if self.bits_per_sample.len() == 1 => Ok(ColorType::Gray(self.bits_per_sample[0])), - _ => Err(ImageError::UnsupportedError(format!( + _ => Err(TiffError::UnsupportedError(format!( "{:?} with {:?} bits per sample is unsupported", self.bits_per_sample, self.photometric_interpretation ))) // TODO: this is bad we should not fail at this point} } } - fn read_header(&mut self) -> ImageResult<()> { + fn read_header(&mut self) -> TiffResult<()> { let mut endianess = Vec::with_capacity(2); try!(self.reader.by_ref().take(2).read_to_end(&mut endianess)); match &*endianess { @@ -283,12 +190,12 @@ impl TIFFDecoder { b"MM" => { self.byte_order = ByteOrder::BigEndian; self.reader.byte_order = ByteOrder::BigEndian; }, - _ => return Err(ImageError::FormatError( + _ => return Err(TiffError::FormatError( "TIFF signature not found.".to_string() )) } if try!(self.read_short()) != 42 { - return Err(ImageError::FormatError("TIFF signature invalid.".to_string())) + return Err(TiffError::FormatError("TIFF signature invalid.".to_string())) } self.next_ifd = match try!(self.read_long()) { 0 => None, @@ -298,7 +205,7 @@ impl TIFFDecoder { } /// Initializes the decoder. - pub fn init(mut self) -> ImageResult> { + pub fn init(mut self) -> TiffResult> { try!(self.read_header()); self.next_image() } @@ -306,7 +213,7 @@ impl TIFFDecoder { /// Reads in the next image. /// If there is no further image in the TIFF file a format error is returned. /// To determine whether there are more images call `TIFFDecoder::more_images` instead. - pub fn next_image(mut self) -> ImageResult> { + pub fn next_image(mut self) -> TiffResult> { self.ifd = Some(try!(self.read_ifd())); self.width = try!(self.get_tag_u32(ifd::Tag::ImageWidth)); self.height = try!(self.get_tag_u32(ifd::Tag::ImageLength)); @@ -314,7 +221,7 @@ impl TIFFDecoder { try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation)) ) { Some(val) => val, - None => return Err(ImageError::UnsupportedError( + None => return Err(TiffError::UnsupportedError( "The image is using an unknown photometric interpretation.".to_string() )) }; @@ -323,7 +230,7 @@ impl TIFFDecoder { Some(method) => { self.compression_method = method }, - None => return Err(ImageError::UnsupportedError( + None => return Err(TiffError::UnsupportedError( "Unknown compression method.".to_string() )) } @@ -343,7 +250,7 @@ impl TIFFDecoder { } } - _ => return Err(ImageError::UnsupportedError( + _ => return Err(TiffError::UnsupportedError( format!("{} samples per pixel is supported.", self.samples) )) } @@ -396,7 +303,7 @@ impl TIFFDecoder { // Type 2 bytes // Count 4 bytes // Value 4 bytes either a pointer the value itself - fn read_entry(&mut self) -> ImageResult> { + fn read_entry(&mut self) -> TiffResult> { let tag = ifd::Tag::from_u16(try!(self.read_short())); let type_: ifd::Type = match FromPrimitive::from_u16(try!(self.read_short())) { Some(t) => t, @@ -416,10 +323,10 @@ impl TIFFDecoder { } /// Reads the next IFD - fn read_ifd(&mut self) -> ImageResult { + fn read_ifd(&mut self) -> TiffResult { let mut dir: Directory = HashMap::new(); match self.next_ifd { - None => return Err(ImageError::FormatError( + None => return Err(TiffError::FormatError( "Image file directory not found.".to_string()) ), Some(offset) => try!(self.goto_offset(offset)) @@ -440,7 +347,7 @@ impl TIFFDecoder { /// Tries to retrieve a tag. /// Return `Ok(None)` if the tag is not present. - fn find_tag(&mut self, tag: ifd::Tag) -> ImageResult> { + fn find_tag(&mut self, tag: ifd::Tag) -> TiffResult> { let ifd: &Directory = unsafe { let ifd = self.ifd.as_ref().unwrap(); // Ok to fail // Get a immutable borrow of self @@ -455,7 +362,7 @@ impl TIFFDecoder { } /// Tries to retrieve a tag and convert it to the desired type. - fn find_tag_u32(&mut self, tag: ifd::Tag) -> ImageResult> { + fn find_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult> { match self.find_tag(tag)? { Some(val) => val.into_u32().map(Some), None => Ok(None) @@ -463,7 +370,7 @@ impl TIFFDecoder { } /// Tries to retrieve a tag and convert it to the desired type. - fn find_tag_u32_vec(&mut self, tag: ifd::Tag) -> ImageResult>> { + fn find_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult>> { match self.find_tag(tag)? { Some(val) => val.into_u32_vec().map(Some), None => Ok(None) @@ -472,28 +379,28 @@ impl TIFFDecoder { /// Tries to retrieve a tag. /// Returns an error if the tag is not present - fn get_tag(&mut self, tag: ifd::Tag) -> ImageResult { + fn get_tag(&mut self, tag: ifd::Tag) -> TiffResult { match try!(self.find_tag(tag)) { Some(val) => Ok(val), - None => Err(ImageError::FormatError(format!( + None => Err(TiffError::FormatError(format!( "Required tag `{:?}` not found.", tag ))) } } /// Tries to retrieve a tag and convert it to the desired type. - fn get_tag_u32(&mut self, tag: ifd::Tag) -> ImageResult { + fn get_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult { self.get_tag(tag)?.into_u32() } /// Tries to retrieve a tag and convert it to the desired type. - fn get_tag_u32_vec(&mut self, tag: ifd::Tag) -> ImageResult> { + fn get_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult> { self.get_tag(tag)?.into_u32_vec() } /// Decompresses the strip into the supplied buffer. /// Returns the number of bytes read. - fn expand_strip<'a>(&mut self, buffer: DecodingBuffer<'a>, offset: u32, length: u32, max_uncompressed_length: usize) -> ImageResult { + fn expand_strip<'a>(&mut self, buffer: DecodingBuffer<'a>, offset: u32, length: u32, max_uncompressed_length: usize) -> TiffResult { let color_type = try!(self.colortype()); try!(self.goto_offset(offset)); let (bytes, mut reader): (usize, Box) = match self.compression_method { @@ -510,7 +417,7 @@ impl TIFFDecoder { let (bytes, reader) = try!(PackBitsReader::new(&mut self.reader, order, length as usize)); (bytes, Box::new(reader)) }, - method => return Err(ImageError::UnsupportedError(format!( + method => return Err(TiffError::UnsupportedError(format!( "Compression method {:?} is unsupported", method ))) }; @@ -544,7 +451,7 @@ impl TIFFDecoder { } bytes } - (type_, _) => return Err(ImageError::UnsupportedError(format!( + (type_, _) => return Err(TiffError::UnsupportedError(format!( "Color type {:?} is unsupported", type_ ))) }) diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index 03f0d28..591e39f 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -1,7 +1,6 @@ //! All IO functionality needed for TIFF decoding -use std::io; -use std::io::{Read, Seek}; +use std::io::{self, Read, Seek}; use byteorder::{ReadBytesExt, BigEndian, LittleEndian}; use lzw; diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..330c985 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,53 @@ +use std::error::Error; +use std::fmt; +use std::io; + +/// An enumeration of Tiff errors +#[derive(Debug)] +pub enum TiffError { + /// The Image is not formatted properly + FormatError(String), + + /// The Decoder does not support this image format + UnsupportedError(String), + + /// An I/O Error occurred while decoding the image + IoError(io::Error), +} + +impl fmt::Display for TiffError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + TiffError::FormatError(ref e) => write!(fmt, "Format error: {}", e), + TiffError::UnsupportedError(ref f) => write!(fmt, "The Decoder does not support the \ + image format `{}`", f), + TiffError::IoError(ref e) => e.fmt(fmt), + } + } +} + +impl Error for TiffError { + fn description (&self) -> &str { + match *self { + TiffError::FormatError(..) => "Format error", + TiffError::UnsupportedError(..) => "Unsupported error", + TiffError::IoError(..) => "IO error", + } + } + + fn cause (&self) -> Option<&Error> { + match *self { + TiffError::IoError(ref e) => Some(e), + _ => None + } + } +} + +impl From for TiffError { + fn from(err: io::Error) -> TiffError { + TiffError::IoError(err) + } +} + +/// Result of an image decoding/encoding process +pub type TiffResult = Result; diff --git a/src/lib.rs b/src/lib.rs index db146f5..f9547dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,3 +14,25 @@ extern crate num_traits; pub use self::decoder::TIFFDecoder; mod decoder; +mod error; + +pub use self::error::{TiffError, TiffResult}; + +/// An enumeration over supported color types and their bit depths +#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)] +pub enum ColorType { + /// Pixel is grayscale + Gray(u8), + + /// Pixel contains R, G and B channels + RGB(u8), + + /// Pixel is an index into a color palette + Palette(u8), + + /// Pixel is grayscale with an alpha channel + GrayA(u8), + + /// Pixel is RGB with an alpha channel + RGBA(u8), +}