diff --git a/src/encoder/mod.rs b/src/encoder/mod.rs index 71aba00..2881d46 100644 --- a/src/encoder/mod.rs +++ b/src/encoder/mod.rs @@ -1,500 +1,31 @@ -use std::collections::BTreeMap; -use std::convert::TryFrom; -use std::io::{Seek, Write}; -use std::{cmp, io, mem}; +pub use tiff_value::*; -use crate::bytecast; -use crate::error::{TiffError, TiffFormatError, TiffResult}; -use crate::tags::{self, ResolutionUnit, Tag, Type}; +use std::{ + cmp, + collections::BTreeMap, + convert::{TryFrom, TryInto}, + io::{self, Seek, Write}, + marker::PhantomData, + mem, + num::TryFromIntError, +}; + +use crate::{ + error::TiffResult, + tags::{self, ResolutionUnit, Tag}, +}; pub mod colortype; +mod tiff_value; 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 { - pub n: u32, - pub d: u32, -} - -/// Type to represent tiff values of type `SRATIONAL` -#[derive(Clone)] -pub struct SRational { - pub n: i32, - pub d: i32, -} - -/// Trait for types that can be encoded in a tiff file -pub trait TiffValue { - const BYTE_LEN: u32; - const FIELD_TYPE: Type; - fn count(&self) -> u32; - fn bytes(&self) -> u32 { - self.count() * Self::BYTE_LEN - } - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()>; -} - -impl TiffValue for [u8] { - const BYTE_LEN: u32 = 1; - const FIELD_TYPE: Type = Type::BYTE; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_bytes(self)?; - Ok(()) - } -} - -impl TiffValue for [i8] { - const BYTE_LEN: u32 = 1; - const FIELD_TYPE: Type = Type::SBYTE; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - let slice = bytecast::i8_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -impl TiffValue for [u16] { - const BYTE_LEN: u32 = 2; - const FIELD_TYPE: Type = Type::SHORT; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - let slice = bytecast::u16_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -impl TiffValue for [i16] { - const BYTE_LEN: u32 = 2; - const FIELD_TYPE: Type = Type::SSHORT; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - let slice = bytecast::i16_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -impl TiffValue for [u32] { - const BYTE_LEN: u32 = 4; - const FIELD_TYPE: Type = Type::LONG; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - let slice = bytecast::u32_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -impl TiffValue for [i32] { - const BYTE_LEN: u32 = 4; - const FIELD_TYPE: Type = Type::SLONG; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - let slice = bytecast::i32_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -impl TiffValue for [u64] { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::LONG8; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - let slice = bytecast::u64_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -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(&self, writer: &mut TiffWriter) -> 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; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - // We write using nativeedian so this sould be safe - let slice = bytecast::f32_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -impl TiffValue for [f64] { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::DOUBLE; - - fn count(&self) -> u32 { - self.len() as u32 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - // We write using nativeedian so this sould be safe - let slice = bytecast::f64_as_ne_bytes(self); - writer.write_bytes(slice)?; - Ok(()) - } -} - -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(&self, writer: &mut TiffWriter) -> 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(&self, writer: &mut TiffWriter) -> TiffResult<()> { - for x in self { - x.write(writer)?; - } - Ok(()) - } -} - -impl TiffValue for [Rational] { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::RATIONAL; - - 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 [SRational] { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = 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: Type = Type::BYTE; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_u8(*self)?; - Ok(()) - } -} - -impl TiffValue for i8 { - const BYTE_LEN: u32 = 1; - const FIELD_TYPE: Type = 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: Type = Type::SHORT; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_u16(*self)?; - Ok(()) - } -} - -impl TiffValue for i16 { - const BYTE_LEN: u32 = 2; - const FIELD_TYPE: Type = 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: Type = Type::LONG; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_u32(*self)?; - Ok(()) - } -} - -impl TiffValue for i32 { - const BYTE_LEN: u32 = 4; - const FIELD_TYPE: Type = Type::SLONG; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_i32(*self)?; - Ok(()) - } -} - -impl TiffValue for u64 { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::LONG8; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_u64(*self)?; - Ok(()) - } -} - -impl TiffValue for i64 { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::SLONG8; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_i64(*self)?; - Ok(()) - } -} - -impl TiffValue for f32 { - const BYTE_LEN: u32 = 4; - const FIELD_TYPE: Type = Type::FLOAT; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_f32(*self)?; - Ok(()) - } -} - -impl TiffValue for f64 { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::DOUBLE; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_f64(*self)?; - Ok(()) - } -} - -impl TiffValue for Ifd { - const BYTE_LEN: u32 = 4; - const FIELD_TYPE: Type = Type::IFD; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> 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(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_u64(self.0)?; - Ok(()) - } -} - -impl TiffValue for Rational { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = Type::RATIONAL; - - fn count(&self) -> u32 { - 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - writer.write_u32(self.n)?; - writer.write_u32(self.d)?; - Ok(()) - } -} - -impl TiffValue for SRational { - const BYTE_LEN: u32 = 8; - const FIELD_TYPE: Type = 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: Type = Type::ASCII; - - fn count(&self) -> u32 { - self.len() as u32 + 1 - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - if self.is_ascii() && !self.bytes().any(|b| b == 0) { - writer.write_bytes(self.as_bytes())?; - writer.write_u8(0)?; - Ok(()) - } else { - Err(TiffError::FormatError(TiffFormatError::InvalidTag)) - } - } -} - -impl<'a, T: TiffValue + ?Sized> TiffValue for &'a T { - const BYTE_LEN: u32 = T::BYTE_LEN; - const FIELD_TYPE: Type = T::FIELD_TYPE; - - fn count(&self) -> u32 { - (*self).count() - } - - fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { - (*self).write(writer) - } -} - -/// Tiff encoder. +/// Encoder for Tiff and BigTiff files. /// /// With this type you can get a `DirectoryEncoder` or a `ImageEncoder` -/// to encode tiff ifd directories with images. +/// to encode Tiff/BigTiff ifd directories with images. /// /// See `DirectoryEncoder` and `ImageEncoder`. /// @@ -506,39 +37,68 @@ impl<'a, T: TiffValue + ?Sized> TiffValue for &'a T { /// # let image_data = vec![0; 100*100*3]; /// use tiff::encoder::*; /// +/// // create a standard Tiff file /// let mut tiff = TiffEncoder::new(&mut file).unwrap(); -/// /// tiff.write_image::(100, 100, &image_data).unwrap(); +/// +/// // create a BigTiff file +/// let mut bigtiff = TiffEncoder::new_big(&mut file).unwrap(); +/// bigtiff.write_image::(100, 100, &image_data).unwrap(); +/// /// # } /// ``` -pub struct TiffEncoder { +pub struct TiffEncoder { writer: TiffWriter, + kind: PhantomData, } +/// Constructor functions to create standard Tiff files. impl TiffEncoder { - pub fn new(writer: W) -> TiffResult> { + /// Creates a new encoder for standard Tiff files. + /// + /// To create BigTiff files, use [`new_big`][TiffEncoder::new_big] or + /// [`new_generic`][TiffEncoder::new_generic]. + pub fn new(writer: W) -> TiffResult> { + TiffEncoder::new_generic(writer) + } +} + +/// Constructor functions to create BigTiff files. +impl TiffEncoder { + /// Creates a new encoder for BigTiff files. + /// + /// To create standard Tiff files, use [`new`][TiffEncoder::new] or + /// [`new_generic`][TiffEncoder::new_generic]. + pub fn new_big(writer: W) -> TiffResult { + TiffEncoder::new_generic(writer) + } +} + +/// Generic functions that are available for both Tiff and BigTiff encoders. +impl TiffEncoder { + /// Creates a new Tiff or BigTiff encoder, inferred from the return type. + pub fn new_generic(writer: W) -> TiffResult { let mut encoder = TiffEncoder { writer: TiffWriter::new(writer), + kind: PhantomData, }; - write_tiff_header(&mut encoder.writer)?; - // blank the IFD offset location - encoder.writer.write_u32(0)?; + K::write_header(&mut encoder.writer)?; Ok(encoder) } - /// Create a `DirectoryEncoder` to encode an ifd directory. - pub fn new_directory(&mut self) -> TiffResult> { + /// Create a [`DirectoryEncoder`] to encode an ifd directory. + pub fn new_directory(&mut self) -> TiffResult> { DirectoryEncoder::new(&mut self.writer) } - /// Create an 'ImageEncoder' to encode an image one slice at a time. + /// Create an [`ImageEncoder`] to encode an image one slice at a time. pub fn new_image( &mut self, width: u32, height: u32, - ) -> TiffResult> { + ) -> TiffResult> { let encoder = DirectoryEncoder::new(&mut self.writer)?; ImageEncoder::new(encoder, width, height) } @@ -554,7 +114,7 @@ impl TiffEncoder { [C::Inner]: TiffValue, { let encoder = DirectoryEncoder::new(&mut self.writer)?; - let image: ImageEncoder = ImageEncoder::new(encoder, width, height)?; + let image: ImageEncoder = ImageEncoder::new(encoder, width, height)?; image.write_data(data) } } @@ -563,19 +123,19 @@ impl TiffEncoder { /// /// You should call `finish` on this when you are finished with it. /// Encoding can silently fail while this is dropping. -pub struct DirectoryEncoder<'a, W: 'a + Write + Seek> { +pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> { writer: &'a mut TiffWriter, dropped: bool, // We use BTreeMap to make sure tags are written in correct order ifd_pointer_pos: u64, - ifd: BTreeMap)>, + ifd: BTreeMap>, } -impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { - fn new(writer: &'a mut TiffWriter) -> TiffResult> { +impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> { + fn new(writer: &'a mut TiffWriter) -> TiffResult { // the previous word is the IFD offset position - let ifd_pointer_pos = writer.offset() - mem::size_of::() as u64; - writer.pad_word_boundary()?; + let ifd_pointer_pos = writer.offset() - mem::size_of::() as u64; + writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff? Ok(DirectoryEncoder { writer, dropped: false, @@ -586,8 +146,7 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { /// Write a single ifd tag. pub fn write_tag(&mut self, tag: Tag, value: T) -> TiffResult<()> { - let len = ::BYTE_LEN * value.count(); - let mut bytes = Vec::with_capacity(usize::try_from(len)?); + let mut bytes = Vec::with_capacity(value.bytes()); { let mut writer = TiffWriter::new(&mut bytes); value.write(&mut writer)?; @@ -595,7 +154,11 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { self.ifd.insert( tag.to_u16(), - (::FIELD_TYPE.to_u16(), value.count(), bytes), + DirectoryEntry { + data_type: ::FIELD_TYPE.to_u16(), + count: value.count().try_into()?, + data: bytes, + }, ); Ok(()) @@ -603,15 +166,21 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { fn write_directory(&mut self) -> TiffResult { // Start by writing out all values - for &mut (_, _, ref mut bytes) in self.ifd.values_mut() { - if bytes.len() > 4 { + for &mut DirectoryEntry { + data: ref mut bytes, + .. + } in self.ifd.values_mut() + { + let data_bytes = mem::size_of::(); + + if bytes.len() > data_bytes { let offset = self.writer.offset(); self.writer.write_bytes(bytes)?; - *bytes = vec![0, 0, 0, 0]; + *bytes = vec![0; data_bytes]; let mut writer = TiffWriter::new(bytes as &mut [u8]); - writer.write_u32(u32::try_from(offset)?)?; + K::write_offset(&mut writer, offset)?; } else { - while bytes.len() < 4 { + while bytes.len() < data_bytes { bytes.push(0); } } @@ -619,11 +188,19 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { let offset = self.writer.offset(); - self.writer.write_u16(u16::try_from(self.ifd.len())?)?; - for (tag, &(ref field_type, ref count, ref offset)) in self.ifd.iter() { + K::write_entry_count(&mut self.writer, self.ifd.len())?; + for ( + tag, + &DirectoryEntry { + data_type: ref field_type, + ref count, + data: ref offset, + }, + ) in self.ifd.iter() + { self.writer.write_u16(*tag)?; self.writer.write_u16(*field_type)?; - self.writer.write_u32(*count)?; + (*count).write(&mut self.writer)?; self.writer.write_bytes(offset)?; } @@ -644,9 +221,9 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { let curr_pos = self.writer.offset(); self.writer.goto_offset(self.ifd_pointer_pos)?; - self.writer.write_u32(u32::try_from(ifd_pointer)?)?; + K::write_offset(&mut self.writer, ifd_pointer)?; self.writer.goto_offset(curr_pos)?; - self.writer.write_u32(0)?; + K::write_offset(&mut self.writer, 0)?; self.dropped = true; @@ -659,7 +236,7 @@ impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { } } -impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> { +impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> { fn drop(&mut self) { if !self.dropped { let _ = self.finish_internal(); @@ -700,26 +277,22 @@ impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> { /// # } /// ``` /// You can also call write_data function wich will encode by strip and finish -pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType> { - encoder: DirectoryEncoder<'a, W>, +pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType, K: TiffKind> { + encoder: DirectoryEncoder<'a, W, K>, strip_idx: u64, strip_count: u64, row_samples: u64, width: u32, height: u32, rows_per_strip: u64, - strip_offsets: Vec, - strip_byte_count: Vec, + strip_offsets: Vec, + strip_byte_count: Vec, dropped: bool, _phantom: ::std::marker::PhantomData, } -impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { - fn new( - mut encoder: DirectoryEncoder<'a, W>, - width: u32, - height: u32, - ) -> TiffResult> { +impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> { + fn new(mut encoder: DirectoryEncoder<'a, W, K>, width: u32, height: u32) -> TiffResult { let row_samples = u64::from(width) * u64::try_from(::BITS_PER_SAMPLE.len())?; let row_bytes = row_samples * u64::from(::BYTE_LEN); @@ -792,8 +365,8 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { } let offset = self.encoder.write_data(value)?; - self.strip_offsets.push(u32::try_from(offset)?); - self.strip_byte_count.push(value.bytes()); + self.strip_offsets.push(K::convert_offset(offset)?); + self.strip_byte_count.push(value.bytes().try_into()?); self.strip_idx += 1; Ok(()) @@ -881,16 +454,18 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { fn finish_internal(&mut self) -> TiffResult<()> { self.encoder - .write_tag(Tag::StripOffsets, &*self.strip_offsets)?; - self.encoder - .write_tag(Tag::StripByteCounts, &*self.strip_byte_count)?; + .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?; + self.encoder.write_tag( + Tag::StripByteCounts, + K::convert_slice(&self.strip_byte_count), + )?; self.dropped = true; self.encoder.finish_internal() } /// Get a reference of the underlying `DirectoryEncoder` - pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W> { + pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> { &mut self.encoder } @@ -900,10 +475,127 @@ impl<'a, W: 'a + Write + Seek, T: ColorType> ImageEncoder<'a, W, T> { } } -impl<'a, W: Write + Seek, C: ColorType> Drop for ImageEncoder<'a, W, C> { +impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W, C, K> { fn drop(&mut self) { if !self.dropped { let _ = self.finish_internal(); } } } + +struct DirectoryEntry { + data_type: u16, + count: S, + data: Vec, +} + +/// Trait to abstract over Tiff/BigTiff differences. +/// +/// Implemented for [`TiffKindStandard`] and [`TiffKindBig`]. +pub trait TiffKind { + /// The type of offset fields, `u32` for normal Tiff, `u64` for BigTiff. + type OffsetType: TryFrom + Into + TiffValue; + + /// Needed for the `convert_slice` method. + type OffsetArrayType: ?Sized + TiffValue; + + /// Write the (Big)Tiff header. + fn write_header(writer: &mut TiffWriter) -> TiffResult<()>; + + /// Convert a file offset to `Self::OffsetType`. + /// + /// This returns an error for normal Tiff if the offset is larger than `u32::MAX`. + fn convert_offset(offset: u64) -> TiffResult; + + /// Write an offset value to the given writer. + /// + /// Like `convert_offset`, this errors if `offset > u32::MAX` for normal Tiff. + fn write_offset(writer: &mut TiffWriter, offset: u64) -> TiffResult<()>; + + /// Write the IFD entry count field with the given `count` value. + /// + /// The entry count field is an `u16` for normal Tiff and `u64` for BigTiff. Errors + /// if the given `usize` is larger than the representable values. + fn write_entry_count(writer: &mut TiffWriter, count: usize) -> TiffResult<()>; + + /// Internal helper method for satisfying Rust's type checker. + /// + /// The `TiffValue` trait is implemented for both primitive values (e.g. `u8`, `u32`) and + /// slices of primitive values (e.g. `[u8]`, `[u32]`). However, this is not represented in + /// the type system, so there is no guarantee that that for all `T: TiffValue` there is also + /// an implementation of `TiffValue` for `[T]`. This method works around that problem by + /// providing a conversion from `[T]` to some value that implements `TiffValue`, thereby + /// making all slices of `OffsetType` usable with `write_tag` and similar methods. + /// + /// Implementations of this trait should always set `OffsetArrayType` to `[OffsetType]`. + fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType; +} + +/// Create a standard Tiff file. +pub struct TiffKindStandard; + +impl TiffKind for TiffKindStandard { + type OffsetType = u32; + type OffsetArrayType = [u32]; + + fn write_header(writer: &mut TiffWriter) -> TiffResult<()> { + write_tiff_header(writer)?; + // blank the IFD offset location + writer.write_u32(0)?; + + Ok(()) + } + + fn convert_offset(offset: u64) -> TiffResult { + Ok(Self::OffsetType::try_from(offset)?) + } + + fn write_offset(writer: &mut TiffWriter, offset: u64) -> TiffResult<()> { + writer.write_u32(u32::try_from(offset)?)?; + Ok(()) + } + + fn write_entry_count(writer: &mut TiffWriter, count: usize) -> TiffResult<()> { + writer.write_u16(u16::try_from(count)?)?; + + Ok(()) + } + + fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType { + slice + } +} + +/// Create a BigTiff file. +pub struct TiffKindBig; + +impl TiffKind for TiffKindBig { + type OffsetType = u64; + type OffsetArrayType = [u64]; + + fn write_header(writer: &mut TiffWriter) -> TiffResult<()> { + write_bigtiff_header(writer)?; + // blank the IFD offset location + writer.write_u64(0)?; + + Ok(()) + } + + fn convert_offset(offset: u64) -> TiffResult { + Ok(offset) + } + + fn write_offset(writer: &mut TiffWriter, offset: u64) -> TiffResult<()> { + writer.write_u64(offset)?; + Ok(()) + } + + fn write_entry_count(writer: &mut TiffWriter, count: usize) -> TiffResult<()> { + writer.write_u64(u64::try_from(count)?)?; + Ok(()) + } + + fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType { + slice + } +} diff --git a/src/encoder/tiff_value.rs b/src/encoder/tiff_value.rs new file mode 100644 index 0000000..1009acb --- /dev/null +++ b/src/encoder/tiff_value.rs @@ -0,0 +1,483 @@ +use std::io::Write; + +use crate::{bytecast, tags::Type, TiffError, TiffFormatError, TiffResult}; + +use super::writer::TiffWriter; + +/// Trait for types that can be encoded in a tiff file +pub trait TiffValue { + const BYTE_LEN: u8; + const FIELD_TYPE: Type; + fn count(&self) -> usize; + fn bytes(&self) -> usize { + self.count() * usize::from(Self::BYTE_LEN) + } + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()>; +} + +impl TiffValue for [u8] { + const BYTE_LEN: u8 = 1; + const FIELD_TYPE: Type = Type::BYTE; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_bytes(self)?; + Ok(()) + } +} + +impl TiffValue for [i8] { + const BYTE_LEN: u8 = 1; + const FIELD_TYPE: Type = Type::SBYTE; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::i8_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [u16] { + const BYTE_LEN: u8 = 2; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::u16_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [i16] { + const BYTE_LEN: u8 = 2; + const FIELD_TYPE: Type = Type::SSHORT; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::i16_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [u32] { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::LONG; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::u32_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [i32] { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::SLONG; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::i32_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [u64] { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::LONG8; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::u64_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [i64] { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::SLONG8; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + let slice = bytecast::i64_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [f32] { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::FLOAT; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + // We write using nativeedian so this sould be safe + let slice = bytecast::f32_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [f64] { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::DOUBLE; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + // We write using nativeedian so this sould be safe + let slice = bytecast::f64_as_ne_bytes(self); + writer.write_bytes(slice)?; + Ok(()) + } +} + +impl TiffValue for [Ifd] { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::IFD; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + for x in self { + x.write(writer)?; + } + Ok(()) + } +} + +impl TiffValue for [Ifd8] { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::IFD8; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + for x in self { + x.write(writer)?; + } + Ok(()) + } +} + +impl TiffValue for [Rational] { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::RATIONAL; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + for x in self { + x.write(writer)?; + } + Ok(()) + } +} + +impl TiffValue for [SRational] { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::SRATIONAL; + + fn count(&self) -> usize { + self.len() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + for x in self { + x.write(writer)?; + } + Ok(()) + } +} + +impl TiffValue for u8 { + const BYTE_LEN: u8 = 1; + const FIELD_TYPE: Type = Type::BYTE; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u8(*self)?; + Ok(()) + } +} + +impl TiffValue for i8 { + const BYTE_LEN: u8 = 1; + const FIELD_TYPE: Type = Type::SBYTE; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i8(*self)?; + Ok(()) + } +} + +impl TiffValue for u16 { + const BYTE_LEN: u8 = 2; + const FIELD_TYPE: Type = Type::SHORT; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u16(*self)?; + Ok(()) + } +} + +impl TiffValue for i16 { + const BYTE_LEN: u8 = 2; + const FIELD_TYPE: Type = Type::SSHORT; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i16(*self)?; + Ok(()) + } +} + +impl TiffValue for u32 { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::LONG; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u32(*self)?; + Ok(()) + } +} + +impl TiffValue for i32 { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::SLONG; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i32(*self)?; + Ok(()) + } +} + +impl TiffValue for u64 { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::LONG8; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u64(*self)?; + Ok(()) + } +} + +impl TiffValue for i64 { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::SLONG8; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_i64(*self)?; + Ok(()) + } +} + +impl TiffValue for f32 { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::FLOAT; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_f32(*self)?; + Ok(()) + } +} + +impl TiffValue for f64 { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::DOUBLE; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_f64(*self)?; + Ok(()) + } +} + +impl TiffValue for Ifd { + const BYTE_LEN: u8 = 4; + const FIELD_TYPE: Type = Type::IFD; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u32(self.0)?; + Ok(()) + } +} + +impl TiffValue for Ifd8 { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::IFD8; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u64(self.0)?; + Ok(()) + } +} + +impl TiffValue for Rational { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::RATIONAL; + + fn count(&self) -> usize { + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + writer.write_u32(self.n)?; + writer.write_u32(self.d)?; + Ok(()) + } +} + +impl TiffValue for SRational { + const BYTE_LEN: u8 = 8; + const FIELD_TYPE: Type = Type::SRATIONAL; + + fn count(&self) -> usize { + 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: u8 = 1; + const FIELD_TYPE: Type = Type::ASCII; + + fn count(&self) -> usize { + self.len() + 1 + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + if self.is_ascii() && !self.bytes().any(|b| b == 0) { + writer.write_bytes(self.as_bytes())?; + writer.write_u8(0)?; + Ok(()) + } else { + Err(TiffError::FormatError(TiffFormatError::InvalidTag)) + } + } +} + +impl<'a, T: TiffValue + ?Sized> TiffValue for &'a T { + const BYTE_LEN: u8 = T::BYTE_LEN; + const FIELD_TYPE: Type = T::FIELD_TYPE; + + fn count(&self) -> usize { + (*self).count() + } + + fn write(&self, writer: &mut TiffWriter) -> TiffResult<()> { + (*self).write(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 { + pub n: u32, + pub d: u32, +} + +/// Type to represent tiff values of type `SRATIONAL` +#[derive(Clone)] +pub struct SRational { + pub n: i32, + pub d: i32, +} diff --git a/src/encoder/writer.rs b/src/encoder/writer.rs index a8e61a7..5ba47d1 100644 --- a/src/encoder/writer.rs +++ b/src/encoder/writer.rs @@ -14,6 +14,31 @@ pub fn write_tiff_header(writer: &mut TiffWriter) -> TiffResult<()> Ok(()) } +/// Writes a BigTiff header, excluding the IFD offset field. +/// +/// Writes the byte order, version number, offset byte size, and zero constant fields. Does +// _not_ write the offset to the first IFD, this should be done by the caller. +pub fn write_bigtiff_header(writer: &mut TiffWriter) -> TiffResult<()> { + #[cfg(target_endian = "little")] + let boi: u8 = 0x49; + #[cfg(not(target_endian = "little"))] + let boi: u8 = 0x4d; + + // byte order indication + writer.writer.write_all(&[boi, boi])?; + // version number + writer.writer.write_all(&43u16.to_ne_bytes())?; + // bytesize of offsets (pointer size) + writer.writer.write_all(&8u16.to_ne_bytes())?; + // always 0 + writer.writer.write_all(&0u16.to_ne_bytes())?; + + // we wrote 8 bytes, so set the internal offset accordingly + writer.offset += 8; + + Ok(()) +} + pub struct TiffWriter { writer: W, offset: u64, diff --git a/tests/encode_images.rs b/tests/encode_images.rs index 4230935..a8e1ca3 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -48,6 +48,45 @@ fn encode_decode() { } } +#[test] +fn encode_decode_big() { + let mut image_data = Vec::new(); + for x in 0..100 { + for y in 0..100u8 { + let val = x + y; + image_data.push(val); + image_data.push(val); + image_data.push(val); + } + } + let mut file = Cursor::new(Vec::new()); + { + let mut tiff = TiffEncoder::new_big(&mut file).unwrap(); + + let mut image = tiff.new_image::(100, 100).unwrap(); + image + .encoder() + .write_tag(Tag::Artist, "Image-tiff") + .unwrap(); + image.write_data(&image_data).unwrap(); + } + { + file.seek(SeekFrom::Start(0)).unwrap(); + let mut decoder = Decoder::new(&mut file).unwrap(); + assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); + assert_eq!(decoder.dimensions().unwrap(), (100, 100)); + assert_eq!( + decoder.get_tag(Tag::Artist).unwrap(), + ifd::Value::Ascii("Image-tiff".into()) + ); + if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { + assert_eq!(image_data, img_res); + } else { + panic!("Wrong data type"); + } + } +} + #[test] fn test_encode_ifd() { let mut data = Cursor::new(Vec::new());