diff options
Diffstat (limited to 'vendor/tiff/src/encoder/mod.rs')
-rw-r--r-- | vendor/tiff/src/encoder/mod.rs | 681 |
1 files changed, 0 insertions, 681 deletions
diff --git a/vendor/tiff/src/encoder/mod.rs b/vendor/tiff/src/encoder/mod.rs deleted file mode 100644 index 6e39c93..0000000 --- a/vendor/tiff/src/encoder/mod.rs +++ /dev/null @@ -1,681 +0,0 @@ -pub use tiff_value::*; - -use std::{ - cmp, - collections::BTreeMap, - convert::{TryFrom, TryInto}, - io::{self, Seek, Write}, - marker::PhantomData, - mem, - num::TryFromIntError, -}; - -use crate::{ - error::TiffResult, - tags::{CompressionMethod, ResolutionUnit, Tag}, - TiffError, TiffFormatError, -}; - -pub mod colortype; -pub mod compression; -mod tiff_value; -mod writer; - -use self::colortype::*; -use self::compression::*; -use self::writer::*; - -/// Encoder for Tiff and BigTiff files. -/// -/// With this type you can get a `DirectoryEncoder` or a `ImageEncoder` -/// to encode Tiff/BigTiff 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::*; -/// -/// // create a standard Tiff file -/// let mut tiff = TiffEncoder::new(&mut file).unwrap(); -/// tiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap(); -/// -/// // create a BigTiff file -/// let mut bigtiff = TiffEncoder::new_big(&mut file).unwrap(); -/// bigtiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap(); -/// -/// # } -/// ``` -pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> { - writer: TiffWriter<W>, - kind: PhantomData<K>, -} - -/// Constructor functions to create standard Tiff files. -impl<W: Write + Seek> TiffEncoder<W> { - /// 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<W, TiffKindStandard>> { - TiffEncoder::new_generic(writer) - } -} - -/// Constructor functions to create BigTiff files. -impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> { - /// 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<Self> { - TiffEncoder::new_generic(writer) - } -} - -/// Generic functions that are available for both Tiff and BigTiff encoders. -impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> { - /// Creates a new Tiff or BigTiff encoder, inferred from the return type. - pub fn new_generic(writer: W) -> TiffResult<Self> { - let mut encoder = TiffEncoder { - writer: TiffWriter::new(writer), - kind: PhantomData, - }; - - K::write_header(&mut encoder.writer)?; - - Ok(encoder) - } - - /// Create a [`DirectoryEncoder`] to encode an ifd directory. - pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<W, K>> { - DirectoryEncoder::new(&mut self.writer) - } - - /// Create an [`ImageEncoder`] to encode an image one slice at a time. - pub fn new_image<C: ColorType>( - &mut self, - width: u32, - height: u32, - ) -> TiffResult<ImageEncoder<W, C, K, Uncompressed>> { - let encoder = DirectoryEncoder::new(&mut self.writer)?; - ImageEncoder::new(encoder, width, height) - } - - /// Create an [`ImageEncoder`] to encode an image one slice at a time. - pub fn new_image_with_compression<C: ColorType, D: Compression>( - &mut self, - width: u32, - height: u32, - compression: D, - ) -> TiffResult<ImageEncoder<W, C, K, D>> { - let encoder = DirectoryEncoder::new(&mut self.writer)?; - ImageEncoder::with_compression(encoder, width, height, compression) - } - - /// Convenience function to write an entire image from memory. - pub fn write_image<C: ColorType>( - &mut self, - width: u32, - height: u32, - data: &[C::Inner], - ) -> TiffResult<()> - where - [C::Inner]: TiffValue, - { - let encoder = DirectoryEncoder::new(&mut self.writer)?; - let image: ImageEncoder<W, C, K> = ImageEncoder::new(encoder, width, height)?; - image.write_data(data) - } - - /// Convenience function to write an entire image from memory with a given compression. - pub fn write_image_with_compression<C: ColorType, D: Compression>( - &mut self, - width: u32, - height: u32, - compression: D, - data: &[C::Inner], - ) -> TiffResult<()> - where - [C::Inner]: TiffValue, - { - let encoder = DirectoryEncoder::new(&mut self.writer)?; - let image: ImageEncoder<W, C, K, D> = - ImageEncoder::with_compression(encoder, width, height, compression)?; - 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, K: TiffKind> { - writer: &'a mut TiffWriter<W>, - dropped: bool, - // We use BTreeMap to make sure tags are written in correct order - ifd_pointer_pos: u64, - ifd: BTreeMap<u16, DirectoryEntry<K::OffsetType>>, -} - -impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> { - fn new(writer: &'a mut TiffWriter<W>) -> TiffResult<Self> { - // the previous word is the IFD offset position - let ifd_pointer_pos = writer.offset() - mem::size_of::<K::OffsetType>() as u64; - writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff? - Ok(DirectoryEncoder { - writer, - dropped: false, - ifd_pointer_pos, - ifd: BTreeMap::new(), - }) - } - - /// Write a single ifd tag. - pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> { - let mut bytes = Vec::with_capacity(value.bytes()); - { - let mut writer = TiffWriter::new(&mut bytes); - value.write(&mut writer)?; - } - - self.ifd.insert( - tag.to_u16(), - DirectoryEntry { - data_type: <T>::FIELD_TYPE.to_u16(), - count: value.count().try_into()?, - data: bytes, - }, - ); - - Ok(()) - } - - fn write_directory(&mut self) -> TiffResult<u64> { - // Start by writing out all values - for &mut DirectoryEntry { - data: ref mut bytes, - .. - } in self.ifd.values_mut() - { - let data_bytes = mem::size_of::<K::OffsetType>(); - - if bytes.len() > data_bytes { - let offset = self.writer.offset(); - self.writer.write_bytes(bytes)?; - *bytes = vec![0; data_bytes]; - let mut writer = TiffWriter::new(bytes as &mut [u8]); - K::write_offset(&mut writer, offset)?; - } else { - while bytes.len() < data_bytes { - bytes.push(0); - } - } - } - - let offset = self.writer.offset(); - - 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)?; - (*count).write(&mut self.writer)?; - 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<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> { - let offset = self.writer.offset(); - value.write(&mut self.writer)?; - Ok(offset) - } - - /// Provides the number of bytes written by the underlying TiffWriter during the last call. - fn last_written(&self) -> u64 { - self.writer.last_written() - } - - 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)?; - K::write_offset(&mut self.writer, ifd_pointer)?; - self.writer.goto_offset(curr_pos)?; - K::write_offset(&mut self.writer, 0)?; - - self.dropped = true; - - Ok(()) - } - - /// Write out the ifd directory. - pub fn finish(mut self) -> TiffResult<()> { - self.finish_internal() - } -} - -impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> { - 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::<colortype::RGB8>(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, - K: TiffKind, - D: Compression = Uncompressed, -> { - 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<K::OffsetType>, - strip_byte_count: Vec<K::OffsetType>, - dropped: bool, - compression: D, - _phantom: ::std::marker::PhantomData<C>, -} - -impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind, D: Compression> - ImageEncoder<'a, W, T, K, D> -{ - fn new(encoder: DirectoryEncoder<'a, W, K>, width: u32, height: u32) -> TiffResult<Self> - where - D: Default, - { - Self::with_compression(encoder, width, height, D::default()) - } - - fn with_compression( - mut encoder: DirectoryEncoder<'a, W, K>, - width: u32, - height: u32, - compression: D, - ) -> TiffResult<Self> { - if width == 0 || height == 0 { - return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions( - width, height, - ))); - } - - let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?; - let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN); - - // Limit the strip size to prevent potential memory and security issues. - // Also keep the multiple strip handling 'oiled' - let rows_per_strip = { - match D::COMPRESSION_METHOD { - CompressionMethod::PackBits => 1, // Each row must be packed separately. Do not compress across row boundaries - _ => (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, D::COMPRESSION_METHOD.to_u16())?; - - encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?; - let sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect(); - encoder.write_tag(Tag::SampleFormat, &sample_format[..])?; - encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?; - - encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?; - - encoder.write_tag( - Tag::SamplesPerPixel, - u16::try_from(<T>::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, - compression: compression, - _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, - { - 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()); - } - - // Write the (possible compressed) data to the encoder. - let offset = self.encoder.write_data(value)?; - let byte_count = self.encoder.last_written() as usize; - - self.strip_offsets.push(K::convert_offset(offset)?); - self.strip_byte_count.push(byte_count.try_into()?); - - 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()); - } - - self.encoder - .writer - .set_compression(self.compression.get_algorithm()); - - 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.encoder.writer.reset_compression(); - 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, 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, K> { - &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, K: TiffKind, D: Compression> Drop - for ImageEncoder<'a, W, C, K, D> -{ - fn drop(&mut self) { - if !self.dropped { - let _ = self.finish_internal(); - } - } -} - -struct DirectoryEntry<S> { - data_type: u16, - count: S, - data: Vec<u8>, -} - -/// 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<usize, Error = TryFromIntError> + Into<u64> + TiffValue; - - /// Needed for the `convert_slice` method. - type OffsetArrayType: ?Sized + TiffValue; - - /// Write the (Big)Tiff header. - fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> 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<Self::OffsetType>; - - /// Write an offset value to the given writer. - /// - /// Like `convert_offset`, this errors if `offset > u32::MAX` for normal Tiff. - fn write_offset<W: Write>(writer: &mut TiffWriter<W>, 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<W: Write>(writer: &mut TiffWriter<W>, 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<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> { - write_tiff_header(writer)?; - // blank the IFD offset location - writer.write_u32(0)?; - - Ok(()) - } - - fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> { - Ok(Self::OffsetType::try_from(offset)?) - } - - fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> { - writer.write_u32(u32::try_from(offset)?)?; - Ok(()) - } - - fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, 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<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> { - write_bigtiff_header(writer)?; - // blank the IFD offset location - writer.write_u64(0)?; - - Ok(()) - } - - fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> { - Ok(offset) - } - - fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> { - writer.write_u64(offset)?; - Ok(()) - } - - fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> { - writer.write_u64(u64::try_from(count)?)?; - Ok(()) - } - - fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType { - slice - } -} |