Signed value support
Add support for SBYTE, SSHORT, SLONG, SRATIONAL as per the Tiff 6.0 spec Add support for multiple BYTE
This commit is contained in:
1 parent
1c2e57a22a
commit
30eb8487a6
7 files changed
+412
-36
No files matched your search
+133
-35
@@ -7,7 +7,7 @@ use std::mem;
|
|||||||
use super::stream::{ByteOrder, EndianReader, SmartReader};
|
use super::stream::{ByteOrder, EndianReader, SmartReader};
|
||||||
use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
use {TiffError, TiffFormatError, TiffResult, TiffUnsupportedError};
|
||||||
|
|
||||||
use self::Value::{Ascii, List, Rational, Unsigned};
|
use self::Value::{Ascii, List, Rational, Unsigned, Signed, SRational};
|
||||||
|
|
||||||
macro_rules! tags {
|
macro_rules! tags {
|
||||||
{$(
|
{$(
|
||||||
@@ -89,15 +89,20 @@ pub enum Type {
|
|||||||
SHORT = 3,
|
SHORT = 3,
|
||||||
LONG = 4,
|
LONG = 4,
|
||||||
RATIONAL = 5,
|
RATIONAL = 5,
|
||||||
|
SBYTE = 6,
|
||||||
|
SSHORT = 8,
|
||||||
|
SLONG = 9,
|
||||||
|
SRATIONAL = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_qualifications)]
|
#[allow(unused_qualifications)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[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),
|
||||||
|
SRational(i32, i32),
|
||||||
Ascii(String),
|
Ascii(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +115,16 @@ impl Value {
|
|||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_i32(self) -> TiffResult<i32> {
|
||||||
|
match self {
|
||||||
|
Signed(val) => Ok(val),
|
||||||
|
val => Err(TiffError::FormatError(
|
||||||
|
TiffFormatError::SignedIntegerExpected(val),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
|
pub fn into_u32_vec(self) -> TiffResult<Vec<u32>> {
|
||||||
match self {
|
match self {
|
||||||
List(vec) => {
|
List(vec) => {
|
||||||
@@ -122,6 +137,32 @@ impl Value {
|
|||||||
Unsigned(val) => Ok(vec![val]),
|
Unsigned(val) => Ok(vec![val]),
|
||||||
Rational(numerator, denominator) => Ok(vec![numerator, denominator]),
|
Rational(numerator, denominator) => Ok(vec![numerator, denominator]),
|
||||||
Ascii(val) => Ok(val.chars().map(|x| x as u32).collect()),
|
Ascii(val) => Ok(val.chars().map(|x| x as u32).collect()),
|
||||||
|
val => Err(TiffError::FormatError(
|
||||||
|
TiffFormatError::UnsignedIntegerExpected(val),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_i32_vec(self) -> TiffResult<Vec<i32>> {
|
||||||
|
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
|
// TODO check if this could give wrong results
|
||||||
// at a different endianess of file/computer.
|
// at a different endianess of file/computer.
|
||||||
(Type::BYTE, 1) => Ok(Unsigned(u32::from(self.offset[0]))),
|
(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::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) => {
|
(Type::SHORT, 2) => {
|
||||||
let mut r = self.r(bo);
|
let mut r = self.r(bo);
|
||||||
Ok(List(vec![
|
Ok(List(vec![
|
||||||
@@ -174,48 +229,51 @@ impl Entry {
|
|||||||
Unsigned(u32::from(r.read_u16()?)),
|
Unsigned(u32::from(r.read_u16()?)),
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
(Type::SHORT, n) => {
|
(Type::SSHORT, 2) => {
|
||||||
if n as usize > limits.decoding_buffer_size / mem::size_of::<Value>() {
|
let mut r = self.r(bo);
|
||||||
return Err(TiffError::LimitsExceeded);
|
Ok(List(vec![
|
||||||
}
|
Signed(i32::from(r.read_i16()?)),
|
||||||
let mut v = Vec::with_capacity(n as usize);
|
Signed(i32::from(r.read_i16()?)),
|
||||||
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::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, 1) => Ok(Unsigned(try!(self.r(bo).read_u32()))),
|
||||||
(Type::LONG, n) => {
|
(Type::SLONG, 1) => Ok(Signed(self.r(bo).read_i32()?)),
|
||||||
if n as usize > limits.decoding_buffer_size / mem::size_of::<Value>() {
|
(Type::LONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
|
||||||
return Err(TiffError::LimitsExceeded);
|
Ok(Unsigned(decoder.read_long()?))
|
||||||
}
|
}),
|
||||||
let mut v = Vec::with_capacity(n as usize);
|
(Type::SLONG, n) => self.decode_offset(n, bo, limits, decoder, |decoder| {
|
||||||
try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
|
Ok(Signed(decoder.read_slong()?))
|
||||||
for _ in 0..n {
|
}),
|
||||||
v.push(Unsigned(try!(decoder.read_long())))
|
|
||||||
}
|
|
||||||
Ok(List(v))
|
|
||||||
}
|
|
||||||
(Type::RATIONAL, 1) => {
|
(Type::RATIONAL, 1) => {
|
||||||
try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
|
try!(decoder.goto_offset(try!(self.r(bo).read_u32())));
|
||||||
let numerator = try!(decoder.read_long());
|
let numerator = try!(decoder.read_long());
|
||||||
let denominator = try!(decoder.read_long());
|
let denominator = try!(decoder.read_long());
|
||||||
Ok(Rational(numerator, denominator))
|
Ok(Rational(numerator, denominator))
|
||||||
}
|
}
|
||||||
(Type::RATIONAL, n) => {
|
(Type::SRATIONAL, 1) => {
|
||||||
if n as usize > limits.decoding_buffer_size / mem::size_of::<Value>() {
|
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||||
return Err(TiffError::LimitsExceeded);
|
let numerator = decoder.read_slong()?;
|
||||||
}
|
let denominator = decoder.read_slong()?;
|
||||||
let mut v = Vec::with_capacity(n as usize);
|
Ok(SRational(numerator, denominator))
|
||||||
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::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) => {
|
(Type::ASCII, n) => {
|
||||||
if n as usize > limits.decoding_buffer_size {
|
if n as usize > limits.decoding_buffer_size {
|
||||||
return Err(TiffError::LimitsExceeded);
|
return Err(TiffError::LimitsExceeded);
|
||||||
@@ -229,6 +287,46 @@ impl Entry {
|
|||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn decode_offset<R, F>(&self, value_count: u32, bo: ByteOrder, limits: &super::Limits, decoder: &mut super::Decoder<R>, decode_fn: F) -> TiffResult<Value>
|
||||||
|
where
|
||||||
|
R: Read + Seek,
|
||||||
|
F: Fn(&mut super::Decoder<R>) -> TiffResult<Value>,
|
||||||
|
{
|
||||||
|
if value_count as usize > limits.decoding_buffer_size / mem::size_of::<Value>() {
|
||||||
|
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<Value> {
|
||||||
|
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<Value> {
|
||||||
|
Ok(List(
|
||||||
|
entry.offset[0..n]
|
||||||
|
.iter()
|
||||||
|
.map(|&e| Signed(i32::from(e as i8)))
|
||||||
|
.collect()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type representing an Image File Directory
|
/// Type representing an Image File Directory
|
||||||
|
|||||||
@@ -380,18 +380,38 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.byte_order
|
self.byte_order
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a TIFF byte value
|
||||||
|
#[inline]
|
||||||
|
pub fn read_byte(&mut self) -> Result<u8, io::Error> {
|
||||||
|
let mut buf = [0; 1];
|
||||||
|
self.reader.read_exact(&mut buf)?;
|
||||||
|
Ok(buf[0])
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a TIFF short value
|
/// Reads a TIFF short value
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_short(&mut self) -> Result<u16, io::Error> {
|
pub fn read_short(&mut self) -> Result<u16, io::Error> {
|
||||||
self.reader.read_u16()
|
self.reader.read_u16()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a TIFF sshort value
|
||||||
|
#[inline]
|
||||||
|
pub fn read_sshort(&mut self) -> Result<i16, io::Error> {
|
||||||
|
self.reader.read_i16()
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a TIFF long value
|
/// Reads a TIFF long value
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_long(&mut self) -> Result<u32, io::Error> {
|
pub fn read_long(&mut self) -> Result<u32, io::Error> {
|
||||||
self.reader.read_u32()
|
self.reader.read_u32()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a TIFF slong value
|
||||||
|
#[inline]
|
||||||
|
pub fn read_slong(&mut self) -> Result<i32, io::Error> {
|
||||||
|
self.reader.read_i32()
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a string
|
/// Reads a string
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn read_string(&mut self, length: usize) -> TiffResult<String> {
|
pub fn read_string(&mut self, length: usize) -> TiffResult<String> {
|
||||||
|
|||||||
@@ -39,6 +39,15 @@ pub trait EndianReader: Read {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads an i16
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_i16(&mut self) -> Result<i16, io::Error> {
|
||||||
|
match self.byte_order() {
|
||||||
|
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_i16::<LittleEndian>(self),
|
||||||
|
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_i16::<BigEndian>(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads an u32
|
/// Reads an u32
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_u32(&mut self) -> Result<u32, io::Error> {
|
fn read_u32(&mut self) -> Result<u32, io::Error> {
|
||||||
@@ -47,6 +56,15 @@ pub trait EndianReader: Read {
|
|||||||
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u32::<BigEndian>(self),
|
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_u32::<BigEndian>(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads an i32
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_i32(&mut self) -> Result<i32, io::Error> {
|
||||||
|
match self.byte_order() {
|
||||||
|
ByteOrder::LittleEndian => <Self as ReadBytesExt>::read_i32::<LittleEndian>(self),
|
||||||
|
ByteOrder::BigEndian => <Self as ReadBytesExt>::read_i32::<BigEndian>(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reader that decompresses LZW streams
|
/// Reader that decompresses LZW streams
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ pub struct Rational {
|
|||||||
pub d: u32,
|
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
|
/// Type to represent resolution units
|
||||||
pub enum ResolutionUnit {
|
pub enum ResolutionUnit {
|
||||||
None = 1,
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> 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] {
|
impl TiffValue for [u16] {
|
||||||
const BYTE_LEN: u32 = 2;
|
const BYTE_LEN: u32 = 2;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::SHORT;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> 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] {
|
impl TiffValue for [u32] {
|
||||||
const BYTE_LEN: u32 = 4;
|
const BYTE_LEN: u32 = 4;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::LONG;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> 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] {
|
impl TiffValue for [Rational] {
|
||||||
const BYTE_LEN: u32 = 8;
|
const BYTE_LEN: u32 = 8;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
for x in self {
|
||||||
|
x.write(writer)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for u8 {
|
impl TiffValue for u8 {
|
||||||
const BYTE_LEN: u32 = 1;
|
const BYTE_LEN: u32 = 1;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::BYTE;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_i8(*self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for u16 {
|
impl TiffValue for u16 {
|
||||||
const BYTE_LEN: u32 = 2;
|
const BYTE_LEN: u32 = 2;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::SHORT;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_i16(*self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for u32 {
|
impl TiffValue for u32 {
|
||||||
const BYTE_LEN: u32 = 4;
|
const BYTE_LEN: u32 = 4;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::LONG;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_i32(*self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for Rational {
|
impl TiffValue for Rational {
|
||||||
const BYTE_LEN: u32 = 8;
|
const BYTE_LEN: u32 = 8;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::RATIONAL;
|
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<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_i32(self.n)?;
|
||||||
|
writer.write_i32(self.d)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for str {
|
impl TiffValue for str {
|
||||||
const BYTE_LEN: u32 = 1;
|
const BYTE_LEN: u32 = 1;
|
||||||
const FIELD_TYPE: ifd::Type = ifd::Type::ASCII;
|
const FIELD_TYPE: ifd::Type = ifd::Type::ASCII;
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ impl<W: Write> TiffWriter<W> {
|
|||||||
Ok(())
|
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> {
|
pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> {
|
||||||
self.writer.write_u16::<NativeEndian>(n)?;
|
self.writer.write_u16::<NativeEndian>(n)?;
|
||||||
self.offset += 2;
|
self.offset += 2;
|
||||||
@@ -59,6 +65,13 @@ impl<W: Write> TiffWriter<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> {
|
||||||
|
self.writer.write_i16::<NativeEndian>(n)?;
|
||||||
|
self.offset += 2;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> {
|
pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> {
|
||||||
self.writer.write_u32::<NativeEndian>(n)?;
|
self.writer.write_u32::<NativeEndian>(n)?;
|
||||||
self.offset += 4;
|
self.offset += 4;
|
||||||
@@ -66,6 +79,13 @@ impl<W: Write> TiffWriter<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> {
|
||||||
|
self.writer.write_i32::<NativeEndian>(n)?;
|
||||||
|
self.offset += 4;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> {
|
pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> {
|
||||||
self.writer.write_u64::<NativeEndian>(n)?;
|
self.writer.write_u64::<NativeEndian>(n)?;
|
||||||
self.offset += 8;
|
self.offset += 8;
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ pub enum TiffFormatError {
|
|||||||
RequiredTagNotFound(Tag),
|
RequiredTagNotFound(Tag),
|
||||||
UnknownPredictor(u32),
|
UnknownPredictor(u32),
|
||||||
UnsignedIntegerExpected(Value),
|
UnsignedIntegerExpected(Value),
|
||||||
|
SignedIntegerExpected(Value),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TiffFormatError {
|
impl fmt::Display for TiffFormatError {
|
||||||
@@ -51,6 +52,9 @@ impl fmt::Display for TiffFormatError {
|
|||||||
UnsignedIntegerExpected(ref val) => {
|
UnsignedIntegerExpected(ref val) => {
|
||||||
write!(fmt, "Expected unsigned integer, {:?} found.", val)
|
write!(fmt, "Expected unsigned integer, {:?} found.", val)
|
||||||
}
|
}
|
||||||
|
SignedIntegerExpected(ref val) => {
|
||||||
|
write!(fmt, "Expected signed integer, {:?} found.", val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+87
-1
@@ -2,7 +2,8 @@ extern crate tempfile;
|
|||||||
extern crate tiff;
|
extern crate tiff;
|
||||||
|
|
||||||
use tiff::decoder::{Decoder, DecodingResult};
|
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 tiff::ColorType;
|
||||||
|
|
||||||
use std::fs::File;
|
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::<colortype::Gray8>(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::<colortype::Gray8>(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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user