Refactor a bit

Rename the Image* types to Tiff*
Extract the "common" types to the top level.
This commit is contained in:
R.Chavignat committed 2018-03-13 00:07:06 +01:00
1 parent 7c46be100d
commit 0c623bc3a3
5 files changed
+110 -129

No files matched your search

+6 -6
View File
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek};
use std::collections::{HashMap}; use std::collections::{HashMap};
use super::stream::{ByteOrder, SmartReader, EndianReader}; use super::stream::{ByteOrder, SmartReader, EndianReader};
use super::{ImageError, ImageResult}; use ::{TiffError, TiffResult};
use self::Value::{Unsigned, List}; use self::Value::{Unsigned, List};
@@ -96,15 +96,15 @@ pub enum Value {
} }
impl Value { impl Value {
pub fn into_u32(self) -> ImageResult<u32> { pub fn into_u32(self) -> TiffResult<u32> {
match self { match self {
Unsigned(val) => Ok(val), Unsigned(val) => Ok(val),
val => Err(ImageError::FormatError(format!( val => Err(TiffError::FormatError(format!(
"Expected unsigned integer, {:?} found.", val "Expected unsigned integer, {:?} found.", val
))) )))
} }
} }
pub fn into_u32_vec(self) -> ImageResult<Vec<u32>> { pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
match self { match self {
List(vec) => { List(vec) => {
let mut new_vec = Vec::with_capacity(vec.len()); let mut new_vec = Vec::with_capacity(vec.len());
@@ -153,7 +153,7 @@ impl Entry {
} }
pub fn val<R: Read + Seek>(&self, decoder: &mut super::TIFFDecoder<R>) pub fn val<R: Read + Seek>(&self, decoder: &mut super::TIFFDecoder<R>)
-> ImageResult<Value> { -> TiffResult<Value> {
let bo = decoder.byte_order(); let bo = decoder.byte_order();
match (self.type_, self.count) { match (self.type_, self.count) {
// TODO check if this could give wrong results // TODO check if this could give wrong results
@@ -184,7 +184,7 @@ impl Entry {
} }
Ok(List(v)) Ok(List(v))
} }
_ => Err(ImageError::UnsupportedError("Unsupported data type.".to_string())) _ => Err(TiffError::UnsupportedError("Unsupported data type.".to_string()))
} }
} }
} }
+28 -121
View File
@@ -1,10 +1,10 @@
use std::error::Error;
use std::io::{self, Read, Seek}; use std::io::{self, Read, Seek};
use std::fmt;
use std::mem; use std::mem;
use num_traits::{FromPrimitive, Num}; use num_traits::{FromPrimitive, Num};
use std::collections::HashMap; use std::collections::HashMap;
use ::{ColorType, TiffError, TiffResult};
use self::ifd::Directory; use self::ifd::Directory;
use self::stream::{ use self::stream::{
@@ -18,99 +18,6 @@ use self::stream::{
mod ifd; mod ifd;
mod stream; 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<io::Error> for ImageError {
fn from(err: io::Error) -> ImageError {
ImageError::IoError(err)
}
}
/// Result of an image decoding/encoding process
pub type ImageResult<T> = Result<T, ImageError>;
/// Result of a decoding process /// Result of a decoding process
#[derive(Debug)] #[derive(Debug)]
pub enum DecodingResult { pub enum DecodingResult {
@@ -221,12 +128,12 @@ fn rev_hpredict_nsamp<T>(mut image: Vec<T>,
image image
} }
fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType) -> ImageResult<DecodingResult> { fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType) -> TiffResult<DecodingResult> {
let samples = match color_type { let samples = match color_type {
ColorType::Gray(8) | ColorType::Gray(16) => 1, ColorType::Gray(8) | ColorType::Gray(16) => 1,
ColorType::RGB(8) | ColorType::RGB(16) => 3, ColorType::RGB(8) | ColorType::RGB(16) => 3,
ColorType::RGBA(8) | ColorType::RGBA(16) => 4, ColorType::RGBA(8) | ColorType::RGBA(16) => 4,
_ => return Err(ImageError::UnsupportedError(format!( _ => return Err(TiffError::UnsupportedError(format!(
"Horizontal predictor for {:?} is unsupported.", color_type "Horizontal predictor for {:?} is unsupported.", color_type
))) )))
}; };
@@ -242,7 +149,7 @@ fn rev_hpredict(image: DecodingResult, size: (u32, u32), color_type: ColorType)
impl<R: Read + Seek> TIFFDecoder<R> { impl<R: Read + Seek> TIFFDecoder<R> {
/// Create a new decoder that decodes from the stream ```r``` /// Create a new decoder that decodes from the stream ```r```
pub fn new(r: R) -> ImageResult<TIFFDecoder<R>> { pub fn new(r: R) -> TiffResult<TIFFDecoder<R>> {
TIFFDecoder { TIFFDecoder {
reader: SmartReader::wrap(r, ByteOrder::LittleEndian), reader: SmartReader::wrap(r, ByteOrder::LittleEndian),
byte_order: ByteOrder::LittleEndian, byte_order: ByteOrder::LittleEndian,
@@ -257,7 +164,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
}.init() }.init()
} }
fn colortype(&mut self) -> ImageResult<ColorType> { fn colortype(&mut self) -> TiffResult<ColorType> {
match self.photometric_interpretation { match self.photometric_interpretation {
// TODO: catch also [ 8, 8, 8, _] this does not work due to a bug in rust atm // 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)), PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 8, 8] => Ok(ColorType::RGBA(8)),
@@ -267,13 +174,13 @@ impl<R: Read + Seek> TIFFDecoder<R> {
PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero
if self.bits_per_sample.len() == 1 => Ok(ColorType::Gray(self.bits_per_sample[0])), 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 "{:?} with {:?} bits per sample is unsupported", self.bits_per_sample, self.photometric_interpretation
))) // TODO: this is bad we should not fail at this point} ))) // 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); let mut endianess = Vec::with_capacity(2);
try!(self.reader.by_ref().take(2).read_to_end(&mut endianess)); try!(self.reader.by_ref().take(2).read_to_end(&mut endianess));
match &*endianess { match &*endianess {
@@ -283,12 +190,12 @@ impl<R: Read + Seek> TIFFDecoder<R> {
b"MM" => { b"MM" => {
self.byte_order = ByteOrder::BigEndian; self.byte_order = ByteOrder::BigEndian;
self.reader.byte_order = ByteOrder::BigEndian; }, self.reader.byte_order = ByteOrder::BigEndian; },
_ => return Err(ImageError::FormatError( _ => return Err(TiffError::FormatError(
"TIFF signature not found.".to_string() "TIFF signature not found.".to_string()
)) ))
} }
if try!(self.read_short()) != 42 { 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()) { self.next_ifd = match try!(self.read_long()) {
0 => None, 0 => None,
@@ -298,7 +205,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
} }
/// Initializes the decoder. /// Initializes the decoder.
pub fn init(mut self) -> ImageResult<TIFFDecoder<R>> { pub fn init(mut self) -> TiffResult<TIFFDecoder<R>> {
try!(self.read_header()); try!(self.read_header());
self.next_image() self.next_image()
} }
@@ -306,7 +213,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
/// Reads in the next image. /// Reads in the next image.
/// If there is no further image in the TIFF file a format error is returned. /// 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. /// To determine whether there are more images call `TIFFDecoder::more_images` instead.
pub fn next_image(mut self) -> ImageResult<TIFFDecoder<R>> { pub fn next_image(mut self) -> TiffResult<TIFFDecoder<R>> {
self.ifd = Some(try!(self.read_ifd())); self.ifd = Some(try!(self.read_ifd()));
self.width = try!(self.get_tag_u32(ifd::Tag::ImageWidth)); self.width = try!(self.get_tag_u32(ifd::Tag::ImageWidth));
self.height = try!(self.get_tag_u32(ifd::Tag::ImageLength)); self.height = try!(self.get_tag_u32(ifd::Tag::ImageLength));
@@ -314,7 +221,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation)) try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation))
) { ) {
Some(val) => val, Some(val) => val,
None => return Err(ImageError::UnsupportedError( None => return Err(TiffError::UnsupportedError(
"The image is using an unknown photometric interpretation.".to_string() "The image is using an unknown photometric interpretation.".to_string()
)) ))
}; };
@@ -323,7 +230,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
Some(method) => { Some(method) => {
self.compression_method = method self.compression_method = method
}, },
None => return Err(ImageError::UnsupportedError( None => return Err(TiffError::UnsupportedError(
"Unknown compression method.".to_string() "Unknown compression method.".to_string()
)) ))
} }
@@ -343,7 +250,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
} }
} }
_ => return Err(ImageError::UnsupportedError( _ => return Err(TiffError::UnsupportedError(
format!("{} samples per pixel is supported.", self.samples) format!("{} samples per pixel is supported.", self.samples)
)) ))
} }
@@ -396,7 +303,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
// Type 2 bytes // Type 2 bytes
// Count 4 bytes // Count 4 bytes
// Value 4 bytes either a pointer the value itself // Value 4 bytes either a pointer the value itself
fn read_entry(&mut self) -> ImageResult<Option<(ifd::Tag, ifd::Entry)>> { fn read_entry(&mut self) -> TiffResult<Option<(ifd::Tag, ifd::Entry)>> {
let tag = ifd::Tag::from_u16(try!(self.read_short())); let tag = ifd::Tag::from_u16(try!(self.read_short()));
let type_: ifd::Type = match FromPrimitive::from_u16(try!(self.read_short())) { let type_: ifd::Type = match FromPrimitive::from_u16(try!(self.read_short())) {
Some(t) => t, Some(t) => t,
@@ -416,10 +323,10 @@ impl<R: Read + Seek> TIFFDecoder<R> {
} }
/// Reads the next IFD /// Reads the next IFD
fn read_ifd(&mut self) -> ImageResult<Directory> { fn read_ifd(&mut self) -> TiffResult<Directory> {
let mut dir: Directory = HashMap::new(); let mut dir: Directory = HashMap::new();
match self.next_ifd { match self.next_ifd {
None => return Err(ImageError::FormatError( None => return Err(TiffError::FormatError(
"Image file directory not found.".to_string()) "Image file directory not found.".to_string())
), ),
Some(offset) => try!(self.goto_offset(offset)) Some(offset) => try!(self.goto_offset(offset))
@@ -440,7 +347,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
/// Tries to retrieve a tag. /// Tries to retrieve a tag.
/// Return `Ok(None)` if the tag is not present. /// Return `Ok(None)` if the tag is not present.
fn find_tag(&mut self, tag: ifd::Tag) -> ImageResult<Option<ifd::Value>> { fn find_tag(&mut self, tag: ifd::Tag) -> TiffResult<Option<ifd::Value>> {
let ifd: &Directory = unsafe { let ifd: &Directory = unsafe {
let ifd = self.ifd.as_ref().unwrap(); // Ok to fail let ifd = self.ifd.as_ref().unwrap(); // Ok to fail
// Get a immutable borrow of self // Get a immutable borrow of self
@@ -455,7 +362,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
} }
/// Tries to retrieve a tag and convert it to the desired type. /// Tries to retrieve a tag and convert it to the desired type.
fn find_tag_u32(&mut self, tag: ifd::Tag) -> ImageResult<Option<u32>> { fn find_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult<Option<u32>> {
match self.find_tag(tag)? { match self.find_tag(tag)? {
Some(val) => val.into_u32().map(Some), Some(val) => val.into_u32().map(Some),
None => Ok(None) None => Ok(None)
@@ -463,7 +370,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
} }
/// Tries to retrieve a tag and convert it to the desired type. /// Tries to retrieve a tag and convert it to the desired type.
fn find_tag_u32_vec(&mut self, tag: ifd::Tag) -> ImageResult<Option<Vec<u32>>> { fn find_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult<Option<Vec<u32>>> {
match self.find_tag(tag)? { match self.find_tag(tag)? {
Some(val) => val.into_u32_vec().map(Some), Some(val) => val.into_u32_vec().map(Some),
None => Ok(None) None => Ok(None)
@@ -472,28 +379,28 @@ impl<R: Read + Seek> TIFFDecoder<R> {
/// Tries to retrieve a tag. /// Tries to retrieve a tag.
/// Returns an error if the tag is not present /// Returns an error if the tag is not present
fn get_tag(&mut self, tag: ifd::Tag) -> ImageResult<ifd::Value> { fn get_tag(&mut self, tag: ifd::Tag) -> TiffResult<ifd::Value> {
match try!(self.find_tag(tag)) { match try!(self.find_tag(tag)) {
Some(val) => Ok(val), Some(val) => Ok(val),
None => Err(ImageError::FormatError(format!( None => Err(TiffError::FormatError(format!(
"Required tag `{:?}` not found.", tag "Required tag `{:?}` not found.", tag
))) )))
} }
} }
/// Tries to retrieve a tag and convert it to the desired type. /// Tries to retrieve a tag and convert it to the desired type.
fn get_tag_u32(&mut self, tag: ifd::Tag) -> ImageResult<u32> { fn get_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult<u32> {
self.get_tag(tag)?.into_u32() self.get_tag(tag)?.into_u32()
} }
/// Tries to retrieve a tag and convert it to the desired type. /// Tries to retrieve a tag and convert it to the desired type.
fn get_tag_u32_vec(&mut self, tag: ifd::Tag) -> ImageResult<Vec<u32>> { fn get_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult<Vec<u32>> {
self.get_tag(tag)?.into_u32_vec() self.get_tag(tag)?.into_u32_vec()
} }
/// Decompresses the strip into the supplied buffer. /// Decompresses the strip into the supplied buffer.
/// Returns the number of bytes read. /// Returns the number of bytes read.
fn expand_strip<'a>(&mut self, buffer: DecodingBuffer<'a>, offset: u32, length: u32, max_uncompressed_length: usize) -> ImageResult<usize> { fn expand_strip<'a>(&mut self, buffer: DecodingBuffer<'a>, offset: u32, length: u32, max_uncompressed_length: usize) -> TiffResult<usize> {
let color_type = try!(self.colortype()); let color_type = try!(self.colortype());
try!(self.goto_offset(offset)); try!(self.goto_offset(offset));
let (bytes, mut reader): (usize, Box<EndianReader>) = match self.compression_method { let (bytes, mut reader): (usize, Box<EndianReader>) = match self.compression_method {
@@ -510,7 +417,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
let (bytes, reader) = try!(PackBitsReader::new(&mut self.reader, order, length as usize)); let (bytes, reader) = try!(PackBitsReader::new(&mut self.reader, order, length as usize));
(bytes, Box::new(reader)) (bytes, Box::new(reader))
}, },
method => return Err(ImageError::UnsupportedError(format!( method => return Err(TiffError::UnsupportedError(format!(
"Compression method {:?} is unsupported", method "Compression method {:?} is unsupported", method
))) )))
}; };
@@ -544,7 +451,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
} }
bytes bytes
} }
(type_, _) => return Err(ImageError::UnsupportedError(format!( (type_, _) => return Err(TiffError::UnsupportedError(format!(
"Color type {:?} is unsupported", type_ "Color type {:?} is unsupported", type_
))) )))
}) })
+1 -2
View File
@@ -1,7 +1,6 @@
//! All IO functionality needed for TIFF decoding //! All IO functionality needed for TIFF decoding
use std::io; use std::io::{self, Read, Seek};
use std::io::{Read, Seek};
use byteorder::{ReadBytesExt, BigEndian, LittleEndian}; use byteorder::{ReadBytesExt, BigEndian, LittleEndian};
use lzw; use lzw;
+53
View File
@@ -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<io::Error> for TiffError {
fn from(err: io::Error) -> TiffError {
TiffError::IoError(err)
}
}
/// Result of an image decoding/encoding process
pub type TiffResult<T> = Result<T, TiffError>;
+22
View File
@@ -14,3 +14,25 @@ extern crate num_traits;
pub use self::decoder::TIFFDecoder; pub use self::decoder::TIFFDecoder;
mod decoder; 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),
}