use std::collections::BTreeMap; use std::convert::TryFrom; use std::io::{Seek, Write}; use std::{cmp, io, mem}; use crate::bytecast; use crate::error::{TiffError, TiffFormatError, TiffResult}; use crate::tags::{self, ResolutionUnit, Tag, Type}; pub mod colortype; mod writer; use self::colortype::*; use self::writer::*; /// 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` 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 [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 [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 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 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. /// /// With this type you can get a `DirectoryEncoder` or a `ImageEncoder` /// to encode tiff ifd directories with images. /// /// See `DirectoryEncoder` and `ImageEncoder`. /// /// # Examples /// ``` /// # extern crate tiff; /// # fn main() { /// # let mut file = std::io::Cursor::new(Vec::new()); /// # let image_data = vec![0; 100*100*3]; /// use tiff::encoder::*; /// /// let mut tiff = TiffEncoder::new(&mut file).unwrap(); /// /// tiff.write_image::(100, 100, &image_data).unwrap(); /// # } /// ``` pub struct TiffEncoder { writer: TiffWriter, } impl TiffEncoder { pub fn new(writer: W) -> TiffResult> { let mut encoder = TiffEncoder { writer: TiffWriter::new(writer), }; write_tiff_header(&mut encoder.writer)?; // blank the IFD offset location encoder.writer.write_u32(0)?; Ok(encoder) } /// 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. pub fn new_image( &mut self, width: u32, height: u32, ) -> TiffResult> { let encoder = DirectoryEncoder::new(&mut self.writer)?; ImageEncoder::new(encoder, width, height) } /// Convenience function to write an entire image from memory. pub fn write_image( &mut self, width: u32, height: u32, data: &[C::Inner], ) -> TiffResult<()> where [C::Inner]: TiffValue, { let encoder = DirectoryEncoder::new(&mut self.writer)?; let image: ImageEncoder = ImageEncoder::new(encoder, width, height)?; image.write_data(data) } } /// Low level interface to encode ifd directories. /// /// 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> { writer: &'a mut TiffWriter, dropped: bool, // We use BTreeMap to make sure tags are written in correct order ifd_pointer_pos: u64, ifd: BTreeMap)>, } impl<'a, W: 'a + Write + Seek> DirectoryEncoder<'a, W> { 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()?; Ok(DirectoryEncoder { writer, dropped: false, ifd_pointer_pos, ifd: BTreeMap::new(), }) } /// 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 writer = TiffWriter::new(&mut bytes); value.write(&mut writer)?; } self.ifd.insert( tag.to_u16(), (::FIELD_TYPE.to_u16(), value.count(), bytes), ); Ok(()) } 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 { let offset = self.writer.offset(); self.writer.write_bytes(bytes)?; *bytes = vec![0, 0, 0, 0]; let mut writer = TiffWriter::new(bytes as &mut [u8]); writer.write_u32(u32::try_from(offset)?)?; } else { while bytes.len() < 4 { bytes.push(0); } } } 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() { self.writer.write_u16(*tag)?; self.writer.write_u16(*field_type)?; self.writer.write_u32(*count)?; self.writer.write_bytes(offset)?; } Ok(offset) } /// Write some data to the tiff file, the offset of the data is returned. /// /// This could be used to write tiff strips. pub fn write_data(&mut self, value: T) -> TiffResult { let offset = self.writer.offset(); value.write(&mut self.writer)?; Ok(offset) } fn finish_internal(&mut self) -> TiffResult<()> { let ifd_pointer = self.write_directory()?; let curr_pos = self.writer.offset(); self.writer.goto_offset(self.ifd_pointer_pos)?; self.writer.write_u32(u32::try_from(ifd_pointer)?)?; self.writer.goto_offset(curr_pos)?; self.writer.write_u32(0)?; self.dropped = true; Ok(()) } /// Write out the ifd directory. pub fn finish(mut self) -> TiffResult<()> { self.finish_internal() } } impl<'a, W: Write + Seek> Drop for DirectoryEncoder<'a, W> { fn drop(&mut self) { if !self.dropped { let _ = self.finish_internal(); } } } /// Type to encode images strip by strip. /// /// You should call `finish` on this when you are finished with it. /// Encoding can silently fail while this is dropping. /// /// # Examples /// ``` /// # extern crate tiff; /// # fn main() { /// # let mut file = std::io::Cursor::new(Vec::new()); /// # let image_data = vec![0; 100*100*3]; /// use tiff::encoder::*; /// use tiff::tags::Tag; /// /// let mut tiff = TiffEncoder::new(&mut file).unwrap(); /// let mut image = tiff.new_image::(100, 100).unwrap(); /// /// // You can encode tags here /// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap(); /// /// // Strip size can be configured before writing data /// image.rows_per_strip(2).unwrap(); /// /// let mut idx = 0; /// while image.next_strip_sample_count() > 0 { /// let sample_count = image.next_strip_sample_count() as usize; /// image.write_strip(&image_data[idx..idx+sample_count]).unwrap(); /// idx += sample_count; /// } /// image.finish().unwrap(); /// # } /// ``` /// 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>, strip_idx: u64, strip_count: u64, row_samples: u64, width: u32, height: u32, rows_per_strip: u64, 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> { let row_samples = u64::from(width) * u64::try_from(::BITS_PER_SAMPLE.len())?; let row_bytes = row_samples * u64::from(::BYTE_LEN); // Limit the strip size to prevent potential memory and security issues. // Also keep the multiple strip handling 'oiled' let rows_per_strip = (1_000_000 + row_bytes - 1) / row_bytes; let strip_count = (u64::from(height) + rows_per_strip - 1) / rows_per_strip; encoder.write_tag(Tag::ImageWidth, width)?; encoder.write_tag(Tag::ImageLength, height)?; encoder.write_tag(Tag::Compression, tags::CompressionMethod::None.to_u16())?; encoder.write_tag(Tag::BitsPerSample, ::BITS_PER_SAMPLE)?; let sample_format: Vec<_> = ::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect(); encoder.write_tag(Tag::SampleFormat, &sample_format[..])?; encoder.write_tag(Tag::PhotometricInterpretation, ::TIFF_VALUE.to_u16())?; encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?; encoder.write_tag( Tag::SamplesPerPixel, u16::try_from(::BITS_PER_SAMPLE.len())?, )?; encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?; encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?; encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?; Ok(ImageEncoder { encoder, strip_count, strip_idx: 0, row_samples, rows_per_strip, width, height, strip_offsets: Vec::new(), strip_byte_count: Vec::new(), dropped: false, _phantom: ::std::marker::PhantomData, }) } /// Number of samples the next strip should have. pub fn next_strip_sample_count(&self) -> u64 { if self.strip_idx >= self.strip_count { return 0; } let raw_start_row = self.strip_idx * self.rows_per_strip; let start_row = cmp::min(u64::from(self.height), raw_start_row); let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip); (end_row - start_row) * self.row_samples } /// Write a single strip. pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()> where [T::Inner]: TiffValue, { // TODO: Compression let samples = self.next_strip_sample_count(); if u64::try_from(value.len())? != samples { return Err(io::Error::new( io::ErrorKind::InvalidData, "Slice is wrong size for strip", ) .into()); } let offset = self.encoder.write_data(value)?; self.strip_offsets.push(u32::try_from(offset)?); self.strip_byte_count.push(value.bytes()); self.strip_idx += 1; Ok(()) } /// Write strips from data pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()> where [T::Inner]: TiffValue, { let num_pix = usize::try_from(self.width)? .checked_mul(usize::try_from(self.height)?) .ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidInput, "Image width * height exceeds usize", ) })?; if data.len() < num_pix { return Err(io::Error::new( io::ErrorKind::InvalidData, "Input data slice is undersized for provided dimensions", ) .into()); } let mut idx = 0; while self.next_strip_sample_count() > 0 { let sample_count = usize::try_from(self.next_strip_sample_count())?; self.write_strip(&data[idx..idx + sample_count])?; idx += sample_count; } self.finish()?; Ok(()) } /// Set image resolution pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) { self.encoder .write_tag(Tag::ResolutionUnit, unit.to_u16()) .unwrap(); self.encoder .write_tag(Tag::XResolution, value.clone()) .unwrap(); self.encoder.write_tag(Tag::YResolution, value).unwrap(); } /// Set image resolution unit pub fn resolution_unit(&mut self, unit: ResolutionUnit) { self.encoder .write_tag(Tag::ResolutionUnit, unit.to_u16()) .unwrap(); } /// Set image x-resolution pub fn x_resolution(&mut self, value: Rational) { self.encoder.write_tag(Tag::XResolution, value).unwrap(); } /// Set image y-resolution pub fn y_resolution(&mut self, value: Rational) { self.encoder.write_tag(Tag::YResolution, value).unwrap(); } /// Set image number of lines per strip /// /// This function needs to be called before any calls to `write_data` or /// `write_strip` and will return an error otherwise. pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> { if self.strip_idx != 0 { return Err(io::Error::new( io::ErrorKind::InvalidInput, "Cannot change strip size after data was written", ) .into()); } // Write tag as 32 bits self.encoder.write_tag(Tag::RowsPerStrip, value)?; let value: u64 = value as u64; self.strip_count = (self.height as u64 + value - 1) / value; self.rows_per_strip = value; Ok(()) } 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)?; self.dropped = true; self.encoder.finish_internal() } /// Get a reference of the underlying `DirectoryEncoder` pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W> { &mut self.encoder } /// Write out image and ifd directory. pub fn finish(mut self) -> TiffResult<()> { self.finish_internal() } } impl<'a, W: Write + Seek, C: ColorType> Drop for ImageEncoder<'a, W, C> { fn drop(&mut self) { if !self.dropped { let _ = self.finish_internal(); } } }