Format code using 'cargo fmt'

This commit is contained in:
Atul Bhosale committed 2019-04-18 00:04:43 +05:30
1 parent fc743cfd27
commit 522fbd1a69
10 files changed
+488 -292

No files matched your search

+40 -34
View File
@@ -1,12 +1,12 @@
//! Function for reading TIFF tags //! Function for reading TIFF tags
use std::collections::HashMap;
use std::io::{self, Read, Seek}; use std::io::{self, Read, Seek};
use std::collections::{HashMap};
use super::stream::{ByteOrder, SmartReader, EndianReader}; use super::stream::{ByteOrder, EndianReader, SmartReader};
use ::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult}; use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
use self::Value::{Unsigned, List, Rational, Ascii}; use self::Value::{Ascii, List, Rational, Unsigned};
macro_rules! tags { macro_rules! tags {
{$( {$(
@@ -37,7 +37,7 @@ 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! {
// Baseline tags: // Baseline tags:
Artist 315; Artist 315;
// grayscale images PhotometricInterpretation 1 or 3 // grayscale images PhotometricInterpretation 1 or 3
@@ -90,7 +90,6 @@ pub enum Type {
RATIONAL = 5, RATIONAL = 5,
} }
#[allow(unused_qualifications)] #[allow(unused_qualifications)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Value { pub enum Value {
@@ -98,14 +97,16 @@ pub enum Value {
Unsigned(u32), Unsigned(u32),
List(Vec<Value>), List(Vec<Value>),
Rational(u32, u32), Rational(u32, u32),
Ascii(String) Ascii(String),
} }
impl Value { impl Value {
pub fn into_u32(self) -> TiffResult<u32> { pub fn into_u32(self) -> TiffResult<u32> {
match self { match self {
Unsigned(val) => Ok(val), Unsigned(val) => Ok(val),
val => Err(TiffError::FormatError(TiffFormatError::UnsignedIntegerExpected(val))), val => Err(TiffError::FormatError(
TiffFormatError::UnsignedIntegerExpected(val),
)),
} }
} }
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> { pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
@@ -116,10 +117,10 @@ impl Value {
new_vec.push(v.into_u32()?) new_vec.push(v.into_u32()?)
} }
Ok(new_vec) Ok(new_vec)
}, }
Unsigned(val) => Ok(vec![val]), Unsigned(val) => Ok(vec![val]),
Rational(numerator, denominator) => Ok(vec![numerator, denominator]), Rational(numerator, denominator) => Ok(vec![numerator, denominator]),
Ascii(val) => Ok(val.chars().map(|x| x as u32).collect()) Ascii(val) => Ok(val.chars().map(|x| x as u32).collect()),
} }
} }
} }
@@ -133,29 +134,32 @@ pub struct Entry {
impl ::std::fmt::Debug for Entry { impl ::std::fmt::Debug for Entry {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
fmt.write_str(&format!("Entry {{ type_: {:?}, count: {:?}, offset: {:?} }}", fmt.write_str(&format!(
self.type_, "Entry {{ type_: {:?}, count: {:?}, offset: {:?} }}",
self.count, self.type_, self.count, &self.offset
&self.offset
)) ))
} }
} }
impl Entry { impl Entry {
pub fn new(type_: Type, count: u32, offset: [u8; 4]) -> Entry { pub fn new(type_: Type, count: u32, offset: [u8; 4]) -> Entry {
Entry { type_, count, offset } Entry {
type_,
count,
offset,
}
} }
/// Returns a mem_reader for the offset/value field /// Returns a mem_reader for the offset/value field
fn r(&self, byte_order: ByteOrder) -> SmartReader<io::Cursor<Vec<u8>>> { fn r(&self, byte_order: ByteOrder) -> SmartReader<io::Cursor<Vec<u8>>> {
SmartReader::wrap( SmartReader::wrap(io::Cursor::new(self.offset.to_vec()), byte_order)
io::Cursor::new(self.offset.to_vec()),
byte_order
)
} }
pub fn val<R: Read + Seek>(&self, limits: &super::Limits, decoder: &mut super::Decoder<R>) pub fn val<R: Read + Seek>(
-> TiffResult<Value> { &self,
limits: &super::Limits,
decoder: &mut super::Decoder<R>,
) -> 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
@@ -166,28 +170,28 @@ impl Entry {
let mut r = self.r(bo); let mut r = self.r(bo);
Ok(List(vec![ Ok(List(vec![
Unsigned(u32::from(r.read_u16()?)), Unsigned(u32::from(r.read_u16()?)),
Unsigned(u32::from(r.read_u16()?)) Unsigned(u32::from(r.read_u16()?)),
])) ]))
}, }
(Type::SHORT, n) => { (Type::SHORT, n) => {
if n as usize > limits.decoding_buffer_size / std::mem::size_of::<Value>() { if n as usize > limits.decoding_buffer_size / std::mem::size_of::<Value>() {
return Err(TiffError::LimitsExceeded) return Err(TiffError::LimitsExceeded);
} }
let mut v = Vec::with_capacity(n as usize); let mut v = Vec::with_capacity(n as usize);
try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
for _ in 0 .. n { for _ in 0..n {
v.push(Unsigned(u32::from(decoder.read_short()?))) v.push(Unsigned(u32::from(decoder.read_short()?)))
} }
Ok(List(v)) Ok(List(v))
}, }
(Type::LONG, 1) => Ok(Unsigned(try!(self.r(bo).read_u32()))), (Type::LONG, 1) => Ok(Unsigned(try!(self.r(bo).read_u32()))),
(Type::LONG, n) => { (Type::LONG, n) => {
if n as usize > limits.decoding_buffer_size / std::mem::size_of::<Value>() { if n as usize > limits.decoding_buffer_size / std::mem::size_of::<Value>() {
return Err(TiffError::LimitsExceeded) return Err(TiffError::LimitsExceeded);
} }
let mut v = Vec::with_capacity(n as usize); let mut v = Vec::with_capacity(n as usize);
try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
for _ in 0 .. n { for _ in 0..n {
v.push(Unsigned(try!(decoder.read_long()))) v.push(Unsigned(try!(decoder.read_long())))
} }
Ok(List(v)) Ok(List(v))
@@ -197,29 +201,31 @@ impl Entry {
let numerator = try!(decoder.read_long()); let numerator = try!(decoder.read_long());
let denominator = try!(decoder.read_long()); let denominator = try!(decoder.read_long());
Ok(Rational(numerator, denominator)) Ok(Rational(numerator, denominator))
}, }
(Type::RATIONAL, n) => { (Type::RATIONAL, n) => {
if n as usize > limits.decoding_buffer_size / std::mem::size_of::<Value>() { if n as usize > limits.decoding_buffer_size / std::mem::size_of::<Value>() {
return Err(TiffError::LimitsExceeded) return Err(TiffError::LimitsExceeded);
} }
let mut v = Vec::with_capacity(n as usize); let mut v = Vec::with_capacity(n as usize);
try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
for _ in 0 .. n { for _ in 0..n {
let numerator = try!(decoder.read_long()); let numerator = try!(decoder.read_long());
let denominator = try!(decoder.read_long()); let denominator = try!(decoder.read_long());
v.push(Rational(numerator, denominator)) v.push(Rational(numerator, denominator))
} }
Ok(List(v)) Ok(List(v))
}, }
(Type::ASCII, n) => { (Type::ASCII, n) => {
if n as usize > limits.decoding_buffer_size { if n as usize > limits.decoding_buffer_size {
return Err(TiffError::LimitsExceeded) return Err(TiffError::LimitsExceeded);
} }
try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
let string = try!(decoder.read_string(n as usize)); let string = try!(decoder.read_string(n as usize));
Ok(Ascii(string)) Ok(Ascii(string))
} }
_ => Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedDataType)) _ => Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedDataType,
)),
} }
} }
} }
+226 -109
View File
@@ -1,18 +1,12 @@
use std::io::{self, Read, Seek};
use num_traits::{FromPrimitive, Num}; use num_traits::{FromPrimitive, Num};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::{self, Read, Seek};
use ::{ColorType, TiffError, TiffFormatError, TiffUnsupportedError, TiffResult}; use {ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
use self::ifd::Directory; use self::ifd::Directory;
use self::stream::{ use self::stream::{ByteOrder, EndianReader, LZWReader, PackBitsReader, SmartReader};
ByteOrder,
EndianReader,
SmartReader,
LZWReader,
PackBitsReader
};
pub mod ifd; pub mod ifd;
mod stream; mod stream;
@@ -23,15 +17,14 @@ pub enum DecodingResult {
/// A vector of unsigned bytes /// A vector of unsigned bytes
U8(Vec<u8>), U8(Vec<u8>),
/// A vector of unsigned words /// A vector of unsigned words
U16(Vec<u16>) U16(Vec<u16>),
} }
impl DecodingResult { impl DecodingResult {
fn new_u8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { fn new_u8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size { if size > limits.decoding_buffer_size {
Err(TiffError::LimitsExceeded) Err(TiffError::LimitsExceeded)
} } else {
else {
Ok(DecodingResult::U8(vec![0; size])) Ok(DecodingResult::U8(vec![0; size]))
} }
} }
@@ -39,8 +32,7 @@ impl DecodingResult {
fn new_u16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> { fn new_u16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size / 2 { if size > limits.decoding_buffer_size / 2 {
Err(TiffError::LimitsExceeded) Err(TiffError::LimitsExceeded)
} } else {
else {
Ok(DecodingResult::U16(vec![0; size])) Ok(DecodingResult::U16(vec![0; size]))
} }
} }
@@ -58,7 +50,7 @@ pub enum DecodingBuffer<'a> {
/// A slice of unsigned bytes /// A slice of unsigned bytes
U8(&'a mut [u8]), U8(&'a mut [u8]),
/// A slice of unsigned words /// A slice of unsigned words
U16(&'a mut [u16]) U16(&'a mut [u16]),
} }
impl<'a> DecodingBuffer<'a> { impl<'a> DecodingBuffer<'a> {
@@ -76,7 +68,10 @@ impl<'a> DecodingBuffer<'a> {
} }
} }
fn copy<'b>(&'b mut self) -> DecodingBuffer<'b> where 'a: 'b { fn copy<'b>(&'b mut self) -> DecodingBuffer<'b>
where
'a: 'b,
{
match self { match self {
DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf), DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf),
DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf), DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf),
@@ -104,19 +99,19 @@ pub enum CompressionMethod {
Fax4 = 4, Fax4 = 4,
LZW = 5, LZW = 5,
JPEG = 6, JPEG = 6,
PackBits = 0x8005 PackBits = 0x8005,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
pub enum PlanarConfiguration { pub enum PlanarConfiguration {
Chunky = 1, Chunky = 1,
Planar = 2 Planar = 2,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
enum Predictor { enum Predictor {
None = 1, None = 1,
Horizontal = 2 Horizontal = 2,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -129,12 +124,12 @@ struct StripDecodeState {
/// Decoding limits /// Decoding limits
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Limits { pub struct Limits {
/// The maximum size of any `DecodingResult` in bytes, the default is /// The maximum size of any `DecodingResult` in bytes, the default is
/// 256MiB. If the entire image is decoded at once, then this will /// 256MiB. If the entire image is decoded at once, then this will
/// be the maximum size of the image. If it is decoded one strip at a /// be the maximum size of the image. If it is decoded one strip at a
/// time, this will be the maximum size of a strip. /// time, this will be the maximum size of a strip.
decoding_buffer_size: usize, decoding_buffer_size: usize,
/// The maximum size of any ifd value in bytes, the default is /// The maximum size of any ifd value in bytes, the default is
/// 1MiB. /// 1MiB.
ifd_value_size: usize, ifd_value_size: usize,
} }
@@ -142,8 +137,8 @@ pub struct Limits {
impl Default for Limits { impl Default for Limits {
fn default() -> Limits { fn default() -> Limits {
Limits { Limits {
decoding_buffer_size: 256*1024*1024, decoding_buffer_size: 256 * 1024 * 1024,
ifd_value_size: 1024*1024, ifd_value_size: 1024 * 1024,
} }
} }
} }
@@ -152,7 +147,10 @@ impl Default for Limits {
/// ///
/// Currently does not support decoding of interlaced images /// Currently does not support decoding of interlaced images
#[derive(Debug)] #[derive(Debug)]
pub struct Decoder<R> where R: Read + Seek { pub struct Decoder<R>
where
R: Read + Seek,
{
reader: SmartReader<R>, reader: SmartReader<R>,
byte_order: ByteOrder, byte_order: ByteOrder,
limits: Limits, limits: Limits,
@@ -183,10 +181,10 @@ impl Wrapping for u16 {
} }
} }
fn rev_hpredict_nsamp<T>(image: &mut [T], fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
size: (u32, u32), where
samples: usize) T: Num + Copy + Wrapping,
where T: Num + 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;
for row in 0..height { for row in 0..height {
@@ -203,12 +201,16 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType)
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) | ColorType::CMYK(8) => 4, ColorType::RGBA(8) | ColorType::RGBA(16) | ColorType::CMYK(8) => 4,
_ => return Err(TiffError::UnsupportedError(TiffUnsupportedError::HorizontalPredictor(color_type))) _ => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::HorizontalPredictor(color_type),
))
}
}; };
match image { match image {
DecodingBuffer::U8(buf) => { DecodingBuffer::U8(buf) => {
rev_hpredict_nsamp(buf, size, samples); rev_hpredict_nsamp(buf, size, samples);
}, }
DecodingBuffer::U16(buf) => { DecodingBuffer::U16(buf) => {
rev_hpredict_nsamp(buf, size, samples); rev_hpredict_nsamp(buf, size, samples);
} }
@@ -232,7 +234,8 @@ impl<R: Read + Seek> Decoder<R> {
photometric_interpretation: PhotometricInterpretation::BlackIsZero, photometric_interpretation: PhotometricInterpretation::BlackIsZero,
compression_method: CompressionMethod::None, compression_method: CompressionMethod::None,
strip_decoder: None, strip_decoder: None,
}.init() }
.init()
} }
pub fn with_limits(mut self, limits: Limits) -> Decoder<R> { pub fn with_limits(mut self, limits: Limits) -> Decoder<R> {
@@ -247,16 +250,34 @@ impl<R: Read + Seek> Decoder<R> {
pub fn colortype(&mut self) -> TiffResult<ColorType> { pub 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] => {
PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 8] => Ok(ColorType::RGB(8)), Ok(ColorType::RGBA(8))
PhotometricInterpretation::RGB if self.bits_per_sample == [16, 16, 16, 16] => Ok(ColorType::RGBA(16)), }
PhotometricInterpretation::RGB if self.bits_per_sample == [16, 16, 16] => Ok(ColorType::RGB(16)), PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 8] => {
PhotometricInterpretation::CMYK if self.bits_per_sample == [8, 8, 8, 8] => Ok(ColorType::CMYK(8)), Ok(ColorType::RGB(8))
}
PhotometricInterpretation::RGB if self.bits_per_sample == [16, 16, 16, 16] => {
Ok(ColorType::RGBA(16))
}
PhotometricInterpretation::RGB if self.bits_per_sample == [16, 16, 16] => {
Ok(ColorType::RGB(16))
}
PhotometricInterpretation::CMYK if self.bits_per_sample == [8, 8, 8, 8] => {
Ok(ColorType::CMYK(8))
}
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]))
}
// 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()))) _ => Err(TiffError::UnsupportedError(
TiffUnsupportedError::InterpretationWithBits(
self.photometric_interpretation,
self.bits_per_sample.clone(),
),
)),
} }
} }
@@ -266,18 +287,26 @@ impl<R: Read + Seek> Decoder<R> {
match &*endianess { match &*endianess {
b"II" => { b"II" => {
self.byte_order = ByteOrder::LittleEndian; self.byte_order = ByteOrder::LittleEndian;
self.reader.byte_order = ByteOrder::LittleEndian; }, self.reader.byte_order = ByteOrder::LittleEndian;
}
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(TiffError::FormatError(TiffFormatError::TiffSignatureNotFound)) }
_ => {
return Err(TiffError::FormatError(
TiffFormatError::TiffSignatureNotFound,
))
}
} }
if try!(self.read_short()) != 42 { if try!(self.read_short()) != 42 {
return Err(TiffError::FormatError(TiffFormatError::TiffSignatureInvalid)) return Err(TiffError::FormatError(
TiffFormatError::TiffSignatureInvalid,
));
} }
self.next_ifd = match try!(self.read_long()) { self.next_ifd = match try!(self.read_long()) {
0 => None, 0 => None,
n => Some(n) n => Some(n),
}; };
Ok(()) Ok(())
} }
@@ -296,18 +325,24 @@ impl<R: Read + Seek> Decoder<R> {
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));
self.strip_decoder = None; self.strip_decoder = None;
self.photometric_interpretation = match FromPrimitive::from_u32( self.photometric_interpretation = match FromPrimitive::from_u32(try!(
try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation)) self.get_tag_u32(ifd::Tag::PhotometricInterpretation)
) { )) {
Some(val) => val, Some(val) => val,
None => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnknownInterpretation)) None => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnknownInterpretation,
))
}
}; };
if let Some(val) = try!(self.find_tag_u32(ifd::Tag::Compression)) { if let Some(val) = try!(self.find_tag_u32(ifd::Tag::Compression)) {
match FromPrimitive::from_u32(val) { match FromPrimitive::from_u32(val) {
Some(method) => { Some(method) => self.compression_method = method,
self.compression_method = method None => {
}, return Err(TiffError::UnsupportedError(
None => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnknownCompressionMethod)) TiffUnsupportedError::UnknownCompressionMethod,
))
}
} }
} }
if let Some(val) = try!(self.find_tag_u32(ifd::Tag::SamplesPerPixel)) { if let Some(val) = try!(self.find_tag_u32(ifd::Tag::SamplesPerPixel)) {
@@ -323,9 +358,12 @@ impl<R: Read + Seek> Decoder<R> {
if let Some(val) = try!(self.find_tag_u32_vec(ifd::Tag::BitsPerSample)) { if let Some(val) = try!(self.find_tag_u32_vec(ifd::Tag::BitsPerSample)) {
self.bits_per_sample = val.iter().map(|&v| v as u8).collect() self.bits_per_sample = val.iter().map(|&v| v as u8).collect()
} }
} }
_ => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedSampleDepth(self.samples))) _ => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedSampleDepth(self.samples),
))
}
} }
Ok(self) Ok(self)
} }
@@ -373,7 +411,9 @@ impl<R: Read + Seek> Decoder<R> {
/// Moves the cursor to the specified offset /// Moves the cursor to the specified offset
#[inline] #[inline]
pub fn goto_offset(&mut self, offset: u32) -> io::Result<()> { pub fn goto_offset(&mut self, offset: u32) -> io::Result<()> {
self.reader.seek(io::SeekFrom::Start(u64::from(offset))).map(|_| ()) self.reader
.seek(io::SeekFrom::Start(u64::from(offset)))
.map(|_| ())
} }
/// Reads a IFD entry. /// Reads a IFD entry.
@@ -391,34 +431,40 @@ impl<R: Read + Seek> Decoder<R> {
// Unknown type. Skip this entry according to spec. // Unknown type. Skip this entry according to spec.
try!(self.read_long()); try!(self.read_long());
try!(self.read_long()); try!(self.read_long());
return Ok(None) return Ok(None);
} }
}; };
Ok(Some((tag, ifd::Entry::new( Ok(Some((
type_, tag,
try!(self.read_long()), // count ifd::Entry::new(
try!(self.read_offset()) // offset type_,
)))) try!(self.read_long()), // count
try!(self.read_offset()), // offset
),
)))
} }
/// Reads the next IFD /// Reads the next IFD
fn read_ifd(&mut self) -> TiffResult<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(TiffError::FormatError(TiffFormatError::ImageFileDirectoryNotFound)), None => {
Some(offset) => try!(self.goto_offset(offset)) return Err(TiffError::FormatError(
TiffFormatError::ImageFileDirectoryNotFound,
))
}
Some(offset) => try!(self.goto_offset(offset)),
} }
for _ in 0..try!(self.read_short()) { for _ in 0..try!(self.read_short()) {
let (tag, entry) = match try!(self.read_entry()) { let (tag, entry) = match try!(self.read_entry()) {
Some(val) => val, Some(val) => val,
None => continue // Unknown data type in tag, skip None => continue, // Unknown data type in tag, skip
}; };
dir.insert(tag, entry); dir.insert(tag, entry);
} }
self.next_ifd = match try!(self.read_long()) { self.next_ifd = match try!(self.read_long()) {
0 => None, 0 => None,
n => Some(n) n => Some(n),
}; };
Ok(dir) Ok(dir)
} }
@@ -440,7 +486,7 @@ impl<R: Read + Seek> Decoder<R> {
pub fn find_tag_u32(&mut self, tag: ifd::Tag) -> TiffResult<Option<u32>> { pub 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),
} }
} }
@@ -448,7 +494,7 @@ impl<R: Read + Seek> Decoder<R> {
pub fn find_tag_u32_vec(&mut self, tag: ifd::Tag) -> TiffResult<Option<Vec<u32>>> { pub 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),
} }
} }
@@ -457,7 +503,9 @@ impl<R: Read + Seek> Decoder<R> {
pub fn get_tag(&mut self, tag: ifd::Tag) -> TiffResult<ifd::Value> { pub 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(TiffError::FormatError(TiffFormatError::RequiredTagNotFound(tag))), None => Err(TiffError::FormatError(
TiffFormatError::RequiredTagNotFound(tag),
)),
} }
} }
@@ -473,50 +521,73 @@ impl<R: Read + Seek> Decoder<R> {
/// 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) -> TiffResult<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 {
CompressionMethod::None => { CompressionMethod::None => {
let order = self.reader.byte_order; let order = self.reader.byte_order;
(length as usize, Box::new(SmartReader::wrap(&mut self.reader, order))) (
}, length as usize,
Box::new(SmartReader::wrap(&mut self.reader, order)),
)
}
CompressionMethod::LZW => { CompressionMethod::LZW => {
let (bytes, reader) = try!(LZWReader::new(&mut self.reader, length as usize, max_uncompressed_length)); let (bytes, reader) = try!(LZWReader::new(
&mut self.reader,
length as usize,
max_uncompressed_length
));
(bytes, Box::new(reader)) (bytes, Box::new(reader))
}, }
CompressionMethod::PackBits => { CompressionMethod::PackBits => {
let order = self.reader.byte_order; let order = self.reader.byte_order;
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(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedCompressionMethod(method))) method => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedCompressionMethod(method),
))
}
}; };
if bytes / buffer.byte_len() > max_uncompressed_length { if bytes / buffer.byte_len() > max_uncompressed_length {
return Err(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered)); return Err(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered,
));
} }
Ok(match (color_type, buffer) { Ok(match (color_type, buffer) {
(ColorType:: RGB(8), DecodingBuffer::U8(ref mut buffer)) | (ColorType::RGB(8), DecodingBuffer::U8(ref mut buffer))
(ColorType::RGBA(8), DecodingBuffer::U8(ref mut buffer)) | | (ColorType::RGBA(8), DecodingBuffer::U8(ref mut buffer))
(ColorType::CMYK(8), DecodingBuffer::U8(ref mut buffer)) => { | (ColorType::CMYK(8), DecodingBuffer::U8(ref mut buffer)) => {
try!(reader.read_exact(&mut buffer[..bytes])); try!(reader.read_exact(&mut buffer[..bytes]));
bytes bytes
} }
(ColorType::RGBA(16), DecodingBuffer::U16(ref mut buffer)) | (ColorType::RGBA(16), DecodingBuffer::U16(ref mut buffer))
(ColorType:: RGB(16), DecodingBuffer::U16(ref mut buffer)) => { | (ColorType::RGB(16), DecodingBuffer::U16(ref mut buffer)) => {
try!(reader.read_u16_into(&mut buffer[..bytes/2])); try!(reader.read_u16_into(&mut buffer[..bytes / 2]));
bytes/2 bytes / 2
} }
(ColorType::Gray(16), DecodingBuffer::U16(ref mut buffer)) => { (ColorType::Gray(16), DecodingBuffer::U16(ref mut buffer)) => {
try!(reader.read_u16_into(&mut buffer[..bytes/2])); try!(reader.read_u16_into(&mut buffer[..bytes / 2]));
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero { if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
for datum in buffer[..bytes/2].iter_mut() { for datum in buffer[..bytes / 2].iter_mut() {
*datum = 0xffff - *datum *datum = 0xffff - *datum
} }
} }
bytes/2 bytes / 2
} }
(ColorType::Gray(n), DecodingBuffer::U8(ref mut buffer)) if n <= 8 => { (ColorType::Gray(n), DecodingBuffer::U8(ref mut buffer)) if n <= 8 => {
try!(reader.read_exact(&mut buffer[..bytes])); try!(reader.read_exact(&mut buffer[..bytes]));
@@ -527,15 +598,20 @@ impl<R: Read + Seek> Decoder<R> {
} }
bytes bytes
} }
(type_, _) => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedColorType(type_))), (type_, _) => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedColorType(type_),
))
}
}) })
} }
/// Number of strips in image /// Number of strips in image
pub fn strip_count(&mut self) -> TiffResult<u32> { pub fn strip_count(&mut self) -> TiffResult<u32> {
let rows_per_strip = self.get_tag_u32(ifd::Tag::RowsPerStrip) let rows_per_strip = self
.get_tag_u32(ifd::Tag::RowsPerStrip)
.unwrap_or(self.height); .unwrap_or(self.height);
Ok((self.height + rows_per_strip - 1) / rows_per_strip) Ok((self.height + rows_per_strip - 1) / rows_per_strip)
} }
@@ -557,20 +633,40 @@ impl<R: Read + Seek> Decoder<R> {
self.initialize_strip_decoder()?; self.initialize_strip_decoder()?;
let index = self.strip_decoder.as_ref().unwrap().strip_index; let index = self.strip_decoder.as_ref().unwrap().strip_index;
let offset = *self.strip_decoder.as_ref().unwrap().strip_offsets.get(index) let offset = *self
.ok_or(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered))?; .strip_decoder
let byte_count = *self.strip_decoder.as_ref().unwrap().strip_bytes.get(index) .as_ref()
.ok_or(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered))?; .unwrap()
.strip_offsets
.get(index)
.ok_or(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered,
))?;
let byte_count = *self
.strip_decoder
.as_ref()
.unwrap()
.strip_bytes
.get(index)
.ok_or(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered,
))?;
let rows_per_strip = self.get_tag_u32(ifd::Tag::RowsPerStrip) let rows_per_strip = self
.get_tag_u32(ifd::Tag::RowsPerStrip)
.unwrap_or(self.height) as usize; .unwrap_or(self.height) as usize;
let strip_height = std::cmp::min(rows_per_strip, self.height as usize - index * rows_per_strip); let strip_height = std::cmp::min(
rows_per_strip,
self.height as usize - index * rows_per_strip,
);
let buffer_size = self.width as usize * strip_height * self.bits_per_sample.len(); let buffer_size = self.width as usize * strip_height * self.bits_per_sample.len();
if buffer.len() < buffer_size || byte_count as usize / buffer.byte_len() > buffer_size { if buffer.len() < buffer_size || byte_count as usize / buffer.byte_len() > buffer_size {
return Err(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered)); return Err(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered,
));
} }
let units_read = self.expand_strip(buffer.copy(), offset, byte_count, buffer_size)?; let units_read = self.expand_strip(buffer.copy(), offset, byte_count, buffer_size)?;
@@ -582,7 +678,9 @@ impl<R: Read + Seek> Decoder<R> {
} }
if units_read < buffer_size { if units_read < buffer_size {
return Err(TiffError::FormatError(TiffFormatError::InconsistentSizesEncountered)); return Err(TiffError::FormatError(
TiffFormatError::InconsistentSizesEncountered,
));
} }
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) { match FromPrimitive::from_u32(predictor) {
@@ -591,10 +689,14 @@ impl<R: Read + Seek> Decoder<R> {
rev_hpredict( rev_hpredict(
buffer.copy(), buffer.copy(),
(self.width, strip_height as u32), (self.width, strip_height as u32),
self.colortype()? self.colortype()?,
)?; )?;
}, }
None => return Err(TiffError::FormatError(TiffFormatError::UnknownPredictor(predictor))), None => {
return Err(TiffError::FormatError(TiffFormatError::UnknownPredictor(
predictor,
)))
}
} }
} }
Ok(()) Ok(())
@@ -605,17 +707,25 @@ impl<R: Read + Seek> Decoder<R> {
self.initialize_strip_decoder()?; self.initialize_strip_decoder()?;
let index = self.strip_decoder.as_ref().unwrap().strip_index; let index = self.strip_decoder.as_ref().unwrap().strip_index;
let rows_per_strip = self.get_tag_u32(ifd::Tag::RowsPerStrip) let rows_per_strip = self
.get_tag_u32(ifd::Tag::RowsPerStrip)
.unwrap_or(self.height) as usize; .unwrap_or(self.height) as usize;
let strip_height = std::cmp::min(rows_per_strip, self.height as usize - index * rows_per_strip); let strip_height = std::cmp::min(
rows_per_strip,
self.height as usize - index * rows_per_strip,
);
let buffer_size = self.width as usize * strip_height * self.bits_per_sample.iter().count(); let buffer_size = self.width as usize * strip_height * self.bits_per_sample.iter().count();
let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) {
n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?, n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?,
n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits)?, n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits)?,
n => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedBitsPerChannel(n))), n => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
))
}
}; };
self.read_strip_to_buffer(result.as_buffer(0))?; self.read_strip_to_buffer(result.as_buffer(0))?;
@@ -626,17 +736,24 @@ impl<R: Read + Seek> Decoder<R> {
/// Decodes the entire image and return it as a Vector /// Decodes the entire image and return it as a Vector
pub fn read_image(&mut self) -> TiffResult<DecodingResult> { pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
self.initialize_strip_decoder()?; self.initialize_strip_decoder()?;
let rows_per_strip = self.get_tag_u32(ifd::Tag::RowsPerStrip) let rows_per_strip = self
.get_tag_u32(ifd::Tag::RowsPerStrip)
.unwrap_or(self.height) as usize; .unwrap_or(self.height) as usize;
let samples_per_strip = self.width as usize * rows_per_strip * self.bits_per_sample.iter().count(); let samples_per_strip =
self.width as usize * rows_per_strip * self.bits_per_sample.iter().count();
let buffer_size = self.width as usize * self.height as usize * self.bits_per_sample.iter().count(); let buffer_size =
self.width as usize * self.height as usize * self.bits_per_sample.iter().count();
let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) { let mut result = match self.bits_per_sample.iter().cloned().max().unwrap_or(8) {
n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?, n if n <= 8 => DecodingResult::new_u8(buffer_size, &self.limits)?,
n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits)?, n if n <= 16 => DecodingResult::new_u16(buffer_size, &self.limits)?,
n => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedBitsPerChannel(n))), n => {
return Err(TiffError::UnsupportedError(
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
))
}
}; };
for i in 0..self.strip_count()? as usize { for i in 0..self.strip_count()? as usize {
+66 -33
View File
@@ -1,8 +1,8 @@
//! All IO functionality needed for TIFF decoding //! All IO functionality needed for TIFF decoding
use std::io::{self, Read, Seek}; use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
use byteorder::{ReadBytesExt, BigEndian, LittleEndian};
use lzw; use lzw;
use std::io::{self, Read, Seek};
/// Byte order of the TIFF file. /// Byte order of the TIFF file.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
@@ -10,10 +10,9 @@ pub enum ByteOrder {
/// little endian byte order /// little endian byte order
LittleEndian, LittleEndian,
/// big endian byte order /// big endian byte order
BigEndian BigEndian,
} }
/// Reader that is aware of the byte order. /// Reader that is aware of the byte order.
pub trait EndianReader: Read { pub trait EndianReader: Read {
/// Byte order that should be adhered to /// Byte order that should be adhered to
@@ -24,15 +23,19 @@ pub trait EndianReader: Read {
fn read_u16(&mut self) -> Result<u16, io::Error> { fn read_u16(&mut self) -> Result<u16, io::Error> {
match self.byte_order() { match self.byte_order() {
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u16::<LittleEndian>(self), ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u16::<LittleEndian>(self),
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u16::<BigEndian>(self) ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u16::<BigEndian>(self),
} }
} }
#[inline(always)] #[inline(always)]
fn read_u16_into(&mut self, buffer: &mut [u16]) -> Result<(), io::Error> { fn read_u16_into(&mut self, buffer: &mut [u16]) -> Result<(), io::Error> {
match self.byte_order() { match self.byte_order() {
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u16_into::<LittleEndian>(self, buffer), ByteOrder::LittleEndian => {
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u16_into::<BigEndian>(self, buffer) <Self as ReadBytesExt>::read_u16_into::<LittleEndian>(self, buffer)
}
ByteOrder::BigEndian => {
<Self as ReadBytesExt>::read_u16_into::<BigEndian>(self, buffer)
}
} }
} }
@@ -41,7 +44,7 @@ pub trait EndianReader: Read {
fn read_u32(&mut self) -> Result<u32, io::Error> { fn read_u32(&mut self) -> Result<u32, io::Error> {
match self.byte_order() { match self.byte_order() {
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u32::<LittleEndian>(self), ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u32::<LittleEndian>(self),
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u32::<BigEndian>(self) ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u32::<BigEndian>(self),
} }
} }
} }
@@ -49,12 +52,19 @@ pub trait EndianReader: Read {
/// Reader that decompresses LZW streams /// Reader that decompresses LZW streams
pub struct LZWReader { pub struct LZWReader {
buffer: io::Cursor<Vec<u8>>, buffer: io::Cursor<Vec<u8>>,
byte_order: ByteOrder byte_order: ByteOrder,
} }
impl LZWReader { impl LZWReader {
/// Wraps a reader /// Wraps a reader
pub fn new<R>(reader: &mut SmartReader<R>, compressed_length: usize, max_uncompressed_length: usize) -> io::Result<(usize, LZWReader)> where R: Read + Seek { pub fn new<R>(
reader: &mut SmartReader<R>,
compressed_length: usize,
max_uncompressed_length: usize,
) -> io::Result<(usize, LZWReader)>
where
R: Read + Seek,
{
let order = reader.byte_order; let order = reader.byte_order;
let mut compressed = vec![0; compressed_length as usize]; let mut compressed = vec![0; compressed_length as usize];
try!(reader.read_exact(&mut compressed[..])); try!(reader.read_exact(&mut compressed[..]));
@@ -68,10 +78,13 @@ impl LZWReader {
} }
let bytes = uncompressed.len(); let bytes = uncompressed.len();
Ok((bytes, LZWReader { Ok((
buffer: io::Cursor::new(uncompressed), bytes,
byte_order: order LZWReader {
})) buffer: io::Cursor::new(uncompressed),
byte_order: order,
},
))
} }
} }
@@ -92,25 +105,32 @@ impl EndianReader for LZWReader {
/// Reader that unpacks Apple's `PackBits` format /// Reader that unpacks Apple's `PackBits` format
pub struct PackBitsReader { pub struct PackBitsReader {
buffer: io::Cursor<Vec<u8>>, buffer: io::Cursor<Vec<u8>>,
byte_order: ByteOrder byte_order: ByteOrder,
} }
impl PackBitsReader { impl PackBitsReader {
/// Wraps a reader /// Wraps a reader
pub fn new<R: Read + Seek>(mut reader: R, byte_order: ByteOrder, length: usize) -> io::Result<(usize, PackBitsReader)> { pub fn new<R: Read + Seek>(
mut reader: R,
byte_order: ByteOrder,
length: usize,
) -> io::Result<(usize, PackBitsReader)> {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
let mut read: usize = 0; let mut read: usize = 0;
while read < length { while read < length {
let lread = read_packbits_run(&mut reader, &mut buffer)?; let lread = read_packbits_run(&mut reader, &mut buffer)?;
if lread == 0 { if lread == 0 {
return Err(io::ErrorKind::UnexpectedEof.into()) return Err(io::ErrorKind::UnexpectedEof.into());
} }
read += lread; read += lread;
} }
Ok((buffer.len(), PackBitsReader { Ok((
buffer: io::Cursor::new(buffer), buffer.len(),
byte_order PackBitsReader {
})) buffer: io::Cursor::new(buffer),
byte_order,
},
))
} }
} }
@@ -128,7 +148,7 @@ fn read_packbits_run<R: Read + Seek>(reader: &mut R, buffer: &mut Vec<u8>) -> io
try!(reader.read_exact(&mut header)); try!(reader.read_exact(&mut header));
buffer.resize(new_len, header[0]); buffer.resize(new_len, header[0]);
Ok(2) Ok(2)
}, }
h => { h => {
let num_vals = h as usize + 1; let num_vals = h as usize + 1;
let start = buffer.len(); let start = buffer.len();
@@ -136,7 +156,7 @@ fn read_packbits_run<R: Read + Seek>(reader: &mut R, buffer: &mut Vec<u8>) -> io
try!(reader.read_exact(&mut buffer[start..])); try!(reader.read_exact(&mut buffer[start..]));
Ok(num_vals + 1) Ok(num_vals + 1)
} }
} },
} }
} }
@@ -156,19 +176,28 @@ impl EndianReader for PackBitsReader {
/// Reader that is aware of the byte order. /// Reader that is aware of the byte order.
#[derive(Debug)] #[derive(Debug)]
pub struct SmartReader<R> where R: Read + Seek { pub struct SmartReader<R>
where
R: Read + Seek,
{
reader: R, reader: R,
pub byte_order: ByteOrder pub byte_order: ByteOrder,
} }
impl<R> SmartReader<R> where R: Read + Seek { impl<R> SmartReader<R>
where
R: Read + Seek,
{
/// Wraps a reader /// Wraps a reader
pub fn wrap(reader: R, byte_order: ByteOrder) -> SmartReader<R> { pub fn wrap(reader: R, byte_order: ByteOrder) -> SmartReader<R> {
SmartReader { reader, byte_order } SmartReader { reader, byte_order }
} }
} }
impl<R> EndianReader for SmartReader<R> where R: Read + Seek { impl<R> EndianReader for SmartReader<R>
where
R: Read + Seek,
{
#[inline(always)] #[inline(always)]
fn byte_order(&self) -> ByteOrder { fn byte_order(&self) -> ByteOrder {
self.byte_order self.byte_order
@@ -195,19 +224,23 @@ mod test {
#[test] #[test]
fn test_packbits() { fn test_packbits() {
let encoded = vec![0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, let encoded = vec![
0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7, 0xAA]; 0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, 0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7,
0xAA,
];
let encoded_len = encoded.len(); let encoded_len = encoded.len();
let buff = io::Cursor::new(encoded); let buff = io::Cursor::new(encoded);
let (_, mut decoder) = PackBitsReader::new(buff, ByteOrder::LittleEndian, encoded_len).unwrap(); let (_, mut decoder) =
PackBitsReader::new(buff, ByteOrder::LittleEndian, encoded_len).unwrap();
let mut decoded = Vec::new(); let mut decoded = Vec::new();
decoder.read_to_end(&mut decoded).unwrap(); decoder.read_to_end(&mut decoded).unwrap();
let expected = vec![0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, let expected = vec![
0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]; 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
];
assert_eq!(decoded, expected); assert_eq!(decoded, expected);
} }
} }
+51 -32
View File
@@ -1,15 +1,15 @@
use std::io::{Write, Seek}; use byteorder::NativeEndian;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use byteorder::{NativeEndian}; use std::io::{Seek, Write};
use crate::decoder::ifd::{self, Tag}; use crate::decoder::ifd::{self, Tag};
use crate::error::{TiffResult, TiffFormatError, TiffError}; use crate::error::{TiffError, TiffFormatError, TiffResult};
mod writer;
pub mod colortype; pub mod colortype;
mod writer;
use self::writer::*;
use self::colortype::*; use self::colortype::*;
use self::writer::*;
/// Type to represent tiff values of type `RATIONAL` /// Type to represent tiff values of type `RATIONAL`
#[derive(Clone)] #[derive(Clone)]
@@ -60,9 +60,8 @@ impl TiffValue for [u16] {
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> { fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
// We write using nativeedian so this sould be safe // We write using nativeedian so this sould be safe
let slice = unsafe { let slice =
std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()*2) unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 2) };
};
writer.write_bytes(slice)?; writer.write_bytes(slice)?;
Ok(()) Ok(())
} }
@@ -78,9 +77,8 @@ impl TiffValue for [u32] {
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> { fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
// We write using nativeedian so this sould be safe // We write using nativeedian so this sould be safe
let slice = unsafe { let slice =
std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()*4) unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 4) };
};
writer.write_bytes(slice)?; writer.write_bytes(slice)?;
Ok(()) Ok(())
} }
@@ -172,8 +170,7 @@ impl TiffValue for str {
writer.write_bytes(self.as_bytes())?; writer.write_bytes(self.as_bytes())?;
writer.write_u8(0)?; writer.write_u8(0)?;
Ok(()) Ok(())
} } else {
else {
Err(TiffError::FormatError(TiffFormatError::InvalidTag)) Err(TiffError::FormatError(TiffFormatError::InvalidTag))
} }
} }
@@ -219,7 +216,7 @@ impl<W: Write + Seek> TiffEncoder<W> {
let mut encoder = TiffEncoder { let mut encoder = TiffEncoder {
writer: TiffWriter::new(writer), writer: TiffWriter::new(writer),
}; };
NativeEndian::write_header(&mut encoder.writer)?; NativeEndian::write_header(&mut encoder.writer)?;
Ok(encoder) Ok(encoder)
@@ -231,20 +228,32 @@ impl<W: Write + Seek> TiffEncoder<W> {
} }
/// Create an 'ImageEncoder' to encode an image one slice at a time. /// Create an 'ImageEncoder' to encode an image one slice at a time.
pub fn new_image<C: ColorType>(&mut self, width: u32, height: u32) -> TiffResult<ImageEncoder<W, C>> { pub fn new_image<C: ColorType>(
&mut self,
width: u32,
height: u32,
) -> TiffResult<ImageEncoder<W, C>> {
let encoder = DirectoryEncoder::new(&mut self.writer)?; let encoder = DirectoryEncoder::new(&mut self.writer)?;
ImageEncoder::new(encoder, width, height) ImageEncoder::new(encoder, width, height)
} }
/// Convenience function to write an entire image from memory. /// Convenience function to write an entire image from memory.
pub fn write_image<C: ColorType>(&mut self, width: u32, height: u32, data: &[C::Inner]) -> TiffResult<()> where [C::Inner]: TiffValue { pub fn write_image<C: ColorType>(
&mut self,
width: u32,
height: u32,
data: &[C::Inner],
) -> TiffResult<()>
where
[C::Inner]: TiffValue,
{
let encoder = DirectoryEncoder::new(&mut self.writer)?; let encoder = DirectoryEncoder::new(&mut self.writer)?;
let mut image: ImageEncoder<W, C> = ImageEncoder::new(encoder, width, height).unwrap(); let mut image: ImageEncoder<W, C> = ImageEncoder::new(encoder, width, height).unwrap();
let mut idx = 0; let mut idx = 0;
while image.next_strip_sample_count() > 0 { while image.next_strip_sample_count() > 0 {
let sample_count = image.next_strip_sample_count() as usize; let sample_count = image.next_strip_sample_count() as usize;
image.write_strip(&data[idx..idx+sample_count]).unwrap(); image.write_strip(&data[idx..idx + sample_count]).unwrap();
idx += sample_count; idx += sample_count;
} }
image.finish() image.finish()
@@ -285,7 +294,8 @@ impl<'a, W: Write + Seek> DirectoryEncoder<'a, W> {
value.write(&mut writer).unwrap(); value.write(&mut writer).unwrap();
} }
self.ifd.insert(tag.to_u16(), (<T>::FIELD_TYPE as u16, value.count(), bytes)); self.ifd
.insert(tag.to_u16(), (<T>::FIELD_TYPE as u16, value.count(), bytes));
} }
fn write_directory(&mut self) -> TiffResult<u64> { fn write_directory(&mut self) -> TiffResult<u64> {
@@ -297,15 +307,14 @@ impl<'a, W: Write + Seek> DirectoryEncoder<'a, W> {
*bytes = vec![0, 0, 0, 0]; *bytes = vec![0, 0, 0, 0];
let mut writer = TiffWriter::new(bytes as &mut [u8]); let mut writer = TiffWriter::new(bytes as &mut [u8]);
writer.write_u32(offset as u32)?; writer.write_u32(offset as u32)?;
} } else {
else {
while bytes.len() < 4 { while bytes.len() < 4 {
bytes.push(0); bytes.push(0);
} }
} }
} }
let offset = self.writer.offset(); let offset = self.writer.offset();
self.writer.write_u16(self.ifd.len() as u16)?; self.writer.write_u16(self.ifd.len() as u16)?;
for (tag, (field_type, count, offset)) in self.ifd.iter() { for (tag, (field_type, count, offset)) in self.ifd.iter() {
@@ -355,7 +364,6 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> {
} }
} }
/// Type to encode images strip by strip. /// Type to encode images strip by strip.
/// ///
/// You should call `finish` on this when you are finished with it. /// You should call `finish` on this when you are finished with it.
@@ -393,7 +401,11 @@ pub struct ImageEncoder<'a, W: Write + Seek, C: ColorType> {
} }
impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
fn new(mut encoder: DirectoryEncoder<'a, W>, width: u32, height: u32) -> TiffResult<ImageEncoder<'a, W, T>> { fn new(
mut encoder: DirectoryEncoder<'a, W>,
width: u32,
height: u32,
) -> TiffResult<ImageEncoder<'a, W, T>> {
let row_samples = u64::from(width) * <T>::BITS_PER_SAMPLE.len() as u64; let row_samples = u64::from(width) * <T>::BITS_PER_SAMPLE.len() as u64;
let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN); let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
@@ -412,10 +424,10 @@ impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32); encoder.write_tag(Tag::RowsPerStrip, rows_per_strip as u32);
encoder.write_tag(Tag::SamplesPerPixel, <T>::BITS_PER_SAMPLE.len() as u16); encoder.write_tag(Tag::SamplesPerPixel, <T>::BITS_PER_SAMPLE.len() as u16);
encoder.write_tag(Tag::XResolution, Rational {n: 1, d: 1}); encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 });
encoder.write_tag(Tag::YResolution, Rational {n: 1, d: 1}); encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 });
encoder.write_tag(Tag::ResolutionUnit, 1u16); encoder.write_tag(Tag::ResolutionUnit, 1u16);
Ok(ImageEncoder { Ok(ImageEncoder {
encoder, encoder,
strip_count, strip_count,
@@ -433,17 +445,23 @@ impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
/// Number of samples the next strip should have. /// Number of samples the next strip should have.
pub fn next_strip_sample_count(&self) -> u64 { pub fn next_strip_sample_count(&self) -> u64 {
if self.strip_idx >= self.strip_count { if self.strip_idx >= self.strip_count {
return 0 return 0;
} }
let start_row = std::cmp::min(u64::from(self.height), self.strip_idx * self.rows_per_strip); let start_row = std::cmp::min(u64::from(self.height), self.strip_idx * self.rows_per_strip);
let end_row = std::cmp::min(u64::from(self.height), (self.strip_idx+1)*self.rows_per_strip); let end_row = std::cmp::min(
u64::from(self.height),
(self.strip_idx + 1) * self.rows_per_strip,
);
(end_row - start_row) * self.row_samples (end_row - start_row) * self.row_samples
} }
/// Write a single strip. /// Write a single strip.
pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()> where [T::Inner]: TiffValue { pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()>
where
[T::Inner]: TiffValue,
{
// TODO: Compression // TODO: Compression
let samples = self.next_strip_sample_count(); let samples = self.next_strip_sample_count();
assert_eq!(value.len() as u64, samples); assert_eq!(value.len() as u64, samples);
@@ -479,8 +497,10 @@ impl<'a, W: Write + Seek, T: ColorType> ImageEncoder<'a, W, T> {
} }
fn finish_internal(&mut self) -> TiffResult<()> { fn finish_internal(&mut self) -> TiffResult<()> {
self.encoder.write_tag(Tag::StripOffsets, &*self.strip_offsets); self.encoder
self.encoder.write_tag(Tag::StripByteCounts, &*self.strip_byte_count); .write_tag(Tag::StripOffsets, &*self.strip_offsets);
self.encoder
.write_tag(Tag::StripByteCounts, &*self.strip_byte_count);
self.dropped = true; self.dropped = true;
self.encoder.finish_internal() self.encoder.finish_internal()
@@ -504,4 +524,3 @@ impl<'a, W: Write + Seek, C: ColorType> Drop for ImageEncoder<'a, W, C> {
} }
} }
} }
+4 -7
View File
@@ -1,6 +1,6 @@
use std::io::{self, Write, Seek, SeekFrom};
use byteorder::{ByteOrder, WriteBytesExt, BigEndian, LittleEndian, NativeEndian};
use crate::error::TiffResult; use crate::error::TiffResult;
use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian, WriteBytesExt};
use std::io::{self, Seek, SeekFrom, Write};
pub trait TiffByteOrder: ByteOrder { pub trait TiffByteOrder: ByteOrder {
fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>; fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
@@ -33,10 +33,7 @@ pub struct TiffWriter<W> {
impl<W: Write> TiffWriter<W> { impl<W: Write> TiffWriter<W> {
pub fn new(writer: W) -> Self { pub fn new(writer: W) -> Self {
Self { Self { writer, offset: 0 }
writer,
offset: 0,
}
} }
pub fn offset(&self) -> u64 { pub fn offset(&self) -> u64 {
@@ -82,7 +79,7 @@ impl<W: Write> TiffWriter<W> {
let padd_len = 4 - (self.offset % 4); let padd_len = 4 - (self.offset % 4);
self.writer.write_all(&padding[..padd_len as usize])?; self.writer.write_all(&padding[..padd_len as usize])?;
} }
Ok(()) Ok(())
} }
} }
+45 -18
View File
@@ -4,7 +4,7 @@ use std::io;
use std::string; use std::string;
use decoder::ifd::{Tag, Value}; use decoder::ifd::{Tag, Value};
use decoder::{PhotometricInterpretation, CompressionMethod, PlanarConfiguration}; use decoder::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration};
use ColorType; use ColorType;
/// Tiff error kinds. /// Tiff error kinds.
@@ -45,8 +45,12 @@ impl fmt::Display for TiffFormatError {
InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."), InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."),
InvalidTag => write!(fmt, "Image contains invalid tag."), InvalidTag => write!(fmt, "Image contains invalid tag."),
RequiredTagNotFound(ref tag) => write!(fmt, "Required tag `{:?}` not found.", tag), RequiredTagNotFound(ref tag) => write!(fmt, "Required tag `{:?}` not found.", tag),
UnknownPredictor(ref predictor) => write!(fmt, "Unknown predictor “{}” encountered", predictor), UnknownPredictor(ref predictor) => {
UnsignedIntegerExpected(ref val) => write!(fmt, "Expected unsigned integer, {:?} found.", val), write!(fmt, "Unknown predictor “{}” encountered", predictor)
}
UnsignedIntegerExpected(ref val) => {
write!(fmt, "Expected unsigned integer, {:?} found.", val)
}
} }
} }
} }
@@ -69,17 +73,36 @@ impl fmt::Display for TiffUnsupportedError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
use self::TiffUnsupportedError::*; use self::TiffUnsupportedError::*;
match *self { match *self {
HorizontalPredictor(color_type) => write!(fmt, "Horizontal predictor for {:?} is unsupported.", color_type), HorizontalPredictor(color_type) => write!(
InterpretationWithBits(ref photometric_interpretation, ref bits_per_sample) => { fmt,
write!(fmt, "{:?} with {:?} bits per sample is unsupported", photometric_interpretation, bits_per_sample) "Horizontal predictor for {:?} is unsupported.",
}, color_type
UnknownInterpretation => write!(fmt, "The image is using an unknown photometric interpretation."), ),
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."), UnknownCompressionMethod => write!(fmt, "Unknown compression method."),
UnsupportedCompressionMethod(method) => write!(fmt, "Compression method {:?} is unsupported", method), UnsupportedCompressionMethod(method) => {
UnsupportedSampleDepth(samples) => write!(fmt, "{} samples per pixel is supported.", samples), write!(fmt, "Compression method {:?} is unsupported", method)
UnsupportedColorType(color_type) => write!(fmt, "Color type {:?} is unsupported", color_type), }
UnsupportedBitsPerChannel(bits) => write!(fmt, "{} bits per channel not supported", bits), UnsupportedSampleDepth(samples) => {
UnsupportedPlanarConfig(config) => write!(fmt, "Unsupported planar configuration “{:?}”.", config), 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."), UnsupportedDataType => write!(fmt, "Unsupported data type."),
} }
} }
@@ -89,8 +112,12 @@ impl fmt::Display for TiffError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
TiffError::FormatError(ref e) => write!(fmt, "Format error: {}", e), TiffError::FormatError(ref e) => write!(fmt, "Format error: {}", e),
TiffError::UnsupportedError(ref f) => write!(fmt, "The Decoder does not support the \ TiffError::UnsupportedError(ref f) => write!(
image format `{}`", f), fmt,
"The Decoder does not support the \
image format `{}`",
f
),
TiffError::IoError(ref e) => e.fmt(fmt), TiffError::IoError(ref e) => e.fmt(fmt),
TiffError::LimitsExceeded => write!(fmt, "The Decoder limits are exceeded"), TiffError::LimitsExceeded => write!(fmt, "The Decoder limits are exceeded"),
} }
@@ -98,7 +125,7 @@ impl fmt::Display for TiffError {
} }
impl Error for TiffError { impl Error for TiffError {
fn description (&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
TiffError::FormatError(..) => "Format error", TiffError::FormatError(..) => "Format error",
TiffError::UnsupportedError(..) => "Unsupported error", TiffError::UnsupportedError(..) => "Unsupported error",
@@ -107,10 +134,10 @@ impl Error for TiffError {
} }
} }
fn cause (&self) -> Option<&Error> { fn cause(&self) -> Option<&Error> {
match *self { match *self {
TiffError::IoError(ref e) => Some(e), TiffError::IoError(ref e) => Some(e),
_ => None _ => None,
} }
} }
} }
+3 -2
View File
@@ -8,14 +8,15 @@
extern crate byteorder; extern crate byteorder;
extern crate lzw; extern crate lzw;
#[macro_use] extern crate num_derive; #[macro_use]
extern crate num_derive;
extern crate num_traits; extern crate num_traits;
pub mod decoder; pub mod decoder;
pub mod encoder; pub mod encoder;
mod error; mod error;
pub use self::error::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult}; pub use self::error::{TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
/// An enumeration over supported color types and their bit depths /// An enumeration over supported color types and their bit depths
#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)] #[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
+22 -23
View File
@@ -1,14 +1,14 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{ifd::Tag, ifd::Value, Decoder, DecodingResult};
use tiff::ColorType; use tiff::ColorType;
use tiff::decoder::{Decoder, DecodingResult, ifd::Tag, ifd::Value};
use std::fs::File; use std::fs::File;
#[test] #[test]
fn test_gray_u8() fn test_gray_u8() {
{ let img_file =
let img_file = File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!"); File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(8)); assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(8));
let img_res = decoder.read_image(); let img_res = decoder.read_image();
@@ -16,8 +16,7 @@ fn test_gray_u8()
} }
#[test] #[test]
fn test_rgb_u8() fn test_rgb_u8() {
{
let img_file = File::open("./tests/images/rgb-3c-8b.tiff").expect("Cannot find test image!"); let img_file = File::open("./tests/images/rgb-3c-8b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
@@ -26,9 +25,9 @@ fn test_rgb_u8()
} }
#[test] #[test]
fn test_gray_u16() fn test_gray_u16() {
{ let img_file =
let img_file = File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!"); File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(16)); assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(16));
let img_res = decoder.read_image(); let img_res = decoder.read_image();
@@ -36,8 +35,7 @@ fn test_gray_u16()
} }
#[test] #[test]
fn test_rgb_u16() fn test_rgb_u16() {
{
let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!"); let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(16)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(16));
@@ -46,8 +44,7 @@ fn test_rgb_u16()
} }
#[test] #[test]
fn test_string_tags() fn test_string_tags() {
{
// these files have null-terminated strings for their Software tag. One has extra bytes after // these files have null-terminated strings for their Software tag. One has extra bytes after
// the null byte, so we check both to ensure that we're truncating properly // the null byte, so we check both to ensure that we're truncating properly
let filenames = vec!["minisblack-1c-16b.tiff", "rgb-3c-16b.tiff"]; let filenames = vec!["minisblack-1c-16b.tiff", "rgb-3c-16b.tiff"];
@@ -55,10 +52,13 @@ fn test_string_tags()
let path = format!("./tests/images/{}", filename); let path = format!("./tests/images/{}", filename);
let img_file = File::open(path).expect("can't open file"); let img_file = File::open(path).expect("can't open file");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
let software= decoder.get_tag(Tag::Software).unwrap(); let software = decoder.get_tag(Tag::Software).unwrap();
match software { match software {
Value::Ascii(s) => assert_eq!(s, String::from("GraphicsMagick 1.2 unreleased Q16 http://www.GraphicsMagick.org/")), Value::Ascii(s) => assert_eq!(
_ => assert!(false) s,
String::from("GraphicsMagick 1.2 unreleased Q16 http://www.GraphicsMagick.org/")
),
_ => assert!(false),
}; };
} }
} }
@@ -80,8 +80,7 @@ fn test_decode_data() {
assert_eq!(decoder.dimensions().unwrap(), (100, 100)); assert_eq!(decoder.dimensions().unwrap(), (100, 100));
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} } else {
else {
panic!("Wrong data type"); panic!("Wrong data type");
} }
} }
@@ -90,9 +89,9 @@ fn test_decode_data() {
//#[test] //#[test]
//fn test_gray_alpha_u8() //fn test_gray_alpha_u8()
//{ //{
//let img_file = File::open("./tests/images/minisblack-2c-8b-alpha.tiff").expect("Cannot find test image!"); //let img_file = File::open("./tests/images/minisblack-2c-8b-alpha.tiff").expect("Cannot find test image!");
//let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); //let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
//assert_eq!(decoder.colortype().unwrap(), ColorType::GrayA(8)); //assert_eq!(decoder.colortype().unwrap(), ColorType::GrayA(8));
//let img_res = decoder.read_image(); //let img_res = decoder.read_image();
//assert!(img_res.is_ok()); //assert!(img_res.is_ok());
//} //}
+30 -33
View File
@@ -1,12 +1,12 @@
extern crate tiff;
extern crate tempfile; extern crate tempfile;
extern crate tiff;
use tiff::ColorType;
use tiff::decoder::{Decoder, DecodingResult}; use tiff::decoder::{Decoder, DecodingResult};
use tiff::encoder::{colortype, TiffEncoder}; use tiff::encoder::{colortype, TiffEncoder};
use tiff::ColorType;
use std::io::{Seek, SeekFrom};
use std::fs::File; use std::fs::File;
use std::io::{Seek, SeekFrom};
#[test] #[test]
fn encode_decode() { fn encode_decode() {
@@ -23,7 +23,8 @@ fn encode_decode() {
{ {
let mut tiff = TiffEncoder::new(&mut file).unwrap(); let mut tiff = TiffEncoder::new(&mut file).unwrap();
tiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap(); tiff.write_image::<colortype::RGB8>(100, 100, &image_data)
.unwrap();
} }
{ {
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
@@ -32,18 +33,16 @@ fn encode_decode() {
assert_eq!(decoder.dimensions().unwrap(), (100, 100)); assert_eq!(decoder.dimensions().unwrap(), (100, 100));
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} } else {
else {
panic!("Wrong data type"); panic!("Wrong data type");
} }
} }
} }
#[test] #[test]
fn test_gray_u8_roundtrip() fn test_gray_u8_roundtrip() {
{ let img_file =
let img_file = File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!"); File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(8)); assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(8));
@@ -55,25 +54,24 @@ fn test_gray_u8_roundtrip()
let mut file = tempfile::tempfile().unwrap(); let mut file = tempfile::tempfile().unwrap();
{ {
let mut tiff = TiffEncoder::new(&mut file).unwrap(); let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap(); let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::Gray8>(width, height, &image_data).unwrap(); tiff.write_image::<colortype::Gray8>(width, height, &image_data)
.unwrap();
} }
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
{ {
let mut decoder = Decoder::new(&mut file).unwrap(); let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} } else {
else {
panic!("Wrong data type"); panic!("Wrong data type");
} }
} }
} }
#[test] #[test]
fn test_rgb_u8_roundtrip() fn test_rgb_u8_roundtrip() {
{
let img_file = File::open("./tests/images/rgb-3c-8b.tiff").expect("Cannot find test image!"); let img_file = File::open("./tests/images/rgb-3c-8b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
@@ -86,26 +84,26 @@ fn test_rgb_u8_roundtrip()
let mut file = tempfile::tempfile().unwrap(); let mut file = tempfile::tempfile().unwrap();
{ {
let mut tiff = TiffEncoder::new(&mut file).unwrap(); let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap(); let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::RGB8>(width, height, &image_data).unwrap(); tiff.write_image::<colortype::RGB8>(width, height, &image_data)
.unwrap();
} }
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
{ {
let mut decoder = Decoder::new(&mut file).unwrap(); let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} } else {
else {
panic!("Wrong data type"); panic!("Wrong data type");
} }
} }
} }
#[test] #[test]
fn test_gray_u16_roundtrip() fn test_gray_u16_roundtrip() {
{ let img_file =
let img_file = File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!"); File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(16)); assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(16));
@@ -117,25 +115,24 @@ fn test_gray_u16_roundtrip()
let mut file = tempfile::tempfile().unwrap(); let mut file = tempfile::tempfile().unwrap();
{ {
let mut tiff = TiffEncoder::new(&mut file).unwrap(); let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap(); let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::Gray16>(width, height, &image_data).unwrap(); tiff.write_image::<colortype::Gray16>(width, height, &image_data)
.unwrap();
} }
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
{ {
let mut decoder = Decoder::new(&mut file).unwrap(); let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U16(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U16(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} } else {
else {
panic!("Wrong data type"); panic!("Wrong data type");
} }
} }
} }
#[test] #[test]
fn test_rgb_u16_roundtrip() fn test_rgb_u16_roundtrip() {
{
let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!"); let img_file = File::open("./tests/images/rgb-3c-16b.tiff").expect("Cannot find test image!");
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder"); let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(16)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(16));
@@ -148,17 +145,17 @@ fn test_rgb_u16_roundtrip()
let mut file = tempfile::tempfile().unwrap(); let mut file = tempfile::tempfile().unwrap();
{ {
let mut tiff = TiffEncoder::new(&mut file).unwrap(); let mut tiff = TiffEncoder::new(&mut file).unwrap();
let (width, height) = decoder.dimensions().unwrap(); let (width, height) = decoder.dimensions().unwrap();
tiff.write_image::<colortype::RGB16>(width, height, &image_data).unwrap(); tiff.write_image::<colortype::RGB16>(width, height, &image_data)
.unwrap();
} }
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
{ {
let mut decoder = Decoder::new(&mut file).unwrap(); let mut decoder = Decoder::new(&mut file).unwrap();
if let DecodingResult::U16(img_res) = decoder.read_image().unwrap() { if let DecodingResult::U16(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} } else {
else {
panic!("Wrong data type"); panic!("Wrong data type");
} }
} }
+1 -1
View File
@@ -1,7 +1,7 @@
extern crate tiff; extern crate tiff;
use tiff::TiffResult;
use tiff::decoder::Decoder; use tiff::decoder::Decoder;
use tiff::TiffResult;
use std::fs::File; use std::fs::File;