Merge pull request #119 from kalcutter/missing-tags-and-i64
Implement missing tag types and signed 64-bit support
This commit is contained in:
8 files changed
+334
-14
No files matched your search
@@ -29,5 +29,6 @@ integral_slice_as_bytes!(i16, i16_as_ne_bytes, i16_as_ne_mut_bytes);
|
|||||||
integral_slice_as_bytes!(u32, u32_as_ne_bytes, u32_as_ne_mut_bytes);
|
integral_slice_as_bytes!(u32, u32_as_ne_bytes, u32_as_ne_mut_bytes);
|
||||||
integral_slice_as_bytes!(i32, i32_as_ne_bytes, i32_as_ne_mut_bytes);
|
integral_slice_as_bytes!(i32, i32_as_ne_bytes, i32_as_ne_mut_bytes);
|
||||||
integral_slice_as_bytes!(u64, u64_as_ne_bytes, u64_as_ne_mut_bytes);
|
integral_slice_as_bytes!(u64, u64_as_ne_bytes, u64_as_ne_mut_bytes);
|
||||||
|
integral_slice_as_bytes!(i64, i64_as_ne_bytes, i64_as_ne_mut_bytes);
|
||||||
integral_slice_as_bytes!(f32, f32_as_ne_bytes, f32_as_ne_mut_bytes);
|
integral_slice_as_bytes!(f32, f32_as_ne_bytes, f32_as_ne_mut_bytes);
|
||||||
integral_slice_as_bytes!(f64, f64_as_ne_bytes, f64_as_ne_mut_bytes);
|
integral_slice_as_bytes!(f64, f64_as_ne_bytes, f64_as_ne_mut_bytes);
|
||||||
+57
-6
@@ -11,8 +11,8 @@ use crate::tags::{Tag, Type};
|
|||||||
use crate::{TiffError, TiffFormatError, TiffResult};
|
use crate::{TiffError, TiffFormatError, TiffResult};
|
||||||
|
|
||||||
use self::Value::{
|
use self::Value::{
|
||||||
Ascii, Byte, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Short,
|
Ascii, Byte, Double, Float, Ifd, IfdBig, List, Rational, RationalBig, SRational, SRationalBig,
|
||||||
Signed, SignedBig, Unsigned, UnsignedBig,
|
Short, Signed, SignedBig, Unsigned, UnsignedBig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(unused_qualifications)]
|
#[allow(unused_qualifications)]
|
||||||
@@ -32,6 +32,8 @@ pub enum Value {
|
|||||||
SRational(i32, i32),
|
SRational(i32, i32),
|
||||||
SRationalBig(i64, i64),
|
SRationalBig(i64, i64),
|
||||||
Ascii(String),
|
Ascii(String),
|
||||||
|
Ifd(u32),
|
||||||
|
IfdBig(u64),
|
||||||
#[doc(hidden)] // Do not match against this.
|
#[doc(hidden)] // Do not match against this.
|
||||||
__NonExhaustive,
|
__NonExhaustive,
|
||||||
}
|
}
|
||||||
@@ -60,6 +62,8 @@ impl Value {
|
|||||||
Short(val) => Ok(val.into()),
|
Short(val) => Ok(val.into()),
|
||||||
Unsigned(val) => Ok(val),
|
Unsigned(val) => Ok(val),
|
||||||
UnsignedBig(val) => Ok(u32::try_from(val)?),
|
UnsignedBig(val) => Ok(u32::try_from(val)?),
|
||||||
|
Ifd(val) => Ok(val),
|
||||||
|
IfdBig(val) => Ok(u32::try_from(val)?),
|
||||||
val => Err(TiffError::FormatError(
|
val => Err(TiffError::FormatError(
|
||||||
TiffFormatError::UnsignedIntegerExpected(val),
|
TiffFormatError::UnsignedIntegerExpected(val),
|
||||||
)),
|
)),
|
||||||
@@ -81,6 +85,8 @@ impl Value {
|
|||||||
Short(val) => Ok(val.into()),
|
Short(val) => Ok(val.into()),
|
||||||
Unsigned(val) => Ok(val.into()),
|
Unsigned(val) => Ok(val.into()),
|
||||||
UnsignedBig(val) => Ok(val),
|
UnsignedBig(val) => Ok(val),
|
||||||
|
Ifd(val) => Ok(val.into()),
|
||||||
|
IfdBig(val) => Ok(val),
|
||||||
val => Err(TiffError::FormatError(
|
val => Err(TiffError::FormatError(
|
||||||
TiffFormatError::UnsignedIntegerExpected(val),
|
TiffFormatError::UnsignedIntegerExpected(val),
|
||||||
)),
|
)),
|
||||||
@@ -139,6 +145,8 @@ impl Value {
|
|||||||
RationalBig(numerator, denominator) => {
|
RationalBig(numerator, denominator) => {
|
||||||
Ok(vec![u32::try_from(numerator)?, u32::try_from(denominator)?])
|
Ok(vec![u32::try_from(numerator)?, u32::try_from(denominator)?])
|
||||||
}
|
}
|
||||||
|
Ifd(val) => Ok(vec![val]),
|
||||||
|
IfdBig(val) => Ok(vec![u32::try_from(val)?]),
|
||||||
Ascii(val) => Ok(val.chars().map(u32::from).collect()),
|
Ascii(val) => Ok(val.chars().map(u32::from).collect()),
|
||||||
val => Err(TiffError::FormatError(
|
val => Err(TiffError::FormatError(
|
||||||
TiffFormatError::UnsignedIntegerExpected(val),
|
TiffFormatError::UnsignedIntegerExpected(val),
|
||||||
@@ -255,6 +263,8 @@ impl Value {
|
|||||||
UnsignedBig(val) => Ok(vec![val]),
|
UnsignedBig(val) => Ok(vec![val]),
|
||||||
Rational(numerator, denominator) => Ok(vec![numerator.into(), denominator.into()]),
|
Rational(numerator, denominator) => Ok(vec![numerator.into(), denominator.into()]),
|
||||||
RationalBig(numerator, denominator) => Ok(vec![numerator, denominator]),
|
RationalBig(numerator, denominator) => Ok(vec![numerator, denominator]),
|
||||||
|
Ifd(val) => Ok(vec![val.into()]),
|
||||||
|
IfdBig(val) => Ok(vec![val]),
|
||||||
Ascii(val) => Ok(val.chars().map(u32::from).map(u64::from).collect()),
|
Ascii(val) => Ok(val.chars().map(u32::from).map(u64::from).collect()),
|
||||||
val => Err(TiffError::FormatError(
|
val => Err(TiffError::FormatError(
|
||||||
TiffFormatError::UnsignedIntegerExpected(val),
|
TiffFormatError::UnsignedIntegerExpected(val),
|
||||||
@@ -343,8 +353,13 @@ impl Entry {
|
|||||||
* match self.type_ {
|
* match self.type_ {
|
||||||
Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
|
Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
|
||||||
Type::SHORT | Type::SSHORT => 2,
|
Type::SHORT | Type::SSHORT => 2,
|
||||||
Type::LONG | Type::SLONG | Type::FLOAT => 4,
|
Type::LONG | Type::SLONG | Type::FLOAT | Type::IFD => 4,
|
||||||
Type::LONG8 | Type::DOUBLE | Type::RATIONAL | Type::SRATIONAL => 8,
|
Type::LONG8
|
||||||
|
| Type::SLONG8
|
||||||
|
| Type::DOUBLE
|
||||||
|
| Type::RATIONAL
|
||||||
|
| Type::SRATIONAL
|
||||||
|
| Type::IFD8 => 8,
|
||||||
Type::__NonExhaustive => unreachable!(),
|
Type::__NonExhaustive => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -354,6 +369,7 @@ impl Entry {
|
|||||||
if decoder.bigtiff && value_bytes > 4 && value_bytes <= 8 {
|
if decoder.bigtiff && value_bytes > 4 && value_bytes <= 8 {
|
||||||
return Ok(match self.type_ {
|
return Ok(match self.type_ {
|
||||||
Type::LONG8 => UnsignedBig(self.r(bo).read_u64()?),
|
Type::LONG8 => UnsignedBig(self.r(bo).read_u64()?),
|
||||||
|
Type::SLONG8 => SignedBig(self.r(bo).read_i64()?),
|
||||||
Type::DOUBLE => Double(self.r(bo).read_f64()?),
|
Type::DOUBLE => Double(self.r(bo).read_f64()?),
|
||||||
Type::RATIONAL => {
|
Type::RATIONAL => {
|
||||||
let mut r = self.r(bo);
|
let mut r = self.r(bo);
|
||||||
@@ -363,6 +379,7 @@ impl Entry {
|
|||||||
let mut r = self.r(bo);
|
let mut r = self.r(bo);
|
||||||
SRational(r.read_i32()?, r.read_i32()?)
|
SRational(r.read_i32()?, r.read_i32()?)
|
||||||
}
|
}
|
||||||
|
Type::IFD8 => IfdBig(self.r(bo).read_u64()?),
|
||||||
Type::BYTE
|
Type::BYTE
|
||||||
| Type::SBYTE
|
| Type::SBYTE
|
||||||
| Type::ASCII
|
| Type::ASCII
|
||||||
@@ -371,7 +388,8 @@ impl Entry {
|
|||||||
| Type::SSHORT
|
| Type::SSHORT
|
||||||
| Type::LONG
|
| Type::LONG
|
||||||
| Type::SLONG
|
| Type::SLONG
|
||||||
| Type::FLOAT => unreachable!(),
|
| Type::FLOAT
|
||||||
|
| Type::IFD => unreachable!(),
|
||||||
Type::__NonExhaustive => unreachable!(),
|
Type::__NonExhaustive => unreachable!(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -397,6 +415,10 @@ impl Entry {
|
|||||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||||
UnsignedBig(decoder.read_long8()?)
|
UnsignedBig(decoder.read_long8()?)
|
||||||
}
|
}
|
||||||
|
Type::SLONG8 => {
|
||||||
|
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||||
|
SignedBig(decoder.read_slong8()?)
|
||||||
|
}
|
||||||
Type::DOUBLE => {
|
Type::DOUBLE => {
|
||||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||||
Double(decoder.read_double()?)
|
Double(decoder.read_double()?)
|
||||||
@@ -409,6 +431,11 @@ impl Entry {
|
|||||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||||
SRational(decoder.read_slong()?, decoder.read_slong()?)
|
SRational(decoder.read_slong()?, decoder.read_slong()?)
|
||||||
}
|
}
|
||||||
|
Type::IFD => Ifd(self.r(bo).read_u32()?),
|
||||||
|
Type::IFD8 => {
|
||||||
|
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||||
|
IfdBig(decoder.read_long8()?)
|
||||||
|
}
|
||||||
Type::__NonExhaustive => unreachable!(),
|
Type::__NonExhaustive => unreachable!(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -477,7 +504,22 @@ impl Entry {
|
|||||||
}
|
}
|
||||||
return Ok(List(v));
|
return Ok(List(v));
|
||||||
}
|
}
|
||||||
Type::LONG8 | Type::RATIONAL | Type::SRATIONAL | Type::DOUBLE => unreachable!(),
|
Type::IFD => {
|
||||||
|
let mut r = self.r(bo);
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for _ in 0..self.count {
|
||||||
|
v.push(Ifd(r.read_u32()?));
|
||||||
|
}
|
||||||
|
return Ok(List(v));
|
||||||
|
}
|
||||||
|
Type::LONG8
|
||||||
|
| Type::SLONG8
|
||||||
|
| Type::RATIONAL
|
||||||
|
| Type::SRATIONAL
|
||||||
|
| Type::DOUBLE
|
||||||
|
| Type::IFD8 => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
Type::__NonExhaustive => unreachable!(),
|
Type::__NonExhaustive => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,6 +561,15 @@ impl Entry {
|
|||||||
Type::LONG8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
Type::LONG8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
||||||
Ok(UnsignedBig(decoder.read_long8()?))
|
Ok(UnsignedBig(decoder.read_long8()?))
|
||||||
}),
|
}),
|
||||||
|
Type::SLONG8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
||||||
|
Ok(SignedBig(decoder.read_slong8()?))
|
||||||
|
}),
|
||||||
|
Type::IFD => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
||||||
|
Ok(Ifd(decoder.read_long()?))
|
||||||
|
}),
|
||||||
|
Type::IFD8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
||||||
|
Ok(IfdBig(decoder.read_long8()?))
|
||||||
|
}),
|
||||||
Type::UNDEFINED => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
Type::UNDEFINED => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
||||||
Ok(Byte(u8::from(decoder.read_byte()?)))
|
Ok(Byte(u8::from(decoder.read_byte()?)))
|
||||||
}),
|
}),
|
||||||
|
|||||||
+38
-3
@@ -38,6 +38,8 @@ pub enum DecodingResult {
|
|||||||
I16(Vec<i16>),
|
I16(Vec<i16>),
|
||||||
/// A vector of 32 bit signed ints
|
/// A vector of 32 bit signed ints
|
||||||
I32(Vec<i32>),
|
I32(Vec<i32>),
|
||||||
|
/// A vector of 64 bit signed ints
|
||||||
|
I64(Vec<i64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DecodingResult {
|
impl DecodingResult {
|
||||||
@@ -113,6 +115,14 @@ impl DecodingResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_i64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
|
||||||
|
if size > limits.decoding_buffer_size / 8 {
|
||||||
|
Err(TiffError::LimitsExceeded)
|
||||||
|
} else {
|
||||||
|
Ok(DecodingResult::I64(vec![0; size]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer {
|
pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer {
|
||||||
match *self {
|
match *self {
|
||||||
DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]),
|
DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]),
|
||||||
@@ -124,6 +134,7 @@ impl DecodingResult {
|
|||||||
DecodingResult::I8(ref mut buf) => DecodingBuffer::I8(&mut buf[start..]),
|
DecodingResult::I8(ref mut buf) => DecodingBuffer::I8(&mut buf[start..]),
|
||||||
DecodingResult::I16(ref mut buf) => DecodingBuffer::I16(&mut buf[start..]),
|
DecodingResult::I16(ref mut buf) => DecodingBuffer::I16(&mut buf[start..]),
|
||||||
DecodingResult::I32(ref mut buf) => DecodingBuffer::I32(&mut buf[start..]),
|
DecodingResult::I32(ref mut buf) => DecodingBuffer::I32(&mut buf[start..]),
|
||||||
|
DecodingResult::I64(ref mut buf) => DecodingBuffer::I64(&mut buf[start..]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,8 +157,10 @@ pub enum DecodingBuffer<'a> {
|
|||||||
I8(&'a mut [i8]),
|
I8(&'a mut [i8]),
|
||||||
/// A slice of 16 bits signed ints
|
/// A slice of 16 bits signed ints
|
||||||
I16(&'a mut [i16]),
|
I16(&'a mut [i16]),
|
||||||
/// A slice of 16 bits signed ints
|
/// A slice of 32 bits signed ints
|
||||||
I32(&'a mut [i32]),
|
I32(&'a mut [i32]),
|
||||||
|
/// A slice of 64 bits signed ints
|
||||||
|
I64(&'a mut [i64]),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DecodingBuffer<'a> {
|
impl<'a> DecodingBuffer<'a> {
|
||||||
@@ -162,6 +175,7 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
DecodingBuffer::I8(ref buf) => buf.len(),
|
DecodingBuffer::I8(ref buf) => buf.len(),
|
||||||
DecodingBuffer::I16(ref buf) => buf.len(),
|
DecodingBuffer::I16(ref buf) => buf.len(),
|
||||||
DecodingBuffer::I32(ref buf) => buf.len(),
|
DecodingBuffer::I32(ref buf) => buf.len(),
|
||||||
|
DecodingBuffer::I64(ref buf) => buf.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +190,7 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
DecodingBuffer::I8(_) => 1,
|
DecodingBuffer::I8(_) => 1,
|
||||||
DecodingBuffer::I16(_) => 2,
|
DecodingBuffer::I16(_) => 2,
|
||||||
DecodingBuffer::I32(_) => 4,
|
DecodingBuffer::I32(_) => 4,
|
||||||
|
DecodingBuffer::I64(_) => 8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,6 +208,7 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
DecodingBuffer::I8(ref mut buf) => DecodingBuffer::I8(buf),
|
DecodingBuffer::I8(ref mut buf) => DecodingBuffer::I8(buf),
|
||||||
DecodingBuffer::I16(ref mut buf) => DecodingBuffer::I16(buf),
|
DecodingBuffer::I16(ref mut buf) => DecodingBuffer::I16(buf),
|
||||||
DecodingBuffer::I32(ref mut buf) => DecodingBuffer::I32(buf),
|
DecodingBuffer::I32(ref mut buf) => DecodingBuffer::I32(buf),
|
||||||
|
DecodingBuffer::I64(ref mut buf) => DecodingBuffer::I64(buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,6 +339,12 @@ impl Wrapping for i32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Wrapping for i64 {
|
||||||
|
fn wrapping_add(&self, other: Self) -> Self {
|
||||||
|
i64::wrapping_add(*self, other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize) -> TiffResult<()>
|
fn rev_hpredict_nsamp<T>(image: &mut [T], size: (u32, u32), samples: usize) -> TiffResult<()>
|
||||||
where
|
where
|
||||||
T: Copy + Wrapping,
|
T: Copy + Wrapping,
|
||||||
@@ -395,6 +417,9 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType)
|
|||||||
DecodingBuffer::I32(buf) => {
|
DecodingBuffer::I32(buf) => {
|
||||||
rev_hpredict_nsamp(buf, size, samples)?;
|
rev_hpredict_nsamp(buf, size, samples)?;
|
||||||
}
|
}
|
||||||
|
DecodingBuffer::I64(buf) => {
|
||||||
|
rev_hpredict_nsamp(buf, size, samples)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -642,6 +667,11 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.reader.read_u64()
|
self.reader.read_u64()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn read_slong8(&mut self) -> Result<i64, io::Error> {
|
||||||
|
self.reader.read_i64()
|
||||||
|
}
|
||||||
|
|
||||||
/// 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> {
|
||||||
@@ -969,6 +999,10 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
bytes / 8
|
bytes / 8
|
||||||
}
|
}
|
||||||
|
(ColorType::Gray(64), DecodingBuffer::I64(ref mut buffer)) => {
|
||||||
|
reader.read_i64_into(&mut buffer[..bytes / 8])?;
|
||||||
|
bytes / 8
|
||||||
|
}
|
||||||
(ColorType::Gray(32), DecodingBuffer::U32(ref mut buffer)) => {
|
(ColorType::Gray(32), DecodingBuffer::U32(ref mut buffer)) => {
|
||||||
reader.read_u32_into(&mut buffer[..bytes / 4])?;
|
reader.read_u32_into(&mut buffer[..bytes / 4])?;
|
||||||
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||||
@@ -1222,8 +1256,9 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
},
|
},
|
||||||
SampleFormat::Int => match max_sample_bits {
|
SampleFormat::Int => match max_sample_bits {
|
||||||
n if n <= 8 => DecodingResult::new_i8(buffer_size, &self.limits),
|
n if n <= 8 => DecodingResult::new_i8(buffer_size, &self.limits),
|
||||||
n if n == 16 => DecodingResult::new_i16(buffer_size, &self.limits),
|
n if n <= 16 => DecodingResult::new_i16(buffer_size, &self.limits),
|
||||||
n if (n > 16) & (n <= 32) => DecodingResult::new_i32(buffer_size, &self.limits),
|
n if n <= 32 => DecodingResult::new_i32(buffer_size, &self.limits),
|
||||||
|
n if n <= 64 => DecodingResult::new_i64(buffer_size, &self.limits),
|
||||||
n => Err(TiffError::UnsupportedError(
|
n => Err(TiffError::UnsupportedError(
|
||||||
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
||||||
)),
|
)),
|
||||||
|
|||||||
@@ -193,6 +193,35 @@ pub trait EndianReader: Read {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_i64_into(&mut self, buffer: &mut [i64]) -> Result<(), io::Error> {
|
||||||
|
self.read_exact(bytecast::i64_as_ne_mut_bytes(buffer))?;
|
||||||
|
match self.byte_order() {
|
||||||
|
ByteOrder::LittleEndian => {
|
||||||
|
for n in buffer {
|
||||||
|
*n = i64::from_le(*n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ByteOrder::BigEndian => {
|
||||||
|
for n in buffer {
|
||||||
|
*n = i64::from_be(*n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads an i64
|
||||||
|
#[inline(always)]
|
||||||
|
fn read_i64(&mut self) -> Result<i64, io::Error> {
|
||||||
|
let mut n = [0u8; 8];
|
||||||
|
self.read_exact(&mut n)?;
|
||||||
|
Ok(match self.byte_order() {
|
||||||
|
ByteOrder::LittleEndian => i64::from_le_bytes(n),
|
||||||
|
ByteOrder::BigEndian => i64::from_be_bytes(n),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads an f32
|
/// Reads an f32
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn read_f32(&mut self) -> Result<f32, io::Error> {
|
fn read_f32(&mut self) -> Result<f32, io::Error> {
|
||||||
|
|||||||
@@ -13,6 +13,14 @@ mod writer;
|
|||||||
use self::colortype::*;
|
use self::colortype::*;
|
||||||
use self::writer::*;
|
use self::writer::*;
|
||||||
|
|
||||||
|
/// Type to represent tiff values of type `IFD`
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Ifd(pub u32);
|
||||||
|
|
||||||
|
/// Type to represent tiff values of type `IFD8`
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Ifd8(pub u64);
|
||||||
|
|
||||||
/// Type to represent tiff values of type `RATIONAL`
|
/// Type to represent tiff values of type `RATIONAL`
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Rational {
|
pub struct Rational {
|
||||||
@@ -21,6 +29,7 @@ pub struct Rational {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Type to represent tiff values of type `SRATIONAL`
|
/// Type to represent tiff values of type `SRATIONAL`
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SRational {
|
pub struct SRational {
|
||||||
pub n: i32,
|
pub n: i32,
|
||||||
pub d: i32,
|
pub d: i32,
|
||||||
@@ -141,6 +150,21 @@ impl TiffValue for [u64] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TiffValue for [i64] {
|
||||||
|
const BYTE_LEN: u32 = 8;
|
||||||
|
const FIELD_TYPE: Type = Type::SLONG8;
|
||||||
|
|
||||||
|
fn count(&self) -> u32 {
|
||||||
|
self.len() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
let slice = bytecast::i64_as_ne_bytes(self);
|
||||||
|
writer.write_bytes(slice)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for [f32] {
|
impl TiffValue for [f32] {
|
||||||
const BYTE_LEN: u32 = 4;
|
const BYTE_LEN: u32 = 4;
|
||||||
const FIELD_TYPE: Type = Type::FLOAT;
|
const FIELD_TYPE: Type = Type::FLOAT;
|
||||||
@@ -173,6 +197,38 @@ impl TiffValue for [f64] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TiffValue for [Ifd] {
|
||||||
|
const BYTE_LEN: u32 = 4;
|
||||||
|
const FIELD_TYPE: Type = Type::IFD;
|
||||||
|
|
||||||
|
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 [Ifd8] {
|
||||||
|
const BYTE_LEN: u32 = 8;
|
||||||
|
const FIELD_TYPE: Type = Type::IFD8;
|
||||||
|
|
||||||
|
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 [Rational] {
|
impl TiffValue for [Rational] {
|
||||||
const BYTE_LEN: u32 = 8;
|
const BYTE_LEN: u32 = 8;
|
||||||
const FIELD_TYPE: Type = Type::RATIONAL;
|
const FIELD_TYPE: Type = Type::RATIONAL;
|
||||||
@@ -303,6 +359,20 @@ impl TiffValue for u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TiffValue for i64 {
|
||||||
|
const BYTE_LEN: u32 = 8;
|
||||||
|
const FIELD_TYPE: Type = Type::SLONG8;
|
||||||
|
|
||||||
|
fn count(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_i64(*self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for f32 {
|
impl TiffValue for f32 {
|
||||||
const BYTE_LEN: u32 = 4;
|
const BYTE_LEN: u32 = 4;
|
||||||
const FIELD_TYPE: Type = Type::FLOAT;
|
const FIELD_TYPE: Type = Type::FLOAT;
|
||||||
@@ -331,6 +401,34 @@ impl TiffValue for f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TiffValue for Ifd {
|
||||||
|
const BYTE_LEN: u32 = 4;
|
||||||
|
const FIELD_TYPE: Type = Type::IFD;
|
||||||
|
|
||||||
|
fn count(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_u32(self.0)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TiffValue for Ifd8 {
|
||||||
|
const BYTE_LEN: u32 = 8;
|
||||||
|
const FIELD_TYPE: Type = Type::IFD8;
|
||||||
|
|
||||||
|
fn count(&self) -> u32 {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
|
||||||
|
writer.write_u64(self.0)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TiffValue for Rational {
|
impl TiffValue for Rational {
|
||||||
const BYTE_LEN: u32 = 8;
|
const BYTE_LEN: u32 = 8;
|
||||||
const FIELD_TYPE: Type = Type::RATIONAL;
|
const FIELD_TYPE: Type = Type::RATIONAL;
|
||||||
|
|||||||
@@ -81,6 +81,13 @@ impl<W: Write> TiffWriter<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_i64(&mut self, n: i64) -> Result<(), io::Error> {
|
||||||
|
self.writer.write_all(&n.to_ne_bytes())?;
|
||||||
|
self.offset += 8;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_f32(&mut self, n: f32) -> Result<(), io::Error> {
|
pub fn write_f32(&mut self, n: f32) -> Result<(), io::Error> {
|
||||||
self.writer.write_all(&u32::to_ne_bytes(n.to_bits()))?;
|
self.writer.write_all(&u32::to_ne_bytes(n.to_bits()))?;
|
||||||
self.offset += 4;
|
self.offset += 4;
|
||||||
|
|||||||
+18
@@ -134,20 +134,38 @@ pub enum Tag(u16) unknown("A private or extension tag") {
|
|||||||
tags! {
|
tags! {
|
||||||
/// The type of an IFD entry (a 2 byte field).
|
/// The type of an IFD entry (a 2 byte field).
|
||||||
pub enum Type(u16) {
|
pub enum Type(u16) {
|
||||||
|
/// 8-bit unsigned integer
|
||||||
BYTE = 1,
|
BYTE = 1,
|
||||||
|
/// 8-bit byte that contains a 7-bit ASCII code; the last byte must be zero
|
||||||
ASCII = 2,
|
ASCII = 2,
|
||||||
|
/// 16-bit unsigned integer
|
||||||
SHORT = 3,
|
SHORT = 3,
|
||||||
|
/// 32-bit unsigned integer
|
||||||
LONG = 4,
|
LONG = 4,
|
||||||
|
/// Fraction stored as two 32-bit unsigned integers
|
||||||
RATIONAL = 5,
|
RATIONAL = 5,
|
||||||
|
/// 8-bit signed integer
|
||||||
SBYTE = 6,
|
SBYTE = 6,
|
||||||
|
/// 8-bit byte that may contain anything, depending on the field
|
||||||
UNDEFINED = 7,
|
UNDEFINED = 7,
|
||||||
|
/// 16-bit signed integer
|
||||||
SSHORT = 8,
|
SSHORT = 8,
|
||||||
|
/// 32-bit signed integer
|
||||||
SLONG = 9,
|
SLONG = 9,
|
||||||
|
/// Fraction stored as two 32-bit signed integers
|
||||||
SRATIONAL = 10,
|
SRATIONAL = 10,
|
||||||
|
/// 32-bit IEEE floating point
|
||||||
FLOAT = 11,
|
FLOAT = 11,
|
||||||
|
/// 64-bit IEEE floating point
|
||||||
DOUBLE = 12,
|
DOUBLE = 12,
|
||||||
|
/// 32-bit unsigned integer (offset)
|
||||||
|
IFD = 13,
|
||||||
/// BigTIFF 64-bit unsigned integer
|
/// BigTIFF 64-bit unsigned integer
|
||||||
LONG8 = 16,
|
LONG8 = 16,
|
||||||
|
/// BigTIFF 64-bit signed integer
|
||||||
|
SLONG8 = 17,
|
||||||
|
/// BigTIFF 64-bit unsigned integer (offset)
|
||||||
|
IFD8 = 18,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+86
-5
@@ -1,7 +1,7 @@
|
|||||||
extern crate tiff;
|
extern crate tiff;
|
||||||
|
|
||||||
use tiff::decoder::{ifd, Decoder, DecodingResult};
|
use tiff::decoder::{ifd, Decoder, DecodingResult};
|
||||||
use tiff::encoder::{colortype, SRational, TiffEncoder};
|
use tiff::encoder::{colortype, Ifd, Ifd8, SRational, TiffEncoder};
|
||||||
use tiff::tags::Tag;
|
use tiff::tags::Tag;
|
||||||
use tiff::ColorType;
|
use tiff::ColorType;
|
||||||
|
|
||||||
@@ -48,6 +48,53 @@ fn encode_decode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode_ifd() {
|
||||||
|
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), Ifd(42u32)).unwrap();
|
||||||
|
encoder
|
||||||
|
.write_tag(Tag::Unknown(65001), &[Ifd(100u32)][..])
|
||||||
|
.unwrap();
|
||||||
|
encoder
|
||||||
|
.write_tag(Tag::Unknown(65002), &[Ifd(1u32), Ifd(2u32), Ifd(3u32)][..])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
encoder.write_tag(Tag::Unknown(65010), Ifd8(43u64)).unwrap();
|
||||||
|
encoder
|
||||||
|
.write_tag(Tag::Unknown(65011), &[Ifd8(100u64)][..])
|
||||||
|
.unwrap();
|
||||||
|
encoder
|
||||||
|
.write_tag(
|
||||||
|
Tag::Unknown(65012),
|
||||||
|
&[Ifd8(1u64), Ifd8(2u64), Ifd8(3u64)][..],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewind the cursor for reading
|
||||||
|
data.set_position(0);
|
||||||
|
{
|
||||||
|
let mut decoder = Decoder::new(&mut data).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(decoder.assert_tag_u32(65000), 42);
|
||||||
|
assert_eq!(decoder.assert_tag_u32_vec(65000), [42]);
|
||||||
|
assert_eq!(decoder.assert_tag_u32_vec(65001), [100]);
|
||||||
|
assert_eq!(decoder.assert_tag_u32_vec(65002), [1, 2, 3]);
|
||||||
|
|
||||||
|
assert_eq!(decoder.assert_tag_u64(65010), 43);
|
||||||
|
assert_eq!(decoder.assert_tag_u64_vec(65010), [43]);
|
||||||
|
assert_eq!(decoder.assert_tag_u64_vec(65011), [100]);
|
||||||
|
assert_eq!(decoder.assert_tag_u64_vec(65012), [1, 2, 3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// Test that attempting to encode when the input buffer is undersized returns
|
/// Test that attempting to encode when the input buffer is undersized returns
|
||||||
/// an error rather than panicking.
|
/// an error rather than panicking.
|
||||||
@@ -182,6 +229,10 @@ trait AssertDecode {
|
|||||||
fn assert_tag_u32_vec(&mut self, tag: u16) -> Vec<u32>;
|
fn assert_tag_u32_vec(&mut self, tag: u16) -> Vec<u32>;
|
||||||
fn assert_tag_i32(&mut self, tag: u16) -> i32;
|
fn assert_tag_i32(&mut self, tag: u16) -> i32;
|
||||||
fn assert_tag_i32_vec(&mut self, tag: u16) -> Vec<i32>;
|
fn assert_tag_i32_vec(&mut self, tag: u16) -> Vec<i32>;
|
||||||
|
fn assert_tag_u64(&mut self, tag: u16) -> u64;
|
||||||
|
fn assert_tag_u64_vec(&mut self, tag: u16) -> Vec<u64>;
|
||||||
|
fn assert_tag_i64(&mut self, tag: u16) -> i64;
|
||||||
|
fn assert_tag_i64_vec(&mut self, tag: u16) -> Vec<i64>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: std::io::Read + std::io::Seek> AssertDecode for Decoder<R> {
|
impl<R: std::io::Read + std::io::Seek> AssertDecode for Decoder<R> {
|
||||||
@@ -203,6 +254,24 @@ impl<R: std::io::Read + std::io::Seek> AssertDecode for Decoder<R> {
|
|||||||
.into_i32_vec()
|
.into_i32_vec()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
fn assert_tag_u64(&mut self, tag: u16) -> u64 {
|
||||||
|
self.get_tag(Tag::Unknown(tag)).unwrap().into_u64().unwrap()
|
||||||
|
}
|
||||||
|
fn assert_tag_u64_vec(&mut self, tag: u16) -> Vec<u64> {
|
||||||
|
self.get_tag(Tag::Unknown(tag))
|
||||||
|
.unwrap()
|
||||||
|
.into_u64_vec()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
fn assert_tag_i64(&mut self, tag: u16) -> i64 {
|
||||||
|
self.get_tag(Tag::Unknown(tag)).unwrap().into_i64().unwrap()
|
||||||
|
}
|
||||||
|
fn assert_tag_i64_vec(&mut self, tag: u16) -> Vec<i64> {
|
||||||
|
self.get_tag(Tag::Unknown(tag))
|
||||||
|
.unwrap()
|
||||||
|
.into_i64_vec()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -289,12 +358,20 @@ fn test_signed() {
|
|||||||
.write_tag(Tag::Unknown(65022), &[-1_i32, 2][..])
|
.write_tag(Tag::Unknown(65022), &[-1_i32, 2][..])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
encoder.write_tag(Tag::Unknown(65030), -1_i64).unwrap();
|
||||||
encoder
|
encoder
|
||||||
.write_tag(Tag::Unknown(65030), make_srational(-1))
|
.write_tag(Tag::Unknown(65031), &[-1_i64][..])
|
||||||
|
.unwrap();
|
||||||
|
encoder
|
||||||
|
.write_tag(Tag::Unknown(65032), &[-1_i64, 2][..])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
encoder
|
||||||
|
.write_tag(Tag::Unknown(65040), make_srational(-1))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
encoder
|
encoder
|
||||||
.write_tag(
|
.write_tag(
|
||||||
Tag::Unknown(65031),
|
Tag::Unknown(65041),
|
||||||
&[make_srational(-1), make_srational(2)][..],
|
&[make_srational(-1), make_srational(2)][..],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -321,8 +398,12 @@ fn test_signed() {
|
|||||||
assert_eq!(decoder.assert_tag_i32_vec(65021), [-1]);
|
assert_eq!(decoder.assert_tag_i32_vec(65021), [-1]);
|
||||||
assert_eq!(decoder.assert_tag_i32_vec(65022), [-1, 2]);
|
assert_eq!(decoder.assert_tag_i32_vec(65022), [-1, 2]);
|
||||||
|
|
||||||
assert_eq!(decoder.assert_tag_i32_vec(65030), [-1, 100]);
|
assert_eq!(decoder.assert_tag_i64(65030), -1);
|
||||||
assert_eq!(decoder.assert_tag_i32_vec(65031), [-1_i32, 100, 2, 100]);
|
assert_eq!(decoder.assert_tag_i64_vec(65031), [-1]);
|
||||||
|
assert_eq!(decoder.assert_tag_i64_vec(65032), [-1, 2]);
|
||||||
|
|
||||||
|
assert_eq!(decoder.assert_tag_i32_vec(65040), [-1, 100]);
|
||||||
|
assert_eq!(decoder.assert_tag_i32_vec(65041), [-1_i32, 100, 2, 100]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user