Format code using 'cargo fmt'
This commit is contained in:
10 files changed
+488
-292
No files matched your search
+40
-34
@@ -1,12 +1,12 @@
|
||||
//! Function for reading TIFF tags
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::{self, Read, Seek};
|
||||
use std::collections::{HashMap};
|
||||
|
||||
use super::stream::{ByteOrder, SmartReader, EndianReader};
|
||||
use ::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult};
|
||||
use super::stream::{ByteOrder, EndianReader, SmartReader};
|
||||
use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||
|
||||
use self::Value::{Unsigned, List, Rational, Ascii};
|
||||
use self::Value::{Ascii, List, Rational, Unsigned};
|
||||
|
||||
macro_rules! tags {
|
||||
{$(
|
||||
@@ -37,7 +37,7 @@ macro_rules! tags {
|
||||
}
|
||||
|
||||
// Note: These tags appear in the order they are mentioned in the TIFF reference
|
||||
tags!{
|
||||
tags! {
|
||||
// Baseline tags:
|
||||
Artist 315;
|
||||
// grayscale images PhotometricInterpretation 1 or 3
|
||||
@@ -90,7 +90,6 @@ pub enum Type {
|
||||
RATIONAL = 5,
|
||||
}
|
||||
|
||||
|
||||
#[allow(unused_qualifications)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Value {
|
||||
@@ -98,14 +97,16 @@ pub enum Value {
|
||||
Unsigned(u32),
|
||||
List(Vec<Value>),
|
||||
Rational(u32, u32),
|
||||
Ascii(String)
|
||||
Ascii(String),
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn into_u32(self) -> TiffResult<u32> {
|
||||
match self {
|
||||
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>> {
|
||||
@@ -116,10 +117,10 @@ impl Value {
|
||||
new_vec.push(v.into_u32()?)
|
||||
}
|
||||
Ok(new_vec)
|
||||
},
|
||||
}
|
||||
Unsigned(val) => Ok(vec![val]),
|
||||
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 {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
fmt.write_str(&format!("Entry {{ type_: {:?}, count: {:?}, offset: {:?} }}",
|
||||
self.type_,
|
||||
self.count,
|
||||
&self.offset
|
||||
fmt.write_str(&format!(
|
||||
"Entry {{ type_: {:?}, count: {:?}, offset: {:?} }}",
|
||||
self.type_, self.count, &self.offset
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl 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
|
||||
fn r(&self, byte_order: ByteOrder) -> SmartReader<io::Cursor<Vec<u8>>> {
|
||||
SmartReader::wrap(
|
||||
io::Cursor::new(self.offset.to_vec()),
|
||||
byte_order
|
||||
)
|
||||
SmartReader::wrap(io::Cursor::new(self.offset.to_vec()), byte_order)
|
||||
}
|
||||
|
||||
pub fn val<R: Read + Seek>(&self, limits: &super::Limits, decoder: &mut super::Decoder<R>)
|
||||
-> TiffResult<Value> {
|
||||
pub fn val<R: Read + Seek>(
|
||||
&self,
|
||||
limits: &super::Limits,
|
||||
decoder: &mut super::Decoder<R>,
|
||||
) -> TiffResult<Value> {
|
||||
let bo = decoder.byte_order();
|
||||
match (self.type_, self.count) {
|
||||
// TODO check if this could give wrong results
|
||||
@@ -166,28 +170,28 @@ impl Entry {
|
||||
let mut r = self.r(bo);
|
||||
Ok(List(vec![
|
||||
Unsigned(u32::from(r.read_u16()?)),
|
||||
Unsigned(u32::from(r.read_u16()?))
|
||||
Unsigned(u32::from(r.read_u16()?)),
|
||||
]))
|
||||
},
|
||||
}
|
||||
(Type::SHORT, n) => {
|
||||
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);
|
||||
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()?)))
|
||||
}
|
||||
Ok(List(v))
|
||||
},
|
||||
}
|
||||
(Type::LONG, 1) => Ok(Unsigned(try!(self.r(bo).read_u32()))),
|
||||
(Type::LONG, n) => {
|
||||
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);
|
||||
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())))
|
||||
}
|
||||
Ok(List(v))
|
||||
@@ -197,29 +201,31 @@ impl Entry {
|
||||
let numerator = try!(decoder.read_long());
|
||||
let denominator = try!(decoder.read_long());
|
||||
Ok(Rational(numerator, denominator))
|
||||
},
|
||||
}
|
||||
(Type::RATIONAL, n) => {
|
||||
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);
|
||||
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 denominator = try!(decoder.read_long());
|
||||
v.push(Rational(numerator, denominator))
|
||||
}
|
||||
Ok(List(v))
|
||||
},
|
||||
}
|
||||
(Type::ASCII, n) => {
|
||||
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())));
|
||||
let string = try!(decoder.read_string(n as usize));
|
||||
Ok(Ascii(string))
|
||||
}
|
||||
_ => Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedDataType))
|
||||
_ => Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::UnsupportedDataType,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+226
-109
@@ -1,18 +1,12 @@
|
||||
use std::io::{self, Read, Seek};
|
||||
use num_traits::{FromPrimitive, Num};
|
||||
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::stream::{
|
||||
ByteOrder,
|
||||
EndianReader,
|
||||
SmartReader,
|
||||
LZWReader,
|
||||
PackBitsReader
|
||||
};
|
||||
use self::stream::{ByteOrder, EndianReader, LZWReader, PackBitsReader, SmartReader};
|
||||
|
||||
pub mod ifd;
|
||||
mod stream;
|
||||
@@ -23,15 +17,14 @@ pub enum DecodingResult {
|
||||
/// A vector of unsigned bytes
|
||||
U8(Vec<u8>),
|
||||
/// A vector of unsigned words
|
||||
U16(Vec<u16>)
|
||||
U16(Vec<u16>),
|
||||
}
|
||||
|
||||
impl DecodingResult {
|
||||
fn new_u8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
|
||||
if size > limits.decoding_buffer_size {
|
||||
Err(TiffError::LimitsExceeded)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Ok(DecodingResult::U8(vec![0; size]))
|
||||
}
|
||||
}
|
||||
@@ -39,8 +32,7 @@ impl DecodingResult {
|
||||
fn new_u16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
|
||||
if size > limits.decoding_buffer_size / 2 {
|
||||
Err(TiffError::LimitsExceeded)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Ok(DecodingResult::U16(vec![0; size]))
|
||||
}
|
||||
}
|
||||
@@ -58,7 +50,7 @@ pub enum DecodingBuffer<'a> {
|
||||
/// A slice of unsigned bytes
|
||||
U8(&'a mut [u8]),
|
||||
/// A slice of unsigned words
|
||||
U16(&'a mut [u16])
|
||||
U16(&'a mut [u16]),
|
||||
}
|
||||
|
||||
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 {
|
||||
DecodingBuffer::U8(ref mut buf) => DecodingBuffer::U8(buf),
|
||||
DecodingBuffer::U16(ref mut buf) => DecodingBuffer::U16(buf),
|
||||
@@ -104,19 +99,19 @@ pub enum CompressionMethod {
|
||||
Fax4 = 4,
|
||||
LZW = 5,
|
||||
JPEG = 6,
|
||||
PackBits = 0x8005
|
||||
PackBits = 0x8005,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||
pub enum PlanarConfiguration {
|
||||
Chunky = 1,
|
||||
Planar = 2
|
||||
Planar = 2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||
enum Predictor {
|
||||
None = 1,
|
||||
Horizontal = 2
|
||||
Horizontal = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -129,12 +124,12 @@ struct StripDecodeState {
|
||||
/// Decoding limits
|
||||
#[derive(Clone, Debug)]
|
||||
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
|
||||
/// 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.
|
||||
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.
|
||||
ifd_value_size: usize,
|
||||
}
|
||||
@@ -142,8 +137,8 @@ pub struct Limits {
|
||||
impl Default for Limits {
|
||||
fn default() -> Limits {
|
||||
Limits {
|
||||
decoding_buffer_size: 256*1024*1024,
|
||||
ifd_value_size: 1024*1024,
|
||||
decoding_buffer_size: 256 * 1024 * 1024,
|
||||
ifd_value_size: 1024 * 1024,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +147,10 @@ impl Default for Limits {
|
||||
///
|
||||
/// Currently does not support decoding of interlaced images
|
||||
#[derive(Debug)]
|
||||
pub struct Decoder<R> where R: Read + Seek {
|
||||
pub struct Decoder<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
reader: SmartReader<R>,
|
||||
byte_order: ByteOrder,
|
||||
limits: Limits,
|
||||
@@ -183,10 +181,10 @@ impl Wrapping for u16 {
|
||||
}
|
||||
}
|
||||
|
||||
fn rev_hpredict_nsamp<T>(image: &mut [T],
|
||||
size: (u32, u32),
|
||||
samples: usize)
|
||||
where T: Num + Copy + Wrapping {
|
||||
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize)
|
||||
where
|
||||
T: Num + Copy + Wrapping,
|
||||
{
|
||||
let width = size.0 as usize;
|
||||
let height = size.1 as usize;
|
||||
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::RGB(8) | ColorType::RGB(16) => 3,
|
||||
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 {
|
||||
DecodingBuffer::U8(buf) => {
|
||||
rev_hpredict_nsamp(buf, size, samples);
|
||||
},
|
||||
}
|
||||
DecodingBuffer::U16(buf) => {
|
||||
rev_hpredict_nsamp(buf, size, samples);
|
||||
}
|
||||
@@ -232,7 +234,8 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
photometric_interpretation: PhotometricInterpretation::BlackIsZero,
|
||||
compression_method: CompressionMethod::None,
|
||||
strip_decoder: None,
|
||||
}.init()
|
||||
}
|
||||
.init()
|
||||
}
|
||||
|
||||
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> {
|
||||
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)),
|
||||
PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 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::RGB if self.bits_per_sample == [8, 8, 8, 8] => {
|
||||
Ok(ColorType::RGBA(8))
|
||||
}
|
||||
PhotometricInterpretation::RGB if self.bits_per_sample == [8, 8, 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
|
||||
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
|
||||
_ => 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 {
|
||||
b"II" => {
|
||||
self.byte_order = ByteOrder::LittleEndian;
|
||||
self.reader.byte_order = ByteOrder::LittleEndian; },
|
||||
self.reader.byte_order = ByteOrder::LittleEndian;
|
||||
}
|
||||
b"MM" => {
|
||||
self.byte_order = ByteOrder::BigEndian;
|
||||
self.reader.byte_order = ByteOrder::BigEndian; },
|
||||
_ => return Err(TiffError::FormatError(TiffFormatError::TiffSignatureNotFound))
|
||||
self.reader.byte_order = ByteOrder::BigEndian;
|
||||
}
|
||||
_ => {
|
||||
return Err(TiffError::FormatError(
|
||||
TiffFormatError::TiffSignatureNotFound,
|
||||
))
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
0 => None,
|
||||
n => Some(n)
|
||||
n => Some(n),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@@ -296,18 +325,24 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
self.width = try!(self.get_tag_u32(ifd::Tag::ImageWidth));
|
||||
self.height = try!(self.get_tag_u32(ifd::Tag::ImageLength));
|
||||
self.strip_decoder = None;
|
||||
self.photometric_interpretation = match FromPrimitive::from_u32(
|
||||
try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation))
|
||||
) {
|
||||
self.photometric_interpretation = match FromPrimitive::from_u32(try!(
|
||||
self.get_tag_u32(ifd::Tag::PhotometricInterpretation)
|
||||
)) {
|
||||
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)) {
|
||||
match FromPrimitive::from_u32(val) {
|
||||
Some(method) => {
|
||||
self.compression_method = method
|
||||
},
|
||||
None => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnknownCompressionMethod))
|
||||
Some(method) => self.compression_method = method,
|
||||
None => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::UnknownCompressionMethod,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
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)
|
||||
}
|
||||
@@ -373,7 +411,9 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
/// Moves the cursor to the specified offset
|
||||
#[inline]
|
||||
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.
|
||||
@@ -391,34 +431,40 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
// Unknown type. Skip this entry according to spec.
|
||||
try!(self.read_long());
|
||||
try!(self.read_long());
|
||||
return Ok(None)
|
||||
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
Ok(Some((tag, ifd::Entry::new(
|
||||
type_,
|
||||
try!(self.read_long()), // count
|
||||
try!(self.read_offset()) // offset
|
||||
))))
|
||||
Ok(Some((
|
||||
tag,
|
||||
ifd::Entry::new(
|
||||
type_,
|
||||
try!(self.read_long()), // count
|
||||
try!(self.read_offset()), // offset
|
||||
),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Reads the next IFD
|
||||
fn read_ifd(&mut self) -> TiffResult<Directory> {
|
||||
let mut dir: Directory = HashMap::new();
|
||||
match self.next_ifd {
|
||||
None => return Err(TiffError::FormatError(TiffFormatError::ImageFileDirectoryNotFound)),
|
||||
Some(offset) => try!(self.goto_offset(offset))
|
||||
None => {
|
||||
return Err(TiffError::FormatError(
|
||||
TiffFormatError::ImageFileDirectoryNotFound,
|
||||
))
|
||||
}
|
||||
Some(offset) => try!(self.goto_offset(offset)),
|
||||
}
|
||||
for _ in 0..try!(self.read_short()) {
|
||||
let (tag, entry) = match try!(self.read_entry()) {
|
||||
Some(val) => val,
|
||||
None => continue // Unknown data type in tag, skip
|
||||
None => continue, // Unknown data type in tag, skip
|
||||
};
|
||||
dir.insert(tag, entry);
|
||||
}
|
||||
self.next_ifd = match try!(self.read_long()) {
|
||||
0 => None,
|
||||
n => Some(n)
|
||||
n => Some(n),
|
||||
};
|
||||
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>> {
|
||||
match self.find_tag(tag)? {
|
||||
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>>> {
|
||||
match self.find_tag(tag)? {
|
||||
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> {
|
||||
match try!(self.find_tag(tag)) {
|
||||
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.
|
||||
/// 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());
|
||||
try!(self.goto_offset(offset));
|
||||
let (bytes, mut reader): (usize, Box<EndianReader>) = match self.compression_method {
|
||||
CompressionMethod::None => {
|
||||
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 => {
|
||||
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))
|
||||
},
|
||||
}
|
||||
CompressionMethod::PackBits => {
|
||||
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))
|
||||
},
|
||||
method => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedCompressionMethod(method)))
|
||||
}
|
||||
method => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::UnsupportedCompressionMethod(method),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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) {
|
||||
(ColorType:: RGB(8), DecodingBuffer::U8(ref mut buffer)) |
|
||||
(ColorType::RGBA(8), DecodingBuffer::U8(ref mut buffer)) |
|
||||
(ColorType::CMYK(8), DecodingBuffer::U8(ref mut buffer)) => {
|
||||
(ColorType::RGB(8), DecodingBuffer::U8(ref mut buffer))
|
||||
| (ColorType::RGBA(8), DecodingBuffer::U8(ref mut buffer))
|
||||
| (ColorType::CMYK(8), DecodingBuffer::U8(ref mut buffer)) => {
|
||||
try!(reader.read_exact(&mut buffer[..bytes]));
|
||||
bytes
|
||||
}
|
||||
(ColorType::RGBA(16), DecodingBuffer::U16(ref mut buffer)) |
|
||||
(ColorType:: RGB(16), DecodingBuffer::U16(ref mut buffer)) => {
|
||||
try!(reader.read_u16_into(&mut buffer[..bytes/2]));
|
||||
bytes/2
|
||||
(ColorType::RGBA(16), DecodingBuffer::U16(ref mut buffer))
|
||||
| (ColorType::RGB(16), DecodingBuffer::U16(ref mut buffer)) => {
|
||||
try!(reader.read_u16_into(&mut buffer[..bytes / 2]));
|
||||
bytes / 2
|
||||
}
|
||||
(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 {
|
||||
for datum in buffer[..bytes/2].iter_mut() {
|
||||
for datum in buffer[..bytes / 2].iter_mut() {
|
||||
*datum = 0xffff - *datum
|
||||
}
|
||||
}
|
||||
bytes/2
|
||||
bytes / 2
|
||||
}
|
||||
(ColorType::Gray(n), DecodingBuffer::U8(ref mut buffer)) if n <= 8 => {
|
||||
try!(reader.read_exact(&mut buffer[..bytes]));
|
||||
@@ -527,15 +598,20 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
}
|
||||
bytes
|
||||
}
|
||||
(type_, _) => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedColorType(type_))),
|
||||
(type_, _) => {
|
||||
return Err(TiffError::UnsupportedError(
|
||||
TiffUnsupportedError::UnsupportedColorType(type_),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Number of strips in image
|
||||
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);
|
||||
|
||||
|
||||
Ok((self.height + rows_per_strip - 1) / rows_per_strip)
|
||||
}
|
||||
|
||||
@@ -557,20 +633,40 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
self.initialize_strip_decoder()?;
|
||||
|
||||
let index = self.strip_decoder.as_ref().unwrap().strip_index;
|
||||
let offset = *self.strip_decoder.as_ref().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 offset = *self
|
||||
.strip_decoder
|
||||
.as_ref()
|
||||
.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;
|
||||
|
||||
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();
|
||||
|
||||
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)?;
|
||||
@@ -582,7 +678,9 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
}
|
||||
|
||||
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) {
|
||||
match FromPrimitive::from_u32(predictor) {
|
||||
@@ -591,10 +689,14 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
rev_hpredict(
|
||||
buffer.copy(),
|
||||
(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(())
|
||||
@@ -605,17 +707,25 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
self.initialize_strip_decoder()?;
|
||||
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;
|
||||
|
||||
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 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 <= 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))?;
|
||||
@@ -626,17 +736,24 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
/// Decodes the entire image and return it as a Vector
|
||||
pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
|
||||
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;
|
||||
|
||||
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) {
|
||||
n if n <= 8 => DecodingResult::new_u8(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 {
|
||||
|
||||
+66
-33
@@ -1,8 +1,8 @@
|
||||
//! All IO functionality needed for TIFF decoding
|
||||
|
||||
use std::io::{self, Read, Seek};
|
||||
use byteorder::{ReadBytesExt, BigEndian, LittleEndian};
|
||||
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
|
||||
use lzw;
|
||||
use std::io::{self, Read, Seek};
|
||||
|
||||
/// Byte order of the TIFF file.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -10,10 +10,9 @@ pub enum ByteOrder {
|
||||
/// little endian byte order
|
||||
LittleEndian,
|
||||
/// big endian byte order
|
||||
BigEndian
|
||||
BigEndian,
|
||||
}
|
||||
|
||||
|
||||
/// Reader that is aware of the byte order.
|
||||
pub trait EndianReader: Read {
|
||||
/// Byte order that should be adhered to
|
||||
@@ -24,15 +23,19 @@ pub trait EndianReader: Read {
|
||||
fn read_u16(&mut self) -> Result<u16, io::Error> {
|
||||
match self.byte_order() {
|
||||
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)]
|
||||
fn read_u16_into(&mut self, buffer: &mut [u16]) -> Result<(), io::Error> {
|
||||
match self.byte_order() {
|
||||
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_u16_into::<LittleEndian>(self, buffer),
|
||||
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u16_into::<BigEndian>(self, buffer)
|
||||
ByteOrder::LittleEndian => {
|
||||
<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> {
|
||||
match self.byte_order() {
|
||||
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
|
||||
pub struct LZWReader {
|
||||
buffer: io::Cursor<Vec<u8>>,
|
||||
byte_order: ByteOrder
|
||||
byte_order: ByteOrder,
|
||||
}
|
||||
|
||||
impl LZWReader {
|
||||
/// 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 mut compressed = vec![0; compressed_length as usize];
|
||||
try!(reader.read_exact(&mut compressed[..]));
|
||||
@@ -68,10 +78,13 @@ impl LZWReader {
|
||||
}
|
||||
|
||||
let bytes = uncompressed.len();
|
||||
Ok((bytes, LZWReader {
|
||||
buffer: io::Cursor::new(uncompressed),
|
||||
byte_order: order
|
||||
}))
|
||||
Ok((
|
||||
bytes,
|
||||
LZWReader {
|
||||
buffer: io::Cursor::new(uncompressed),
|
||||
byte_order: order,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,25 +105,32 @@ impl EndianReader for LZWReader {
|
||||
/// Reader that unpacks Apple's `PackBits` format
|
||||
pub struct PackBitsReader {
|
||||
buffer: io::Cursor<Vec<u8>>,
|
||||
byte_order: ByteOrder
|
||||
byte_order: ByteOrder,
|
||||
}
|
||||
|
||||
impl PackBitsReader {
|
||||
/// 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 read: usize = 0;
|
||||
while read < length {
|
||||
let lread = read_packbits_run(&mut reader, &mut buffer)?;
|
||||
if lread == 0 {
|
||||
return Err(io::ErrorKind::UnexpectedEof.into())
|
||||
return Err(io::ErrorKind::UnexpectedEof.into());
|
||||
}
|
||||
read += lread;
|
||||
}
|
||||
Ok((buffer.len(), PackBitsReader {
|
||||
buffer: io::Cursor::new(buffer),
|
||||
byte_order
|
||||
}))
|
||||
Ok((
|
||||
buffer.len(),
|
||||
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));
|
||||
buffer.resize(new_len, header[0]);
|
||||
Ok(2)
|
||||
},
|
||||
}
|
||||
h => {
|
||||
let num_vals = h as usize + 1;
|
||||
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..]));
|
||||
Ok(num_vals + 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,19 +176,28 @@ impl EndianReader for PackBitsReader {
|
||||
|
||||
/// Reader that is aware of the byte order.
|
||||
#[derive(Debug)]
|
||||
pub struct SmartReader<R> where R: Read + Seek {
|
||||
pub struct SmartReader<R>
|
||||
where
|
||||
R: Read + Seek,
|
||||
{
|
||||
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
|
||||
pub fn wrap(reader: R, byte_order: ByteOrder) -> SmartReader<R> {
|
||||
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)]
|
||||
fn byte_order(&self) -> ByteOrder {
|
||||
self.byte_order
|
||||
@@ -195,19 +224,23 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_packbits() {
|
||||
let encoded = vec![0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA,
|
||||
0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7, 0xAA];
|
||||
let encoded = vec![
|
||||
0xFE, 0xAA, 0x02, 0x80, 0x00, 0x2A, 0xFD, 0xAA, 0x03, 0x80, 0x00, 0x2A, 0x22, 0xF7,
|
||||
0xAA,
|
||||
];
|
||||
let encoded_len = encoded.len();
|
||||
|
||||
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();
|
||||
decoder.read_to_end(&mut decoded).unwrap();
|
||||
|
||||
let expected = vec![0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA];
|
||||
let expected = vec![
|
||||
0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0x80, 0x00, 0x2A, 0x22,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
];
|
||||
assert_eq!(decoded, expected);
|
||||
}
|
||||
}
|
||||
+51
-32
@@ -1,15 +1,15 @@
|
||||
use std::io::{Write, Seek};
|
||||
use byteorder::NativeEndian;
|
||||
use std::collections::BTreeMap;
|
||||
use byteorder::{NativeEndian};
|
||||
use std::io::{Seek, Write};
|
||||
|
||||
use crate::decoder::ifd::{self, Tag};
|
||||
use crate::error::{TiffResult, TiffFormatError, TiffError};
|
||||
use crate::error::{TiffError, TiffFormatError, TiffResult};
|
||||
|
||||
mod writer;
|
||||
pub mod colortype;
|
||||
mod writer;
|
||||
|
||||
use self::writer::*;
|
||||
use self::colortype::*;
|
||||
use self::writer::*;
|
||||
|
||||
/// Type to represent tiff values of type `RATIONAL`
|
||||
#[derive(Clone)]
|
||||
@@ -60,9 +60,8 @@ impl TiffValue for [u16] {
|
||||
|
||||
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||
// We write using nativeedian so this sould be safe
|
||||
let slice = unsafe {
|
||||
std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()*2)
|
||||
};
|
||||
let slice =
|
||||
unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 2) };
|
||||
writer.write_bytes(slice)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -78,9 +77,8 @@ impl TiffValue for [u32] {
|
||||
|
||||
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||
// We write using nativeedian so this sould be safe
|
||||
let slice = unsafe {
|
||||
std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()*4)
|
||||
};
|
||||
let slice =
|
||||
unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * 4) };
|
||||
writer.write_bytes(slice)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -172,8 +170,7 @@ impl TiffValue for str {
|
||||
writer.write_bytes(self.as_bytes())?;
|
||||
writer.write_u8(0)?;
|
||||
Ok(())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Err(TiffError::FormatError(TiffFormatError::InvalidTag))
|
||||
}
|
||||
}
|
||||
@@ -219,7 +216,7 @@ impl<W: Write + Seek> TiffEncoder<W> {
|
||||
let mut encoder = TiffEncoder {
|
||||
writer: TiffWriter::new(writer),
|
||||
};
|
||||
|
||||
|
||||
NativeEndian::write_header(&mut encoder.writer)?;
|
||||
|
||||
Ok(encoder)
|
||||
@@ -231,20 +228,32 @@ impl<W: Write + Seek> TiffEncoder<W> {
|
||||
}
|
||||
|
||||
/// 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)?;
|
||||
ImageEncoder::new(encoder, width, height)
|
||||
}
|
||||
|
||||
/// 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 mut image: ImageEncoder<W, C> = ImageEncoder::new(encoder, width, height).unwrap();
|
||||
|
||||
let mut idx = 0;
|
||||
while image.next_strip_sample_count() > 0 {
|
||||
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;
|
||||
}
|
||||
image.finish()
|
||||
@@ -285,7 +294,8 @@ impl<'a, W: Write + Seek> DirectoryEncoder<'a, W> {
|
||||
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> {
|
||||
@@ -297,15 +307,14 @@ impl<'a, W: Write + Seek> DirectoryEncoder<'a, W> {
|
||||
*bytes = vec![0, 0, 0, 0];
|
||||
let mut writer = TiffWriter::new(bytes as &mut [u8]);
|
||||
writer.write_u32(offset as u32)?;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while bytes.len() < 4 {
|
||||
bytes.push(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let offset = self.writer.offset();
|
||||
let offset = self.writer.offset();
|
||||
|
||||
self.writer.write_u16(self.ifd.len() as u16)?;
|
||||
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.
|
||||
///
|
||||
/// 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> {
|
||||
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_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::SamplesPerPixel, <T>::BITS_PER_SAMPLE.len() as u16);
|
||||
encoder.write_tag(Tag::XResolution, Rational {n: 1, d: 1});
|
||||
encoder.write_tag(Tag::YResolution, 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::ResolutionUnit, 1u16);
|
||||
|
||||
|
||||
Ok(ImageEncoder {
|
||||
encoder,
|
||||
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.
|
||||
pub fn next_strip_sample_count(&self) -> u64 {
|
||||
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 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
|
||||
}
|
||||
|
||||
/// 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
|
||||
let samples = self.next_strip_sample_count();
|
||||
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<()> {
|
||||
self.encoder.write_tag(Tag::StripOffsets, &*self.strip_offsets);
|
||||
self.encoder.write_tag(Tag::StripByteCounts, &*self.strip_byte_count);
|
||||
self.encoder
|
||||
.write_tag(Tag::StripOffsets, &*self.strip_offsets);
|
||||
self.encoder
|
||||
.write_tag(Tag::StripByteCounts, &*self.strip_byte_count);
|
||||
self.dropped = true;
|
||||
|
||||
self.encoder.finish_internal()
|
||||
@@ -504,4 +524,3 @@ impl<'a, W: Write + Seek, C: ColorType> Drop for ImageEncoder<'a, W, C> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::io::{self, Write, Seek, SeekFrom};
|
||||
use byteorder::{ByteOrder, WriteBytesExt, BigEndian, LittleEndian, NativeEndian};
|
||||
use crate::error::TiffResult;
|
||||
use byteorder::{BigEndian, ByteOrder, LittleEndian, NativeEndian, WriteBytesExt};
|
||||
use std::io::{self, Seek, SeekFrom, Write};
|
||||
|
||||
pub trait TiffByteOrder: ByteOrder {
|
||||
fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
|
||||
@@ -33,10 +33,7 @@ pub struct TiffWriter<W> {
|
||||
|
||||
impl<W: Write> TiffWriter<W> {
|
||||
pub fn new(writer: W) -> Self {
|
||||
Self {
|
||||
writer,
|
||||
offset: 0,
|
||||
}
|
||||
Self { writer, offset: 0 }
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> u64 {
|
||||
@@ -82,7 +79,7 @@ impl<W: Write> TiffWriter<W> {
|
||||
let padd_len = 4 - (self.offset % 4);
|
||||
self.writer.write_all(&padding[..padd_len as usize])?;
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+45
-18
@@ -4,7 +4,7 @@ use std::io;
|
||||
use std::string;
|
||||
|
||||
use decoder::ifd::{Tag, Value};
|
||||
use decoder::{PhotometricInterpretation, CompressionMethod, PlanarConfiguration};
|
||||
use decoder::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration};
|
||||
use ColorType;
|
||||
|
||||
/// Tiff error kinds.
|
||||
@@ -45,8 +45,12 @@ impl fmt::Display for TiffFormatError {
|
||||
InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."),
|
||||
InvalidTag => write!(fmt, "Image contains invalid tag."),
|
||||
RequiredTagNotFound(ref tag) => write!(fmt, "Required tag `{:?}` not found.", tag),
|
||||
UnknownPredictor(ref predictor) => write!(fmt, "Unknown predictor “{}” encountered", predictor),
|
||||
UnsignedIntegerExpected(ref val) => write!(fmt, "Expected unsigned integer, {:?} found.", val),
|
||||
UnknownPredictor(ref predictor) => {
|
||||
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> {
|
||||
use self::TiffUnsupportedError::*;
|
||||
match *self {
|
||||
HorizontalPredictor(color_type) => write!(fmt, "Horizontal predictor for {:?} is unsupported.", color_type),
|
||||
InterpretationWithBits(ref photometric_interpretation, ref bits_per_sample) => {
|
||||
write!(fmt, "{:?} with {:?} bits per sample is unsupported", photometric_interpretation, bits_per_sample)
|
||||
},
|
||||
UnknownInterpretation => write!(fmt, "The image is using an unknown photometric interpretation."),
|
||||
HorizontalPredictor(color_type) => write!(
|
||||
fmt,
|
||||
"Horizontal predictor for {:?} is unsupported.",
|
||||
color_type
|
||||
),
|
||||
InterpretationWithBits(ref photometric_interpretation, ref bits_per_sample) => write!(
|
||||
fmt,
|
||||
"{:?} with {:?} bits per sample is unsupported",
|
||||
photometric_interpretation, bits_per_sample
|
||||
),
|
||||
UnknownInterpretation => write!(
|
||||
fmt,
|
||||
"The image is using an unknown photometric interpretation."
|
||||
),
|
||||
UnknownCompressionMethod => write!(fmt, "Unknown compression method."),
|
||||
UnsupportedCompressionMethod(method) => write!(fmt, "Compression method {:?} is unsupported", method),
|
||||
UnsupportedSampleDepth(samples) => write!(fmt, "{} samples per pixel is supported.", samples),
|
||||
UnsupportedColorType(color_type) => write!(fmt, "Color type {:?} is unsupported", color_type),
|
||||
UnsupportedBitsPerChannel(bits) => write!(fmt, "{} bits per channel not supported", bits),
|
||||
UnsupportedPlanarConfig(config) => write!(fmt, "Unsupported planar configuration “{:?}”.", config),
|
||||
UnsupportedCompressionMethod(method) => {
|
||||
write!(fmt, "Compression method {:?} is unsupported", method)
|
||||
}
|
||||
UnsupportedSampleDepth(samples) => {
|
||||
write!(fmt, "{} samples per pixel is supported.", samples)
|
||||
}
|
||||
UnsupportedColorType(color_type) => {
|
||||
write!(fmt, "Color type {:?} is unsupported", color_type)
|
||||
}
|
||||
UnsupportedBitsPerChannel(bits) => {
|
||||
write!(fmt, "{} bits per channel not supported", bits)
|
||||
}
|
||||
UnsupportedPlanarConfig(config) => {
|
||||
write!(fmt, "Unsupported planar configuration “{:?}”.", config)
|
||||
}
|
||||
UnsupportedDataType => write!(fmt, "Unsupported data type."),
|
||||
}
|
||||
}
|
||||
@@ -89,8 +112,12 @@ 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::UnsupportedError(ref f) => write!(
|
||||
fmt,
|
||||
"The Decoder does not support the \
|
||||
image format `{}`",
|
||||
f
|
||||
),
|
||||
TiffError::IoError(ref e) => e.fmt(fmt),
|
||||
TiffError::LimitsExceeded => write!(fmt, "The Decoder limits are exceeded"),
|
||||
}
|
||||
@@ -98,7 +125,7 @@ impl fmt::Display for TiffError {
|
||||
}
|
||||
|
||||
impl Error for TiffError {
|
||||
fn description (&self) -> &str {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
TiffError::FormatError(..) => "Format 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 {
|
||||
TiffError::IoError(ref e) => Some(e),
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -8,14 +8,15 @@
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate lzw;
|
||||
#[macro_use] extern crate num_derive;
|
||||
#[macro_use]
|
||||
extern crate num_derive;
|
||||
extern crate num_traits;
|
||||
|
||||
pub mod decoder;
|
||||
pub mod encoder;
|
||||
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
|
||||
#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
|
||||
|
||||
+22
-23
@@ -1,14 +1,14 @@
|
||||
extern crate tiff;
|
||||
|
||||
use tiff::decoder::{ifd::Tag, ifd::Value, Decoder, DecodingResult};
|
||||
use tiff::ColorType;
|
||||
use tiff::decoder::{Decoder, DecodingResult, ifd::Tag, ifd::Value};
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
#[test]
|
||||
fn test_gray_u8()
|
||||
{
|
||||
let img_file = File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!");
|
||||
fn test_gray_u8() {
|
||||
let img_file =
|
||||
File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!");
|
||||
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(8));
|
||||
let img_res = decoder.read_image();
|
||||
@@ -16,8 +16,7 @@ fn test_gray_u8()
|
||||
}
|
||||
|
||||
#[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 mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
|
||||
@@ -26,9 +25,9 @@ fn test_rgb_u8()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gray_u16()
|
||||
{
|
||||
let img_file = File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!");
|
||||
fn test_gray_u16() {
|
||||
let img_file =
|
||||
File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!");
|
||||
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(16));
|
||||
let img_res = decoder.read_image();
|
||||
@@ -36,8 +35,7 @@ fn test_gray_u16()
|
||||
}
|
||||
|
||||
#[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 mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(16));
|
||||
@@ -46,8 +44,7 @@ fn test_rgb_u16()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_string_tags()
|
||||
{
|
||||
fn test_string_tags() {
|
||||
// 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
|
||||
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 img_file = File::open(path).expect("can't open file");
|
||||
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 {
|
||||
Value::Ascii(s) => assert_eq!(s, String::from("GraphicsMagick 1.2 unreleased Q16 http://www.GraphicsMagick.org/")),
|
||||
_ => assert!(false)
|
||||
Value::Ascii(s) => assert_eq!(
|
||||
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));
|
||||
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
|
||||
assert_eq!(image_data, img_res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Wrong data type");
|
||||
}
|
||||
}
|
||||
@@ -90,9 +89,9 @@ fn test_decode_data() {
|
||||
//#[test]
|
||||
//fn test_gray_alpha_u8()
|
||||
//{
|
||||
//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");
|
||||
//assert_eq!(decoder.colortype().unwrap(), ColorType::GrayA(8));
|
||||
//let img_res = decoder.read_image();
|
||||
//assert!(img_res.is_ok());
|
||||
//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");
|
||||
//assert_eq!(decoder.colortype().unwrap(), ColorType::GrayA(8));
|
||||
//let img_res = decoder.read_image();
|
||||
//assert!(img_res.is_ok());
|
||||
//}
|
||||
+30
-33
@@ -1,12 +1,12 @@
|
||||
extern crate tiff;
|
||||
extern crate tempfile;
|
||||
extern crate tiff;
|
||||
|
||||
use tiff::ColorType;
|
||||
use tiff::decoder::{Decoder, DecodingResult};
|
||||
use tiff::encoder::{colortype, TiffEncoder};
|
||||
use tiff::ColorType;
|
||||
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::fs::File;
|
||||
use std::io::{Seek, SeekFrom};
|
||||
|
||||
#[test]
|
||||
fn encode_decode() {
|
||||
@@ -23,7 +23,8 @@ fn encode_decode() {
|
||||
{
|
||||
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();
|
||||
@@ -32,18 +33,16 @@ fn encode_decode() {
|
||||
assert_eq!(decoder.dimensions().unwrap(), (100, 100));
|
||||
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
|
||||
assert_eq!(image_data, img_res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Wrong data type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_gray_u8_roundtrip()
|
||||
{
|
||||
let img_file = File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!");
|
||||
fn test_gray_u8_roundtrip() {
|
||||
let img_file =
|
||||
File::open("./tests/images/minisblack-1c-8b.tiff").expect("Cannot find test image!");
|
||||
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
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 tiff = TiffEncoder::new(&mut file).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();
|
||||
{
|
||||
let mut decoder = Decoder::new(&mut file).unwrap();
|
||||
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
|
||||
assert_eq!(image_data, img_res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Wrong data type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
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 tiff = TiffEncoder::new(&mut file).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();
|
||||
{
|
||||
let mut decoder = Decoder::new(&mut file).unwrap();
|
||||
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() {
|
||||
assert_eq!(image_data, img_res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Wrong data type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_gray_u16_roundtrip()
|
||||
{
|
||||
let img_file = File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!");
|
||||
fn test_gray_u16_roundtrip() {
|
||||
let img_file =
|
||||
File::open("./tests/images/minisblack-1c-16b.tiff").expect("Cannot find test image!");
|
||||
let mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
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 tiff = TiffEncoder::new(&mut file).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();
|
||||
{
|
||||
let mut decoder = Decoder::new(&mut file).unwrap();
|
||||
if let DecodingResult::U16(img_res) = decoder.read_image().unwrap() {
|
||||
assert_eq!(image_data, img_res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Wrong data type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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 mut decoder = Decoder::new(img_file).expect("Cannot create decoder");
|
||||
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 tiff = TiffEncoder::new(&mut file).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();
|
||||
{
|
||||
let mut decoder = Decoder::new(&mut file).unwrap();
|
||||
if let DecodingResult::U16(img_res) = decoder.read_image().unwrap() {
|
||||
assert_eq!(image_data, img_res);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
panic!("Wrong data type");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
extern crate tiff;
|
||||
|
||||
use tiff::TiffResult;
|
||||
use tiff::decoder::Decoder;
|
||||
use tiff::TiffResult;
|
||||
|
||||
use std::fs::File;
|
||||
|
||||
|
||||
Reference in new issue
Block a user