diff --git a/src/decoder/ifd.rs b/src/decoder/ifd.rs index ba663d9..672bb87 100644 --- a/src/decoder/ifd.rs +++ b/src/decoder/ifd.rs @@ -7,7 +7,7 @@ use std::mem; use super::stream::{ByteOrder, EndianReader, SmartReader}; use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError}; -use self::Value::{Ascii, List, Rational, Unsigned}; +use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational}; macro_rules! tags { {$( @@ -89,15 +89,20 @@ pub enum Type { SHORT = 3, LONG = 4, RATIONAL = 5, + SBYTE = 6, + SSHORT = 8, + SLONG = 9, + SRATIONAL = 10, } #[allow(unused_qualifications)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Value { - //Signed(i32), + Signed(i32), Unsigned(u32), List(Vec), Rational(u32, u32), + SRational(i32, i32), Ascii(String), } @@ -110,6 +115,16 @@ impl Value { )), } } + + pub fn into_i32(self) -> TiffResult { + match self { + Signed(val) => Ok(val), + val => Err(TiffError::FormatError( + TiffFormatError::SignedIntegerExpected(val), + )), + } + } + pub fn into_u32_vec(self) -> TiffResult> { match self { List(vec) => { @@ -122,6 +137,32 @@ impl Value { Unsigned(val) => Ok(vec![val]), Rational(numerator, denominator) => Ok(vec![numerator, denominator]), Ascii(val) => Ok(val.chars().map(|x| x as u32).collect()), + val => Err(TiffError::FormatError( + TiffFormatError::UnsignedIntegerExpected(val), + )), + } + } + + pub fn into_i32_vec(self) -> TiffResult> { + match self { + List(vec) => { + let mut new_vec = Vec::with_capacity(vec.len()); + for v in vec { + match v { + SRational(numerator, denominator) => { + new_vec.push(numerator); + new_vec.push(denominator); + } + _ => new_vec.push(v.into_i32()?) + } + } + Ok(new_vec) + } + Signed(val) => Ok(vec![val]), + SRational(numerator, denominator) => Ok(vec![numerator, denominator]), + val => Err(TiffError::FormatError( + TiffFormatError::SignedIntegerExpected(val), + )), } } } @@ -166,7 +207,21 @@ impl Entry { // TODO check if this could give wrong results // at a different endianess of file/computer. (Type::BYTE, 1) => Ok(Unsigned(u32::from(self.offset[0]))), + (Type::BYTE, 2) => offset_to_bytes(2, self), + (Type::BYTE, 3) => offset_to_bytes(3, self), + (Type::BYTE, 4) => offset_to_bytes(4, self), + (Type::BYTE, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Unsigned(u32::from(decoder.read_byte()?))) + }), + (Type::SBYTE, 1) => Ok(Signed(i32::from(self.offset[0] as i8))), + (Type::SBYTE, 2) => offset_to_sbytes(2, self), + (Type::SBYTE, 3) => offset_to_sbytes(3, self), + (Type::SBYTE, 4) => offset_to_sbytes(4, self), + (Type::SBYTE, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Signed(i32::from(decoder.read_byte()? as i8))) + }), (Type::SHORT, 1) => Ok(Unsigned(u32::from(self.r(bo).read_u16()?))), + (Type::SSHORT, 1) => Ok(Signed(i32::from(self.r(bo).read_i16()?))), (Type::SHORT, 2) => { let mut r = self.r(bo); Ok(List(vec![ @@ -174,48 +229,51 @@ impl Entry { Unsigned(u32::from(r.read_u16()?)), ])) } - (Type::SHORT, n) => { - if n as usize > limits.decoding_buffer_size / mem::size_of::() { - 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 { - v.push(Unsigned(u32::from(decoder.read_short()?))) - } - Ok(List(v)) + (Type::SSHORT, 2) => { + let mut r = self.r(bo); + Ok(List(vec![ + Signed(i32::from(r.read_i16()?)), + Signed(i32::from(r.read_i16()?)), + ])) } + (Type::SHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Unsigned(u32::from(decoder.read_short()?))) + }), + (Type::SSHORT, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Signed(i32::from(decoder.read_sshort()?))) + }), (Type::LONG, 1) => Ok(Unsigned(try!(self.r(bo).read_u32()))), - (Type::LONG, n) => { - if n as usize > limits.decoding_buffer_size / mem::size_of::() { - 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 { - v.push(Unsigned(try!(decoder.read_long()))) - } - Ok(List(v)) - } + (Type::SLONG, 1) => Ok(Signed(self.r(bo).read_i32()?)), + (Type::LONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Unsigned(decoder.read_long()?)) + }), + (Type::SLONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Signed(decoder.read_slong()?)) + }), (Type::RATIONAL, 1) => { try!(decoder.goto_offset(try!(self.r(bo).read_u32()))); 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 / mem::size_of::() { - 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 { - let numerator = try!(decoder.read_long()); - let denominator = try!(decoder.read_long()); - v.push(Rational(numerator, denominator)) - } - Ok(List(v)) + (Type::SRATIONAL, 1) => { + decoder.goto_offset(self.r(bo).read_u32()?)?; + let numerator = decoder.read_slong()?; + let denominator = decoder.read_slong()?; + Ok(SRational(numerator, denominator)) } + (Type::RATIONAL, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(Rational( + decoder.read_long()?, + decoder.read_long()?, + )) + }), + (Type::SRATIONAL, n) => self.decode_offset(n, bo, limits, decoder, |decoder| { + Ok(SRational( + decoder.read_slong()?, + decoder.read_slong()?, + )) + }), (Type::ASCII, n) => { if n as usize > limits.decoding_buffer_size { return Err(TiffError::LimitsExceeded); @@ -229,6 +287,46 @@ impl Entry { )), } } + + #[inline] + fn decode_offset(&self, value_count: u32, bo: ByteOrder, limits: &super::Limits, decoder: &mut super::Decoder, decode_fn: F) -> TiffResult + where + R: Read + Seek, + F: Fn(&mut super::Decoder) -> TiffResult, + { + if value_count as usize > limits.decoding_buffer_size / mem::size_of::() { + return Err(TiffError::LimitsExceeded); + } + + let mut v = Vec::with_capacity(value_count as usize); + decoder.goto_offset(self.r(bo).read_u32()?)?; + for _ in 0..value_count { + v.push(decode_fn(decoder)?) + } + Ok(List(v)) + } +} + +/// Extracts a list of BYTE tags stored in an offset +#[inline] +fn offset_to_bytes(n: usize, entry: &Entry) -> TiffResult { + Ok(List( + entry.offset[0..n] + .iter() + .map(|&e| Unsigned(u32::from(e))) + .collect() + )) +} + +/// Extracts a list of SBYTE tags stored in an offset +#[inline] +fn offset_to_sbytes(n: usize, entry: &Entry) -> TiffResult { + Ok(List( + entry.offset[0..n] + .iter() + .map(|&e| Signed(i32::from(e as i8))) + .collect() + )) } /// Type representing an Image File Directory diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 21805b7..7a052d7 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -380,18 +380,38 @@ impl Decoder { self.byte_order } + /// Reads a TIFF byte value + #[inline] + pub fn read_byte(&mut self) -> Result { + let mut buf = [0; 1]; + self.reader.read_exact(&mut buf)?; + Ok(buf[0]) + } + /// Reads a TIFF short value #[inline] pub fn read_short(&mut self) -> Result { self.reader.read_u16() } + /// Reads a TIFF sshort value + #[inline] + pub fn read_sshort(&mut self) -> Result { + self.reader.read_i16() + } + /// Reads a TIFF long value #[inline] pub fn read_long(&mut self) -> Result { self.reader.read_u32() } + /// Reads a TIFF slong value + #[inline] + pub fn read_slong(&mut self) -> Result { + self.reader.read_i32() + } + /// Reads a string #[inline] pub fn read_string(&mut self, length: usize) -> TiffResult { diff --git a/src/decoder/stream.rs b/src/decoder/stream.rs index b9285db..4eb5e91 100644 --- a/src/decoder/stream.rs +++ b/src/decoder/stream.rs @@ -39,6 +39,15 @@ pub trait EndianReader: Read { } } + /// Reads an i16 + #[inline(always)] + fn read_i16(&mut self) -> Result { + match self.byte_order() { + ByteOrder::LittleEndian => ::read_i16::(self), + ByteOrder::BigEndian => ::read_i16::(self), + } + } + /// Reads an u32 #[inline(always)] fn read_u32(&mut self) -> Result { @@ -47,6 +56,15 @@ pub trait EndianReader: Read { ByteOrder::BigEndian => ::read_u32::(self), } } + + /// Reads an i32 + #[inline(always)] + fn read_i32(&mut self) -> Result { + match self.byte_order() { + ByteOrder::LittleEndian => ::read_i32::(self), + ByteOrder::BigEndian => ::read_i32::(self), + } + } } /// Reader that decompresses LZW streams diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index ed7ab56..96ba414 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -18,6 +18,12 @@ pub struct Rational { pub d: u32, } +/// Type to represent tiff values of type `SRATIONAL` +pub struct SRational { + pub n: i32, + pub d: i32, +} + /// Type to represent resolution units pub enum ResolutionUnit { None = 1, @@ -50,6 +56,23 @@ impl TiffValue for [u8] { } } +impl TiffValue for [i8] { + const BYTE_LEN: u32 = 1; + const FIELD_TYPE: ifd::Type = ifd::Type::SBYTE; + + fn count(&self) -> u32 { + self.len() as u32 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + // We write using nativeedian so this should be safe + let slice = + unsafe { ::std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) }; + writer.write_bytes(slice)?; + Ok(()) + } +} + impl TiffValue for [u16] { const BYTE_LEN: u32 = 2; const FIELD_TYPE: ifd::Type = ifd::Type::SHORT; @@ -67,6 +90,23 @@ impl TiffValue for [u16] { } } +impl TiffValue for [i16] { + const BYTE_LEN: u32 = 2; + const FIELD_TYPE: ifd::Type = ifd::Type::SSHORT; + + fn count(&self) -> u32 { + self.len() as u32 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + // We write using nativeedian so this should be safe + let slice = + unsafe { ::std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * Self::BYTE_LEN as usize) }; + writer.write_bytes(slice)?; + Ok(()) + } +} + impl TiffValue for [u32] { const BYTE_LEN: u32 = 4; const FIELD_TYPE: ifd::Type = ifd::Type::LONG; @@ -84,6 +124,23 @@ impl TiffValue for [u32] { } } +impl TiffValue for [i32] { + const BYTE_LEN: u32 = 4; + const FIELD_TYPE: ifd::Type = ifd::Type::SLONG; + + fn count(&self) -> u32 { + self.len() as u32 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + // We write using nativeedian so this should be safe + let slice = + unsafe { ::std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len() * Self::BYTE_LEN as usize) }; + writer.write_bytes(slice)?; + Ok(()) + } +} + impl TiffValue for [Rational] { const BYTE_LEN: u32 = 8; const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL; @@ -100,6 +157,22 @@ impl TiffValue for [Rational] { } } +impl TiffValue for [SRational] { + const BYTE_LEN: u32 = 8; + const FIELD_TYPE: ifd::Type = ifd::Type::SRATIONAL; + + fn count(&self) -> u32 { + self.len() as u32 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + for x in self { + x.write(writer)?; + } + Ok(()) + } +} + impl TiffValue for u8 { const BYTE_LEN: u32 = 1; const FIELD_TYPE: ifd::Type = ifd::Type::BYTE; @@ -114,6 +187,20 @@ impl TiffValue for u8 { } } +impl TiffValue for i8 { + const BYTE_LEN: u32 = 1; + const FIELD_TYPE: ifd::Type = ifd::Type::SBYTE; + + fn count(&self) -> u32 { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i8(*self)?; + Ok(()) + } +} + impl TiffValue for u16 { const BYTE_LEN: u32 = 2; const FIELD_TYPE: ifd::Type = ifd::Type::SHORT; @@ -128,6 +215,20 @@ impl TiffValue for u16 { } } +impl TiffValue for i16 { + const BYTE_LEN: u32 = 2; + const FIELD_TYPE: ifd::Type = ifd::Type::SSHORT; + + fn count(&self) -> u32 { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i16(*self)?; + Ok(()) + } +} + impl TiffValue for u32 { const BYTE_LEN: u32 = 4; const FIELD_TYPE: ifd::Type = ifd::Type::LONG; @@ -142,6 +243,20 @@ impl TiffValue for u32 { } } +impl TiffValue for i32 { + const BYTE_LEN: u32 = 4; + const FIELD_TYPE: ifd::Type = ifd::Type::SLONG; + + fn count(&self) -> u32 { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i32(*self)?; + Ok(()) + } +} + impl TiffValue for Rational { const BYTE_LEN: u32 = 8; const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL; @@ -157,6 +272,21 @@ impl TiffValue for Rational { } } +impl TiffValue for SRational { + const BYTE_LEN: u32 = 8; + const FIELD_TYPE: ifd::Type = ifd::Type::SRATIONAL; + + fn count(&self) -> u32 { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i32(self.n)?; + writer.write_i32(self.d)?; + Ok(()) + } +} + impl TiffValue for str { const BYTE_LEN: u32 = 1; const FIELD_TYPE: ifd::Type = ifd::Type::ASCII; diff --git a/src/encoder/writer.rs b/src/encoder/writer.rs index 812093f..78a128d 100644 --- a/src/encoder/writer.rs +++ b/src/encoder/writer.rs @@ -52,6 +52,12 @@ impl TiffWriter { Ok(()) } + pub fn write_i8(&mut self, n: i8) -> Result<(), io::Error> { + self.writer.write_i8(n)?; + self.offset += 1; + Ok(()) + } + pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> { self.writer.write_u16::(n)?; self.offset += 2; @@ -59,6 +65,13 @@ impl TiffWriter { Ok(()) } + pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> { + self.writer.write_i16::(n)?; + self.offset += 2; + + Ok(()) + } + pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> { self.writer.write_u32::(n)?; self.offset += 4; @@ -66,6 +79,13 @@ impl TiffWriter { Ok(()) } + pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> { + self.writer.write_i32::(n)?; + self.offset += 4; + + Ok(()) + } + pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> { self.writer.write_u64::(n)?; self.offset += 8; diff --git a/src/error.rs b/src/error.rs index cc57e62..4e9f127 100644 --- a/src/error.rs +++ b/src/error.rs @@ -33,6 +33,7 @@ pub enum TiffFormatError { RequiredTagNotFound(Tag), UnknownPredictor(u32), UnsignedIntegerExpected(Value), + SignedIntegerExpected(Value), } impl fmt::Display for TiffFormatError { @@ -51,6 +52,9 @@ impl fmt::Display for TiffFormatError { UnsignedIntegerExpected(ref val) => { write!(fmt, "Expected unsigned integer, {:?} found.", val) } + SignedIntegerExpected(ref val) => { + write!(fmt, "Expected signed integer, {:?} found.", val) + } } } } diff --git a/tests/encode_images.rs b/tests/encode_images.rs index 34cc8e1..2ae8c1c 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -2,7 +2,8 @@ extern crate tempfile; extern crate tiff; use tiff::decoder::{Decoder, DecodingResult}; -use tiff::encoder::{colortype, TiffEncoder}; +use tiff::decoder::ifd::Tag; +use tiff::encoder::{colortype, TiffEncoder, SRational}; use tiff::ColorType; use std::fs::File; @@ -175,3 +176,88 @@ fn test_rgb_u16_roundtrip() { } } } + +#[test] +fn test_multiple_byte() { + let mut data = Cursor::new(Vec::new()); + + { + let mut tiff = TiffEncoder::new(&mut data).unwrap(); + let mut image_encoder = tiff.new_image::(1, 1).unwrap(); + let encoder = image_encoder.encoder(); + + encoder.write_tag(Tag::Unknown(65000), &[1_u8][..]); + encoder.write_tag(Tag::Unknown(65001), &[1_u8, 2][..]); + encoder.write_tag(Tag::Unknown(65002), &[1_u8, 2, 3][..]); + encoder.write_tag(Tag::Unknown(65003), &[1_u8, 2, 3, 4][..]); + encoder.write_tag(Tag::Unknown(65004), &[1_u8, 2, 3, 4, 5][..]); + } + + data.set_position(0); + { + let mut decoder = Decoder::new(&mut data).unwrap(); + + assert_eq!(decoder.get_tag(Tag::Unknown(65000)).unwrap().into_u32_vec().unwrap(), [1]); + assert_eq!(decoder.get_tag(Tag::Unknown(65001)).unwrap().into_u32_vec().unwrap(), [1, 2]); + assert_eq!(decoder.get_tag(Tag::Unknown(65002)).unwrap().into_u32_vec().unwrap(), [1, 2, 3]); + assert_eq!(decoder.get_tag(Tag::Unknown(65003)).unwrap().into_u32_vec().unwrap(), [1, 2, 3, 4]); + assert_eq!(decoder.get_tag(Tag::Unknown(65004)).unwrap().into_u32_vec().unwrap(), [1, 2, 3, 4, 5]); + } +} + +#[test] +/// Test writing signed tags from TIFF 6.0 +fn test_signed() { + let mut data = Cursor::new(Vec::new()); + + { + let mut tiff = TiffEncoder::new(&mut data).unwrap(); + let mut image_encoder = tiff.new_image::(1, 1).unwrap(); + let encoder = image_encoder.encoder(); + + //Use the "reusable" tags section as per the TIFF6 spec + encoder.write_tag(Tag::Unknown(65000), -1_i8); + encoder.write_tag(Tag::Unknown(65001), &[-1_i8][..]); + encoder.write_tag(Tag::Unknown(65002), &[-1_i8, 2][..]); + encoder.write_tag(Tag::Unknown(65003), &[-1_i8, 2, -3][..]); + encoder.write_tag(Tag::Unknown(65004), &[-1_i8, 2, -3, 4][..]); + encoder.write_tag(Tag::Unknown(65005), &[-1_i8, 2, -3, 4, -5][..]); + + encoder.write_tag(Tag::Unknown(65010), -1_i16); + encoder.write_tag(Tag::Unknown(65011), -1_i16); + encoder.write_tag(Tag::Unknown(65012), &[-1_i16, 2][..]); + encoder.write_tag(Tag::Unknown(65013), &[-1_i16, 2, -3][..]); + + encoder.write_tag(Tag::Unknown(65020), -1_i32); + encoder.write_tag(Tag::Unknown(65021), &[-1_i32][..]); + encoder.write_tag(Tag::Unknown(65022), &[-1_i32, 2][..]); + + encoder.write_tag(Tag::Unknown(65030), SRational { n: -1, d: 100 }); + encoder.write_tag(Tag::Unknown(65031), &[SRational { n: -1, d: 100 }, SRational { n: 2, d: 100 }][..]); + } + + //Rewind the cursor for reading + data.set_position(0); + { + let mut decoder = Decoder::new(&mut data).unwrap(); + + assert_eq!(decoder.get_tag(Tag::Unknown(65000)).unwrap().into_i32().unwrap(), -1, ); + assert_eq!(decoder.get_tag(Tag::Unknown(65001)).unwrap().into_i32_vec().unwrap(), [-1]); + assert_eq!(decoder.get_tag(Tag::Unknown(65002)).unwrap().into_i32_vec().unwrap(), [-1, 2]); + assert_eq!(decoder.get_tag(Tag::Unknown(65003)).unwrap().into_i32_vec().unwrap(), [-1, 2, -3]); + assert_eq!(decoder.get_tag(Tag::Unknown(65004)).unwrap().into_i32_vec().unwrap(), [-1, 2, -3, 4]); + assert_eq!(decoder.get_tag(Tag::Unknown(65005)).unwrap().into_i32_vec().unwrap(), [-1, 2, -3, 4, -5], ); + + assert_eq!(decoder.get_tag(Tag::Unknown(65010)).unwrap().into_i32().unwrap(), -1); + assert_eq!(decoder.get_tag(Tag::Unknown(65011)).unwrap().into_i32_vec().unwrap(), [-1]); + assert_eq!(decoder.get_tag(Tag::Unknown(65012)).unwrap().into_i32_vec().unwrap(), [-1, 2]); + assert_eq!(decoder.get_tag(Tag::Unknown(65013)).unwrap().into_i32_vec().unwrap(), [-1, 2, -3]); + + assert_eq!(decoder.get_tag(Tag::Unknown(65020)).unwrap().into_i32().unwrap(), -1); + assert_eq!(decoder.get_tag(Tag::Unknown(65021)).unwrap().into_i32_vec().unwrap(), [-1]); + assert_eq!(decoder.get_tag(Tag::Unknown(65022)).unwrap().into_i32_vec().unwrap(), [-1, 2]); + + assert_eq!(decoder.get_tag(Tag::Unknown(65030)).unwrap().into_i32_vec().unwrap(), [-1, 100]); + assert_eq!(decoder.get_tag(Tag::Unknown(65031)).unwrap().into_i32_vec().unwrap(), [-1_i32, 100, 2, 100]); + } +} \ No newline at end of file