Refactor a bit
Rename the Image* types to Tiff* Extract the "common" types to the top level.
This commit is contained in:
1 parent
7c46be100d
commit
0c623bc3a3
5 files changed
+110
-129
No files matched your search
+6
-6
@@ -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<u32> {
|
||||
pub fn into_u32(self) -> TiffResult<u32> {
|
||||
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<Vec<u32>> {
|
||||
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
|
||||
match self {
|
||||
List(vec) => {
|
||||
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>)
|
||||
-> ImageResult<Value> {
|
||||
-> TiffResult<Value> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-121
@@ -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<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
|
||||
#[derive(Debug)]
|
||||
pub enum DecodingResult {
|
||||
@@ -221,12 +128,12 @@ fn rev_hpredict_nsamp<T>(mut image: Vec<T>,
|
||||
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 {
|
||||
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<R: Read + Seek> TIFFDecoder<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 {
|
||||
reader: SmartReader::wrap(r, ByteOrder::LittleEndian),
|
||||
byte_order: ByteOrder::LittleEndian,
|
||||
@@ -257,7 +164,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
|
||||
}.init()
|
||||
}
|
||||
|
||||
fn colortype(&mut self) -> ImageResult<ColorType> {
|
||||
fn colortype(&mut self) -> TiffResult<ColorType> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
}
|
||||
|
||||
/// Initializes the decoder.
|
||||
pub fn init(mut self) -> ImageResult<TIFFDecoder<R>> {
|
||||
pub fn init(mut self) -> TiffResult<TIFFDecoder<R>> {
|
||||
try!(self.read_header());
|
||||
self.next_image()
|
||||
}
|
||||
@@ -306,7 +213,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
|
||||
/// 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<TIFFDecoder<R>> {
|
||||
pub fn next_image(mut self) -> TiffResult<TIFFDecoder<R>> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
}
|
||||
|
||||
}
|
||||
_ => return Err(ImageError::UnsupportedError(
|
||||
_ => return Err(TiffError::UnsupportedError(
|
||||
format!("{} samples per pixel is supported.", self.samples)
|
||||
))
|
||||
}
|
||||
@@ -396,7 +303,7 @@ impl<R: Read + Seek> TIFFDecoder<R> {
|
||||
// Type 2 bytes
|
||||
// Count 4 bytes
|
||||
// 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 type_: ifd::Type = match FromPrimitive::from_u16(try!(self.read_short())) {
|
||||
Some(t) => t,
|
||||
@@ -416,10 +323,10 @@ impl<R: Read + Seek> TIFFDecoder<R> {
|
||||
}
|
||||
|
||||
/// Reads the next IFD
|
||||
fn read_ifd(&mut self) -> ImageResult<Directory> {
|
||||
fn read_ifd(&mut self) -> TiffResult<Directory> {
|
||||
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<R: Read + Seek> TIFFDecoder<R> {
|
||||
|
||||
/// Tries to retrieve a tag.
|
||||
/// 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 = self.ifd.as_ref().unwrap(); // Ok to fail
|
||||
// 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.
|
||||
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)? {
|
||||
Some(val) => val.into_u32().map(Some),
|
||||
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.
|
||||
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)? {
|
||||
Some(val) => val.into_u32_vec().map(Some),
|
||||
None => Ok(None)
|
||||
@@ -472,28 +379,28 @@ impl<R: Read + Seek> TIFFDecoder<R> {
|
||||
|
||||
/// Tries to retrieve a tag.
|
||||
/// 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)) {
|
||||
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<u32> {
|
||||
fn get_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult<u32> {
|
||||
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<Vec<u32>> {
|
||||
fn get_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult<Vec<u32>> {
|
||||
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<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());
|
||||
try!(self.goto_offset(offset));
|
||||
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));
|
||||
(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<R: Read + Seek> TIFFDecoder<R> {
|
||||
}
|
||||
bytes
|
||||
}
|
||||
(type_, _) => return Err(ImageError::UnsupportedError(format!(
|
||||
(type_, _) => return Err(TiffError::UnsupportedError(format!(
|
||||
"Color type {:?} is unsupported", type_
|
||||
)))
|
||||
})
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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),
|
||||
}
|
||||
Reference in new issue
Block a user