Implement missing tag types and signed 64-bit support
This commit is contained in:
1 parent
2cba04dfe7
commit
d086e289dd
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!(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!(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!(f64, f64_as_ne_bytes, f64_as_ne_mut_bytes);
|
||||
+57
-6
@@ -10,8 +10,8 @@ use crate::tags::{Tag, Type};
|
||||
use crate::{TiffError, TiffFormatError, TiffResult};
|
||||
|
||||
use self::Value::{
|
||||
Ascii, Byte, Double, Float, List, Rational, RationalBig, SRational, SRationalBig, Short,
|
||||
Signed, SignedBig, Unsigned, UnsignedBig,
|
||||
Ascii, Byte, Double, Float, Ifd, IfdBig, List, Rational, RationalBig, SRational, SRationalBig,
|
||||
Short, Signed, SignedBig, Unsigned, UnsignedBig,
|
||||
};
|
||||
|
||||
#[allow(unused_qualifications)]
|
||||
@@ -31,6 +31,8 @@ pub enum Value {
|
||||
SRational(i32, i32),
|
||||
SRationalBig(i64, i64),
|
||||
Ascii(String),
|
||||
Ifd(u32),
|
||||
IfdBig(u64),
|
||||
#[doc(hidden)] // Do not match against this.
|
||||
__NonExhaustive,
|
||||
}
|
||||
@@ -59,6 +61,8 @@ impl Value {
|
||||
Short(val) => Ok(val.into()),
|
||||
Unsigned(val) => Ok(val),
|
||||
UnsignedBig(val) => Ok(u32::try_from(val)?),
|
||||
Ifd(val) => Ok(val),
|
||||
IfdBig(val) => Ok(u32::try_from(val)?),
|
||||
val => Err(TiffError::FormatError(
|
||||
TiffFormatError::UnsignedIntegerExpected(val),
|
||||
)),
|
||||
@@ -80,6 +84,8 @@ impl Value {
|
||||
Short(val) => Ok(val.into()),
|
||||
Unsigned(val) => Ok(val.into()),
|
||||
UnsignedBig(val) => Ok(val),
|
||||
Ifd(val) => Ok(val.into()),
|
||||
IfdBig(val) => Ok(val),
|
||||
val => Err(TiffError::FormatError(
|
||||
TiffFormatError::UnsignedIntegerExpected(val),
|
||||
)),
|
||||
@@ -138,6 +144,8 @@ impl Value {
|
||||
RationalBig(numerator, 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()),
|
||||
val => Err(TiffError::FormatError(
|
||||
TiffFormatError::UnsignedIntegerExpected(val),
|
||||
@@ -254,6 +262,8 @@ impl Value {
|
||||
UnsignedBig(val) => Ok(vec![val]),
|
||||
Rational(numerator, denominator) => Ok(vec![numerator.into(), denominator.into()]),
|
||||
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()),
|
||||
val => Err(TiffError::FormatError(
|
||||
TiffFormatError::UnsignedIntegerExpected(val),
|
||||
@@ -342,8 +352,13 @@ impl Entry {
|
||||
* match self.type_ {
|
||||
Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
|
||||
Type::SHORT | Type::SSHORT => 2,
|
||||
Type::LONG | Type::SLONG | Type::FLOAT => 4,
|
||||
Type::LONG8 | Type::DOUBLE | Type::RATIONAL | Type::SRATIONAL => 8,
|
||||
Type::LONG | Type::SLONG | Type::FLOAT | Type::IFD => 4,
|
||||
Type::LONG8
|
||||
| Type::SLONG8
|
||||
| Type::DOUBLE
|
||||
| Type::RATIONAL
|
||||
| Type::SRATIONAL
|
||||
| Type::IFD8 => 8,
|
||||
Type::__NonExhaustive => unreachable!(),
|
||||
};
|
||||
|
||||
@@ -353,6 +368,7 @@ impl Entry {
|
||||
if decoder.bigtiff && value_bytes > 4 && value_bytes <= 8 {
|
||||
return Ok(match self.type_ {
|
||||
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::RATIONAL => {
|
||||
let mut r = self.r(bo);
|
||||
@@ -362,6 +378,7 @@ impl Entry {
|
||||
let mut r = self.r(bo);
|
||||
SRational(r.read_i32()?, r.read_i32()?)
|
||||
}
|
||||
Type::IFD8 => IfdBig(self.r(bo).read_u64()?),
|
||||
Type::BYTE
|
||||
| Type::SBYTE
|
||||
| Type::ASCII
|
||||
@@ -370,7 +387,8 @@ impl Entry {
|
||||
| Type::SSHORT
|
||||
| Type::LONG
|
||||
| Type::SLONG
|
||||
| Type::FLOAT => unreachable!(),
|
||||
| Type::FLOAT
|
||||
| Type::IFD => unreachable!(),
|
||||
Type::__NonExhaustive => unreachable!(),
|
||||
});
|
||||
}
|
||||
@@ -396,6 +414,10 @@ impl Entry {
|
||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||
UnsignedBig(decoder.read_long8()?)
|
||||
}
|
||||
Type::SLONG8 => {
|
||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||
SignedBig(decoder.read_slong8()?)
|
||||
}
|
||||
Type::DOUBLE => {
|
||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||
Double(decoder.read_double()?)
|
||||
@@ -408,6 +430,11 @@ impl Entry {
|
||||
decoder.goto_offset(self.r(bo).read_u32()?)?;
|
||||
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!(),
|
||||
});
|
||||
}
|
||||
@@ -472,7 +499,22 @@ impl Entry {
|
||||
}
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
@@ -514,6 +556,15 @@ impl Entry {
|
||||
Type::LONG8 => self.decode_offset(self.count, bo, limits, decoder, |decoder| {
|
||||
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| {
|
||||
Ok(Byte(u8::from(decoder.read_byte()?)))
|
||||
}),
|
||||
|
||||
+38
-3
@@ -38,6 +38,8 @@ pub enum DecodingResult {
|
||||
I16(Vec<i16>),
|
||||
/// A vector of 32 bit signed ints
|
||||
I32(Vec<i32>),
|
||||
/// A vector of 64 bit signed ints
|
||||
I64(Vec<i64>),
|
||||
}
|
||||
|
||||
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 {
|
||||
match *self {
|
||||
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::I16(ref mut buf) => DecodingBuffer::I16(&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]),
|
||||
/// A slice of 16 bits signed ints
|
||||
I16(&'a mut [i16]),
|
||||
/// A slice of 16 bits signed ints
|
||||
/// A slice of 32 bits signed ints
|
||||
I32(&'a mut [i32]),
|
||||
/// A slice of 64 bits signed ints
|
||||
I64(&'a mut [i64]),
|
||||
}
|
||||
|
||||
impl<'a> DecodingBuffer<'a> {
|
||||
@@ -162,6 +175,7 @@ impl<'a> DecodingBuffer<'a> {
|
||||
DecodingBuffer::I8(ref buf) => buf.len(),
|
||||
DecodingBuffer::I16(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::I16(_) => 2,
|
||||
DecodingBuffer::I32(_) => 4,
|
||||
DecodingBuffer::I64(_) => 8,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +208,7 @@ impl<'a> DecodingBuffer<'a> {
|
||||
DecodingBuffer::I8(ref mut buf) => DecodingBuffer::I8(buf),
|
||||
DecodingBuffer::I16(ref mut buf) => DecodingBuffer::I16(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<()>
|
||||
where
|
||||
T: Copy + Wrapping,
|
||||
@@ -395,6 +417,9 @@ fn rev_hpredict(image: DecodingBuffer, size: (u32, u32), color_type: ColorType)
|
||||
DecodingBuffer::I32(buf) => {
|
||||
rev_hpredict_nsamp(buf, size, samples)?;
|
||||
}
|
||||
DecodingBuffer::I64(buf) => {
|
||||
rev_hpredict_nsamp(buf, size, samples)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -642,6 +667,11 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
self.reader.read_u64()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_slong8(&mut self) -> Result<i64, io::Error> {
|
||||
self.reader.read_i64()
|
||||
}
|
||||
|
||||
/// Reads a string
|
||||
#[inline]
|
||||
pub fn read_string(&mut self, length: usize) -> TiffResult<String> {
|
||||
@@ -969,6 +999,10 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
}
|
||||
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)) => {
|
||||
reader.read_u32_into(&mut buffer[..bytes / 4])?;
|
||||
if self.photometric_interpretation == PhotometricInterpretation::WhiteIsZero {
|
||||
@@ -1222,8 +1256,9 @@ impl<R: Read + Seek> Decoder<R> {
|
||||
},
|
||||
SampleFormat::Int => match max_sample_bits {
|
||||
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) & (n <= 32) => DecodingResult::new_i32(buffer_size, &self.limits),
|
||||
n if n <= 16 => DecodingResult::new_i16(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(
|
||||
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
||||
)),
|
||||
|
||||
@@ -193,6 +193,35 @@ pub trait EndianReader: Read {
|
||||
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
|
||||
#[inline(always)]
|
||||
fn read_f32(&mut self) -> Result<f32, io::Error> {
|
||||
|
||||
@@ -13,6 +13,14 @@ mod writer;
|
||||
use self::colortype::*;
|
||||
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`
|
||||
#[derive(Clone)]
|
||||
pub struct Rational {
|
||||
@@ -21,6 +29,7 @@ pub struct Rational {
|
||||
}
|
||||
|
||||
/// Type to represent tiff values of type `SRATIONAL`
|
||||
#[derive(Clone)]
|
||||
pub struct SRational {
|
||||
pub n: 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] {
|
||||
const BYTE_LEN: u32 = 4;
|
||||
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] {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
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 {
|
||||
const BYTE_LEN: u32 = 4;
|
||||
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 {
|
||||
const BYTE_LEN: u32 = 8;
|
||||
const FIELD_TYPE: Type = Type::RATIONAL;
|
||||
|
||||
@@ -81,6 +81,13 @@ impl<W: Write> TiffWriter<W> {
|
||||
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> {
|
||||
self.writer.write_all(&u32::to_ne_bytes(n.to_bits()))?;
|
||||
self.offset += 4;
|
||||
|
||||
+18
@@ -134,20 +134,38 @@ pub enum Tag(u16) unknown("A private or extension tag") {
|
||||
tags! {
|
||||
/// The type of an IFD entry (a 2 byte field).
|
||||
pub enum Type(u16) {
|
||||
/// 8-bit unsigned integer
|
||||
BYTE = 1,
|
||||
/// 8-bit byte that contains a 7-bit ASCII code; the last byte must be zero
|
||||
ASCII = 2,
|
||||
/// 16-bit unsigned integer
|
||||
SHORT = 3,
|
||||
/// 32-bit unsigned integer
|
||||
LONG = 4,
|
||||
/// Fraction stored as two 32-bit unsigned integers
|
||||
RATIONAL = 5,
|
||||
/// 8-bit signed integer
|
||||
SBYTE = 6,
|
||||
/// 8-bit byte that may contain anything, depending on the field
|
||||
UNDEFINED = 7,
|
||||
/// 16-bit signed integer
|
||||
SSHORT = 8,
|
||||
/// 32-bit signed integer
|
||||
SLONG = 9,
|
||||
/// Fraction stored as two 32-bit signed integers
|
||||
SRATIONAL = 10,
|
||||
/// 32-bit IEEE floating point
|
||||
FLOAT = 11,
|
||||
/// 64-bit IEEE floating point
|
||||
DOUBLE = 12,
|
||||
/// 32-bit unsigned integer (offset)
|
||||
IFD = 13,
|
||||
/// BigTIFF 64-bit unsigned integer
|
||||
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;
|
||||
|
||||
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::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 that attempting to encode when the input buffer is undersized returns
|
||||
/// 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_i32(&mut self, tag: u16) -> 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> {
|
||||
@@ -203,6 +254,24 @@ impl<R: std::io::Read + std::io::Seek> AssertDecode for Decoder<R> {
|
||||
.into_i32_vec()
|
||||
.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]
|
||||
@@ -289,12 +358,20 @@ fn test_signed() {
|
||||
.write_tag(Tag::Unknown(65022), &[-1_i32, 2][..])
|
||||
.unwrap();
|
||||
|
||||
encoder.write_tag(Tag::Unknown(65030), -1_i64).unwrap();
|
||||
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();
|
||||
encoder
|
||||
.write_tag(
|
||||
Tag::Unknown(65031),
|
||||
Tag::Unknown(65041),
|
||||
&[make_srational(-1), make_srational(2)][..],
|
||||
)
|
||||
.unwrap();
|
||||
@@ -321,8 +398,12 @@ fn test_signed() {
|
||||
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(65030), [-1, 100]);
|
||||
assert_eq!(decoder.assert_tag_i32_vec(65031), [-1_i32, 100, 2, 100]);
|
||||
assert_eq!(decoder.assert_tag_i64(65030), -1);
|
||||
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