Merge branch 'master' into 16bit-performance
This commit is contained in:
5 files changed
+146
-71
No files matched your search
+21
-17
@@ -4,9 +4,9 @@ use std::io::{self, Read, Seek};
|
|||||||
use std::collections::{HashMap};
|
use std::collections::{HashMap};
|
||||||
|
|
||||||
use super::stream::{ByteOrder, SmartReader, EndianReader};
|
use super::stream::{ByteOrder, SmartReader, EndianReader};
|
||||||
use ::{TiffError, TiffResult};
|
use ::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult};
|
||||||
|
|
||||||
use self::Value::{Unsigned, List, Rational};
|
use self::Value::{Unsigned, List, Rational, Ascii};
|
||||||
|
|
||||||
macro_rules! tags {
|
macro_rules! tags {
|
||||||
{$(
|
{$(
|
||||||
@@ -33,7 +33,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; // TODO add support
|
Artist 315;
|
||||||
// grayscale images PhotometricInterpretation 1 or 3
|
// grayscale images PhotometricInterpretation 1 or 3
|
||||||
BitsPerSample 258;
|
BitsPerSample 258;
|
||||||
CellLength 265; // TODO add support
|
CellLength 265; // TODO add support
|
||||||
@@ -41,22 +41,22 @@ tags!{
|
|||||||
// palette-color images (PhotometricInterpretation 3)
|
// palette-color images (PhotometricInterpretation 3)
|
||||||
ColorMap 320; // TODO add support
|
ColorMap 320; // TODO add support
|
||||||
Compression 259; // TODO add support for 2 and 32773
|
Compression 259; // TODO add support for 2 and 32773
|
||||||
Copyright 33_432; // TODO add support
|
Copyright 33_432;
|
||||||
DateTime 306; // TODO add support
|
DateTime 306;
|
||||||
ExtraSamples 338; // TODO add support
|
ExtraSamples 338; // TODO add support
|
||||||
FillOrder 266; // TODO add support
|
FillOrder 266; // TODO add support
|
||||||
FreeByteCounts 289; // TODO add support
|
FreeByteCounts 289; // TODO add support
|
||||||
FreeOffsets 288; // TODO add support
|
FreeOffsets 288; // TODO add support
|
||||||
GrayResponseCurve 291; // TODO add support
|
GrayResponseCurve 291; // TODO add support
|
||||||
GrayResponseUnit 290; // TODO add support
|
GrayResponseUnit 290; // TODO add support
|
||||||
HostComputer 316; // TODO add support
|
HostComputer 316;
|
||||||
ImageDescription 270; // TODO add support
|
ImageDescription 270;
|
||||||
ImageLength 257;
|
ImageLength 257;
|
||||||
ImageWidth 256;
|
ImageWidth 256;
|
||||||
Make 271; // TODO add support
|
Make 271;
|
||||||
MaxSampleValue 281; // TODO add support
|
MaxSampleValue 281; // TODO add support
|
||||||
MinSampleValue 280; // TODO add support
|
MinSampleValue 280; // TODO add support
|
||||||
Model 272; // TODO add support
|
Model 272;
|
||||||
NewSubfileType 254; // TODO add support
|
NewSubfileType 254; // TODO add support
|
||||||
Orientation 274; // TODO add support
|
Orientation 274; // TODO add support
|
||||||
PhotometricInterpretation 262;
|
PhotometricInterpretation 262;
|
||||||
@@ -86,21 +86,20 @@ pub enum Type {
|
|||||||
|
|
||||||
|
|
||||||
#[allow(unused_qualifications)]
|
#[allow(unused_qualifications)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
//Signed(i32),
|
//Signed(i32),
|
||||||
Unsigned(u32),
|
Unsigned(u32),
|
||||||
List(Vec<Value>),
|
List(Vec<Value>),
|
||||||
Rational(u32, u32)
|
Rational(u32, u32),
|
||||||
|
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(format!(
|
val => Err(TiffError::FormatError(TiffFormatError::UnsignedIntegerExpected(val))),
|
||||||
"Expected unsigned integer, {:?} found.", val
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
|
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
|
||||||
@@ -113,8 +112,8 @@ impl Value {
|
|||||||
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]),
|
||||||
//_ => Err(::image::FormatError("Tag data malformed.".to_string()))
|
Ascii(val) => Ok(val.chars().map(|x| x as u32).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +195,12 @@ impl Entry {
|
|||||||
}
|
}
|
||||||
Ok(List(v))
|
Ok(List(v))
|
||||||
},
|
},
|
||||||
_ => Err(TiffError::UnsupportedError("Unsupported data type.".to_string()))
|
(Type::ASCII, n) => {
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-50
@@ -2,8 +2,9 @@ use std::io::{self, Read, Seek};
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use num_traits::{FromPrimitive, Num};
|
use num_traits::{FromPrimitive, Num};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
use ::{ColorType, TiffError, TiffResult};
|
use ::{ColorType, TiffError, TiffFormatError, TiffUnsupportedError, TiffResult};
|
||||||
|
|
||||||
use self::ifd::Directory;
|
use self::ifd::Directory;
|
||||||
|
|
||||||
@@ -35,8 +36,8 @@ enum DecodingBuffer<'a> {
|
|||||||
U16(&'a mut [u16])
|
U16(&'a mut [u16])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, FromPrimitive)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||||
enum PhotometricInterpretation {
|
pub enum PhotometricInterpretation {
|
||||||
WhiteIsZero = 0,
|
WhiteIsZero = 0,
|
||||||
BlackIsZero = 1,
|
BlackIsZero = 1,
|
||||||
RGB = 2,
|
RGB = 2,
|
||||||
@@ -47,8 +48,8 @@ enum PhotometricInterpretation {
|
|||||||
CIELab = 8,
|
CIELab = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, FromPrimitive)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||||
enum CompressionMethod {
|
pub enum CompressionMethod {
|
||||||
None = 1,
|
None = 1,
|
||||||
Huffman = 2,
|
Huffman = 2,
|
||||||
Fax3 = 3,
|
Fax3 = 3,
|
||||||
@@ -58,13 +59,13 @@ enum CompressionMethod {
|
|||||||
PackBits = 0x8005
|
PackBits = 0x8005
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, FromPrimitive)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||||
enum PlanarConfiguration {
|
pub enum PlanarConfiguration {
|
||||||
Chunky = 1,
|
Chunky = 1,
|
||||||
Planar = 2
|
Planar = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, FromPrimitive)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, FromPrimitive)]
|
||||||
enum Predictor {
|
enum Predictor {
|
||||||
None = 1,
|
None = 1,
|
||||||
Horizontal = 2
|
Horizontal = 2
|
||||||
@@ -125,9 +126,7 @@ fn rev_hpredict(image: DecodingResult, 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(format!(
|
_ => return Err(TiffError::UnsupportedError(TiffUnsupportedError::HorizontalPredictor(color_type)))
|
||||||
"Horizontal predictor for {:?} is unsupported.", color_type
|
|
||||||
)))
|
|
||||||
};
|
};
|
||||||
Ok(match image {
|
Ok(match image {
|
||||||
DecodingResult::U8(buf) => {
|
DecodingResult::U8(buf) => {
|
||||||
@@ -171,9 +170,8 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero
|
PhotometricInterpretation::BlackIsZero | PhotometricInterpretation::WhiteIsZero
|
||||||
if self.bits_per_sample.len() == 1 => Ok(ColorType::Gray(self.bits_per_sample[0])),
|
if self.bits_per_sample.len() == 1 => Ok(ColorType::Gray(self.bits_per_sample[0])),
|
||||||
|
|
||||||
_ => Err(TiffError::UnsupportedError(format!(
|
// TODO: this is bad we should not fail at this point
|
||||||
"{:?} with {:?} bits per sample is unsupported", self.photometric_interpretation, self.bits_per_sample
|
_ => Err(TiffError::UnsupportedError(TiffUnsupportedError::InterpretationWithBits(self.photometric_interpretation, self.bits_per_sample.clone())))
|
||||||
))) // TODO: this is bad we should not fail at this point}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,12 +185,10 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
b"MM" => {
|
b"MM" => {
|
||||||
self.byte_order = ByteOrder::BigEndian;
|
self.byte_order = ByteOrder::BigEndian;
|
||||||
self.reader.byte_order = ByteOrder::BigEndian; },
|
self.reader.byte_order = ByteOrder::BigEndian; },
|
||||||
_ => return Err(TiffError::FormatError(
|
_ => return Err(TiffError::FormatError(TiffFormatError::TiffSignatureNotFound))
|
||||||
"TIFF signature not found.".to_string()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
if try!(self.read_short()) != 42 {
|
if try!(self.read_short()) != 42 {
|
||||||
return Err(TiffError::FormatError("TIFF signature invalid.".to_string()))
|
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,
|
||||||
@@ -218,18 +214,14 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation))
|
try!(self.get_tag_u32(ifd::Tag::PhotometricInterpretation))
|
||||||
) {
|
) {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None => return Err(TiffError::UnsupportedError(
|
None => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnknownInterpretation))
|
||||||
"The image is using an unknown photometric interpretation.".to_string()
|
|
||||||
))
|
|
||||||
};
|
};
|
||||||
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))
|
||||||
"Unknown compression method.".to_string()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(val) = try!(self.find_tag_u32(ifd::Tag::SamplesPerPixel)) {
|
if let Some(val) = try!(self.find_tag_u32(ifd::Tag::SamplesPerPixel)) {
|
||||||
@@ -247,9 +239,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
_ => return Err(TiffError::UnsupportedError(
|
_ => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedSampleDepth(self.samples)))
|
||||||
format!("{} samples per pixel is supported.", self.samples)
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
@@ -279,6 +269,16 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.reader.read_u32()
|
self.reader.read_u32()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a string
|
||||||
|
#[inline]
|
||||||
|
pub fn read_string(&mut self, length: usize) -> Result<String, FromUtf8Error> {
|
||||||
|
let mut out = String::with_capacity(length);
|
||||||
|
self.reader.read_to_string(&mut out);
|
||||||
|
// Strings may be null-terminated, so we trim anything downstream of the null byte
|
||||||
|
let trimmed = out.bytes().take_while(|&n| n != 0).collect::<Vec<u8>>();
|
||||||
|
String::from_utf8(trimmed)
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a TIFF IFA offset/value field
|
/// Reads a TIFF IFA offset/value field
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_offset(&mut self) -> Result<[u8; 4], io::Error> {
|
pub fn read_offset(&mut self) -> Result<[u8; 4], io::Error> {
|
||||||
@@ -323,9 +323,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
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(
|
None => return Err(TiffError::FormatError(TiffFormatError::ImageFileDirectoryNotFound)),
|
||||||
"Image file directory not found.".to_string())
|
|
||||||
),
|
|
||||||
Some(offset) => try!(self.goto_offset(offset))
|
Some(offset) => try!(self.goto_offset(offset))
|
||||||
}
|
}
|
||||||
for _ in 0..try!(self.read_short()) {
|
for _ in 0..try!(self.read_short()) {
|
||||||
@@ -379,9 +377,7 @@ 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(format!(
|
None => Err(TiffError::FormatError(TiffFormatError::RequiredTagNotFound(tag))),
|
||||||
"Required tag `{:?}` not found.", tag
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,9 +410,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let (bytes, reader) = try!(PackBitsReader::new(&mut self.reader, order, length as usize));
|
let (bytes, reader) = try!(PackBitsReader::new(&mut self.reader, order, length as usize));
|
||||||
(bytes, Box::new(reader))
|
(bytes, Box::new(reader))
|
||||||
},
|
},
|
||||||
method => return Err(TiffError::UnsupportedError(format!(
|
method => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedCompressionMethod(method)))
|
||||||
"Compression method {:?} is unsupported", method
|
|
||||||
)))
|
|
||||||
};
|
};
|
||||||
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)) |
|
||||||
@@ -448,9 +442,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
bytes
|
bytes
|
||||||
}
|
}
|
||||||
(type_, _) => return Err(TiffError::UnsupportedError(format!(
|
(type_, _) => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedColorType(type_))),
|
||||||
"Color type {:?} is unsupported", type_
|
|
||||||
)))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,18 +460,12 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
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::U8(vec![0; buffer_size]),
|
n if n <= 8 => DecodingResult::U8(vec![0; buffer_size]),
|
||||||
n if n <= 16 => DecodingResult::U16(vec![0; buffer_size]),
|
n if n <= 16 => DecodingResult::U16(vec![0; buffer_size]),
|
||||||
n => return Err(
|
n => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedBitsPerChannel(n))),
|
||||||
TiffError::UnsupportedError(
|
|
||||||
format!("{} bits per channel not supported", n)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
if let Ok(config) = self.get_tag_u32(ifd::Tag::PlanarConfiguration) {
|
if let Ok(config) = self.get_tag_u32(ifd::Tag::PlanarConfiguration) {
|
||||||
match FromPrimitive::from_u32(config) {
|
match FromPrimitive::from_u32(config) {
|
||||||
Some(PlanarConfiguration::Chunky) => {},
|
Some(PlanarConfiguration::Chunky) => {},
|
||||||
config => return Err(TiffError::UnsupportedError(
|
config => return Err(TiffError::UnsupportedError(TiffUnsupportedError::UnsupportedPlanarConfig(config)))
|
||||||
format!("Unsupported planar configuration “{:?}”.", config)
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut units_read = 0;
|
let mut units_read = 0;
|
||||||
@@ -519,9 +505,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
try!(self.colortype())
|
try!(self.colortype())
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
None => return Err(TiffError::FormatError(
|
None => return Err(TiffError::FormatError(TiffFormatError::UnknownPredictor(predictor))),
|
||||||
format!("Unknown predictor “{}” encountered", predictor)
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
|||||||
+71
-2
@@ -1,20 +1,83 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::string;
|
||||||
|
|
||||||
|
use decoder::ifd::{Tag, Value};
|
||||||
|
use decoder::{PhotometricInterpretation, CompressionMethod, PlanarConfiguration};
|
||||||
|
use ColorType;
|
||||||
|
|
||||||
/// Tiff error kinds.
|
/// Tiff error kinds.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TiffError {
|
pub enum TiffError {
|
||||||
/// The Image is not formatted properly
|
/// The Image is not formatted properly
|
||||||
FormatError(String),
|
FormatError(TiffFormatError),
|
||||||
|
|
||||||
/// The Decoder does not support this image format
|
/// The Decoder does not support this image format
|
||||||
UnsupportedError(String),
|
UnsupportedError(TiffUnsupportedError),
|
||||||
|
|
||||||
/// An I/O Error occurred while decoding the image
|
/// An I/O Error occurred while decoding the image
|
||||||
IoError(io::Error),
|
IoError(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TiffFormatError {
|
||||||
|
TiffSignatureNotFound,
|
||||||
|
TiffSignatureInvalid,
|
||||||
|
ImageFileDirectoryNotFound,
|
||||||
|
RequiredTagNotFound(Tag),
|
||||||
|
UnknownPredictor(u32),
|
||||||
|
UnsignedIntegerExpected(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TiffFormatError {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
use self::TiffFormatError::*;
|
||||||
|
match *self {
|
||||||
|
TiffSignatureNotFound => write!(fmt, "TIFF signature not found."),
|
||||||
|
TiffSignatureInvalid => write!(fmt, "TIFF signature invalid."),
|
||||||
|
ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."),
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TiffUnsupportedError {
|
||||||
|
HorizontalPredictor(ColorType),
|
||||||
|
InterpretationWithBits(PhotometricInterpretation, Vec<u8>),
|
||||||
|
UnknownInterpretation,
|
||||||
|
UnknownCompressionMethod,
|
||||||
|
UnsupportedCompressionMethod(CompressionMethod),
|
||||||
|
UnsupportedSampleDepth(u8),
|
||||||
|
UnsupportedColorType(ColorType),
|
||||||
|
UnsupportedBitsPerChannel(u8),
|
||||||
|
UnsupportedPlanarConfig(Option<PlanarConfiguration>),
|
||||||
|
UnsupportedDataType,
|
||||||
|
}
|
||||||
|
|
||||||
|
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."),
|
||||||
|
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),
|
||||||
|
UnsupportedDataType => write!(fmt, "Unsupported data type."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for TiffError {
|
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 {
|
||||||
@@ -49,5 +112,11 @@ impl From<io::Error> for TiffError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<string::FromUtf8Error> for TiffError {
|
||||||
|
fn from(err: string::FromUtf8Error) -> TiffError {
|
||||||
|
TiffError::FormatError(String::from("Image contains invalid tag."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Result of an image decoding/encoding process
|
/// Result of an image decoding/encoding process
|
||||||
pub type TiffResult<T> = Result<T, TiffError>;
|
pub type TiffResult<T> = Result<T, TiffError>;
|
||||||
+1
-1
@@ -14,7 +14,7 @@ extern crate num_traits;
|
|||||||
pub mod decoder;
|
pub mod decoder;
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
pub use self::error::{TiffError, TiffResult};
|
pub use self::error::{TiffError, TiffFormatError, TiffUnsupportedError, TiffResult};
|
||||||
|
|
||||||
/// 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)]
|
||||||
|
|||||||
+19
-1
@@ -1,7 +1,7 @@
|
|||||||
extern crate tiff;
|
extern crate tiff;
|
||||||
|
|
||||||
use tiff::ColorType;
|
use tiff::ColorType;
|
||||||
use tiff::decoder::{Decoder, DecodingResult};
|
use tiff::decoder::{Decoder, DecodingResult, ifd::Tag, ifd::Value};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
@@ -45,6 +45,24 @@ fn test_rgb_u16()
|
|||||||
assert!(img_res.is_ok());
|
assert!(img_res.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
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"];
|
||||||
|
for filename in filenames.iter() {
|
||||||
|
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();
|
||||||
|
match software {
|
||||||
|
Value::Ascii(s) => assert_eq!(s, String::from("GraphicsMagick 1.2 unreleased Q16 http://www.GraphicsMagick.org/")),
|
||||||
|
_ => assert!(false)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: GrayA support
|
// TODO: GrayA support
|
||||||
//#[test]
|
//#[test]
|
||||||
//fn test_gray_alpha_u8()
|
//fn test_gray_alpha_u8()
|
||||||
|
|||||||
Reference in new issue
Block a user