summaryrefslogtreecommitdiff
path: root/vendor/tiff/src/encoder
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tiff/src/encoder')
-rw-r--r--vendor/tiff/src/encoder/colortype.rs245
-rw-r--r--vendor/tiff/src/encoder/compression/deflate.rs83
-rw-r--r--vendor/tiff/src/encoder/compression/lzw.rs47
-rw-r--r--vendor/tiff/src/encoder/compression/mod.rs60
-rw-r--r--vendor/tiff/src/encoder/compression/packbits.rs214
-rw-r--r--vendor/tiff/src/encoder/compression/uncompressed.rs37
-rw-r--r--vendor/tiff/src/encoder/mod.rs681
-rw-r--r--vendor/tiff/src/encoder/tiff_value.rs523
-rw-r--r--vendor/tiff/src/encoder/writer.rs188
9 files changed, 2078 insertions, 0 deletions
diff --git a/vendor/tiff/src/encoder/colortype.rs b/vendor/tiff/src/encoder/colortype.rs
new file mode 100644
index 0000000..1946daf
--- /dev/null
+++ b/vendor/tiff/src/encoder/colortype.rs
@@ -0,0 +1,245 @@
+use crate::tags::{PhotometricInterpretation, SampleFormat};
+
+/// Trait for different colortypes that can be encoded.
+pub trait ColorType {
+ /// The type of each sample of this colortype
+ type Inner: super::TiffValue;
+ /// The value of the tiff tag `PhotometricInterpretation`
+ const TIFF_VALUE: PhotometricInterpretation;
+ /// The value of the tiff tag `BitsPerSample`
+ const BITS_PER_SAMPLE: &'static [u16];
+ /// The value of the tiff tag `SampleFormat`
+ const SAMPLE_FORMAT: &'static [SampleFormat];
+}
+
+pub struct Gray8;
+impl ColorType for Gray8 {
+ type Inner = u8;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[8];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint];
+}
+
+pub struct GrayI8;
+impl ColorType for GrayI8 {
+ type Inner = i8;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[8];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Int];
+}
+
+pub struct Gray16;
+impl ColorType for Gray16 {
+ type Inner = u16;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[16];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint];
+}
+
+pub struct GrayI16;
+impl ColorType for GrayI16 {
+ type Inner = i16;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[16];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Int];
+}
+
+pub struct Gray32;
+impl ColorType for Gray32 {
+ type Inner = u32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint];
+}
+
+pub struct GrayI32;
+impl ColorType for GrayI32 {
+ type Inner = i32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Int];
+}
+
+pub struct Gray32Float;
+impl ColorType for Gray32Float {
+ type Inner = f32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP];
+}
+
+pub struct Gray64;
+impl ColorType for Gray64 {
+ type Inner = u64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint];
+}
+
+pub struct GrayI64;
+impl ColorType for GrayI64 {
+ type Inner = i64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Int];
+}
+
+pub struct Gray64Float;
+impl ColorType for Gray64Float {
+ type Inner = f64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::BlackIsZero;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP];
+}
+
+pub struct RGB8;
+impl ColorType for RGB8 {
+ type Inner = u8;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[8, 8, 8];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 3];
+}
+
+pub struct RGB16;
+impl ColorType for RGB16 {
+ type Inner = u16;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 3];
+}
+
+pub struct RGB32;
+impl ColorType for RGB32 {
+ type Inner = u32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 3];
+}
+
+pub struct RGB32Float;
+impl ColorType for RGB32Float {
+ type Inner = f32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP; 3];
+}
+
+pub struct RGB64;
+impl ColorType for RGB64 {
+ type Inner = u64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 3];
+}
+
+pub struct RGB64Float;
+impl ColorType for RGB64Float {
+ type Inner = f64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP; 3];
+}
+
+pub struct RGBA8;
+impl ColorType for RGBA8 {
+ type Inner = u8;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[8, 8, 8, 8];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct RGBA16;
+impl ColorType for RGBA16 {
+ type Inner = u16;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16, 16];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct RGBA32;
+impl ColorType for RGBA32 {
+ type Inner = u32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32, 32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct RGBA32Float;
+impl ColorType for RGBA32Float {
+ type Inner = f32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32, 32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP; 4];
+}
+
+pub struct RGBA64;
+impl ColorType for RGBA64 {
+ type Inner = u64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64, 64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct RGBA64Float;
+impl ColorType for RGBA64Float {
+ type Inner = f64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::RGB;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64, 64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP; 4];
+}
+
+pub struct CMYK8;
+impl ColorType for CMYK8 {
+ type Inner = u8;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
+ const BITS_PER_SAMPLE: &'static [u16] = &[8, 8, 8, 8];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct CMYK16;
+impl ColorType for CMYK16 {
+ type Inner = u16;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
+ const BITS_PER_SAMPLE: &'static [u16] = &[16, 16, 16, 16];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct CMYK32;
+impl ColorType for CMYK32 {
+ type Inner = u32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32, 32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct CMYK32Float;
+impl ColorType for CMYK32Float {
+ type Inner = f32;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
+ const BITS_PER_SAMPLE: &'static [u16] = &[32, 32, 32, 32];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP; 4];
+}
+
+pub struct CMYK64;
+impl ColorType for CMYK64 {
+ type Inner = u64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64, 64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 4];
+}
+
+pub struct CMYK64Float;
+impl ColorType for CMYK64Float {
+ type Inner = f64;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::CMYK;
+ const BITS_PER_SAMPLE: &'static [u16] = &[64, 64, 64, 64];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::IEEEFP; 4];
+}
+
+pub struct YCbCr8;
+impl ColorType for YCbCr8 {
+ type Inner = u8;
+ const TIFF_VALUE: PhotometricInterpretation = PhotometricInterpretation::YCbCr;
+ const BITS_PER_SAMPLE: &'static [u16] = &[8, 8, 8];
+ const SAMPLE_FORMAT: &'static [SampleFormat] = &[SampleFormat::Uint; 3];
+}
diff --git a/vendor/tiff/src/encoder/compression/deflate.rs b/vendor/tiff/src/encoder/compression/deflate.rs
new file mode 100644
index 0000000..5e7a261
--- /dev/null
+++ b/vendor/tiff/src/encoder/compression/deflate.rs
@@ -0,0 +1,83 @@
+use crate::{encoder::compression::*, tags::CompressionMethod};
+use flate2::{write::ZlibEncoder, Compression as FlateCompression};
+use std::io::Write;
+
+/// The Deflate algorithm used to compress image data in TIFF files.
+#[derive(Debug, Clone, Copy)]
+pub struct Deflate {
+ level: FlateCompression,
+}
+
+/// The level of compression used by the Deflate algorithm.
+/// It allows trading compression ratio for compression speed.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+#[non_exhaustive]
+pub enum DeflateLevel {
+ /// The fastest possible compression mode.
+ Fast = 1,
+ /// The conserative choice between speed and ratio.
+ Balanced = 6,
+ /// The best compression available with Deflate.
+ Best = 9,
+}
+
+impl Default for DeflateLevel {
+ fn default() -> Self {
+ DeflateLevel::Balanced
+ }
+}
+
+impl Deflate {
+ /// Create a new deflate compressor with a specific level of compression.
+ pub fn with_level(level: DeflateLevel) -> Self {
+ Self {
+ level: FlateCompression::new(level as u32),
+ }
+ }
+}
+
+impl Default for Deflate {
+ fn default() -> Self {
+ Self::with_level(DeflateLevel::default())
+ }
+}
+
+impl Compression for Deflate {
+ const COMPRESSION_METHOD: CompressionMethod = CompressionMethod::Deflate;
+
+ fn get_algorithm(&self) -> Compressor {
+ Compressor::Deflate(self.clone())
+ }
+}
+
+impl CompressionAlgorithm for Deflate {
+ fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error> {
+ let mut encoder = ZlibEncoder::new(writer, self.level);
+ encoder.write_all(bytes)?;
+ encoder.try_finish()?;
+ Ok(encoder.total_out())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::encoder::compression::tests::TEST_DATA;
+ use std::io::Cursor;
+
+ #[test]
+ fn test_deflate() {
+ const EXPECTED_COMPRESSED_DATA: [u8; 64] = [
+ 0x78, 0x9C, 0x15, 0xC7, 0xD1, 0x0D, 0x80, 0x20, 0x0C, 0x04, 0xD0, 0x55, 0x6E, 0x02,
+ 0xA7, 0x71, 0x81, 0xA6, 0x41, 0xDA, 0x28, 0xD4, 0xF4, 0xD0, 0xF9, 0x81, 0xE4, 0xFD,
+ 0xBC, 0xD3, 0x9C, 0x58, 0x04, 0x1C, 0xE9, 0xBD, 0xE2, 0x8A, 0x84, 0x5A, 0xD1, 0x7B,
+ 0xE7, 0x97, 0xF4, 0xF8, 0x08, 0x8D, 0xF6, 0x66, 0x21, 0x3D, 0x3A, 0xE4, 0xA9, 0x91,
+ 0x3E, 0xAC, 0xF1, 0x98, 0xB9, 0x70, 0x17, 0x13,
+ ];
+
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Deflate::default().write_to(&mut writer, TEST_DATA).unwrap();
+ assert_eq!(EXPECTED_COMPRESSED_DATA, compressed_data.as_slice());
+ }
+}
diff --git a/vendor/tiff/src/encoder/compression/lzw.rs b/vendor/tiff/src/encoder/compression/lzw.rs
new file mode 100644
index 0000000..0e0f2aa
--- /dev/null
+++ b/vendor/tiff/src/encoder/compression/lzw.rs
@@ -0,0 +1,47 @@
+use crate::{encoder::compression::*, tags::CompressionMethod};
+use std::io::Write;
+use weezl::encode::Encoder as LZWEncoder;
+
+/// The LZW algorithm used to compress image data in TIFF files.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct Lzw;
+
+impl Compression for Lzw {
+ const COMPRESSION_METHOD: CompressionMethod = CompressionMethod::LZW;
+
+ fn get_algorithm(&self) -> Compressor {
+ Compressor::Lzw(*self)
+ }
+}
+
+impl CompressionAlgorithm for Lzw {
+ fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error> {
+ let mut encoder = LZWEncoder::with_tiff_size_switch(weezl::BitOrder::Msb, 8);
+ let result = encoder.into_stream(writer).encode_all(bytes);
+ let byte_count = result.bytes_written as u64;
+ result.status.map(|_| byte_count)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::encoder::compression::tests::TEST_DATA;
+ use std::io::Cursor;
+
+ #[test]
+ fn test_lzw() {
+ const EXPECTED_COMPRESSED_DATA: [u8; 63] = [
+ 0x80, 0x15, 0x0D, 0x06, 0x93, 0x98, 0x82, 0x08, 0x20, 0x30, 0x88, 0x0E, 0x67, 0x43,
+ 0x91, 0xA4, 0xDC, 0x67, 0x10, 0x19, 0x8D, 0xE7, 0x21, 0x01, 0x8C, 0xD0, 0x65, 0x31,
+ 0x9A, 0xE1, 0xD1, 0x03, 0xB1, 0x86, 0x1A, 0x6F, 0x3A, 0xC1, 0x4C, 0x66, 0xF3, 0x69,
+ 0xC0, 0xE4, 0x65, 0x39, 0x9C, 0xCD, 0x26, 0xF3, 0x74, 0x20, 0xD8, 0x67, 0x89, 0x9A,
+ 0x4E, 0x86, 0x83, 0x69, 0xCC, 0x5D, 0x01,
+ ];
+
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Lzw::default().write_to(&mut writer, TEST_DATA).unwrap();
+ assert_eq!(EXPECTED_COMPRESSED_DATA, compressed_data.as_slice());
+ }
+}
diff --git a/vendor/tiff/src/encoder/compression/mod.rs b/vendor/tiff/src/encoder/compression/mod.rs
new file mode 100644
index 0000000..04baef3
--- /dev/null
+++ b/vendor/tiff/src/encoder/compression/mod.rs
@@ -0,0 +1,60 @@
+use crate::tags::CompressionMethod;
+use std::io::{self, Write};
+
+mod deflate;
+mod lzw;
+mod packbits;
+mod uncompressed;
+
+pub use self::deflate::{Deflate, DeflateLevel};
+pub use self::lzw::Lzw;
+pub use self::packbits::Packbits;
+pub use self::uncompressed::Uncompressed;
+
+/// An algorithm used for compression
+pub trait CompressionAlgorithm {
+ /// The algorithm writes data directly into the writer.
+ /// It returns the total number of bytes written.
+ fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error>;
+}
+
+/// An algorithm used for compression with associated enums and optional configurations.
+pub trait Compression: CompressionAlgorithm {
+ /// The corresponding tag to the algorithm.
+ const COMPRESSION_METHOD: CompressionMethod;
+
+ /// Method to optain a type that can store each variant of comression algorithm.
+ fn get_algorithm(&self) -> Compressor;
+}
+
+/// An enum to store each compression algorithm.
+pub enum Compressor {
+ Uncompressed(Uncompressed),
+ Lzw(Lzw),
+ Deflate(Deflate),
+ Packbits(Packbits),
+}
+
+impl Default for Compressor {
+ /// The default compression strategy does not apply any compression.
+ fn default() -> Self {
+ Compressor::Uncompressed(Uncompressed::default())
+ }
+}
+
+impl CompressionAlgorithm for Compressor {
+ fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error> {
+ match self {
+ Compressor::Uncompressed(algorithm) => algorithm.write_to(writer, bytes),
+ Compressor::Lzw(algorithm) => algorithm.write_to(writer, bytes),
+ Compressor::Deflate(algorithm) => algorithm.write_to(writer, bytes),
+ Compressor::Packbits(algorithm) => algorithm.write_to(writer, bytes),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ pub const TEST_DATA: &'static [u8] =
+ b"This is a string for checking various compression algorithms.";
+}
diff --git a/vendor/tiff/src/encoder/compression/packbits.rs b/vendor/tiff/src/encoder/compression/packbits.rs
new file mode 100644
index 0000000..7ba3833
--- /dev/null
+++ b/vendor/tiff/src/encoder/compression/packbits.rs
@@ -0,0 +1,214 @@
+use crate::{encoder::compression::*, tags::CompressionMethod};
+use std::io::{BufWriter, Error, ErrorKind, Write};
+
+/// Compressor that uses the Packbits[^note] algorithm to compress bytes.
+///
+/// [^note]: PackBits is often ineffective on continuous tone images,
+/// including many grayscale images. In such cases, it is better
+/// to leave the image uncompressed.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct Packbits;
+
+impl Compression for Packbits {
+ const COMPRESSION_METHOD: CompressionMethod = CompressionMethod::PackBits;
+
+ fn get_algorithm(&self) -> Compressor {
+ Compressor::Packbits(*self)
+ }
+}
+
+impl CompressionAlgorithm for Packbits {
+ fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error> {
+ // Inspired by https://github.com/skirridsystems/packbits
+
+ const MIN_REPT: u8 = 3; // Minimum run to compress between differ blocks
+ const MAX_BYTES: u8 = 128; // Maximum number of bytes that can be encoded in a header byte
+
+ // Encoding for header byte based on number of bytes represented.
+ fn encode_diff(n: u8) -> u8 {
+ n - 1
+ }
+ fn encode_rept(n: u8) -> u8 {
+ let var = 256 - (n - 1) as u16;
+ var as u8
+ }
+
+ fn write_u8<W: Write>(writer: &mut W, byte: u8) -> Result<u64, Error> {
+ writer.write(&[byte]).map(|byte_count| byte_count as u64)
+ }
+
+ let mut bufwriter = BufWriter::new(writer);
+ let mut bytes_written = 0u64; // The number of bytes written into the writer
+ let mut offset: Option<u64> = None; // The index of the first byte written into the writer
+
+ let mut src_index: usize = 0; // Index of the current byte
+ let mut src_count = bytes.len(); //The number of bytes remaining to be compressed
+
+ let mut in_run = false; // Indication whether counting of similar bytes is performed
+ let mut run_index = 0u8; // Distance into pending bytes that a run starts
+
+ let mut bytes_pending = 0u8; // Bytes looked at but not yet output
+ let mut pending_index = 0usize; // Index of the first pending byte
+
+ let mut curr_byte: u8; // Byte currently being considered
+ let mut last_byte: u8; // Previous byte
+
+ // Need at least one byte to compress
+ if src_count == 0 {
+ return Err(Error::new(ErrorKind::WriteZero, "write zero"));
+ }
+
+ // Prime compressor with first character.
+ last_byte = bytes[src_index];
+ src_index += 1;
+ bytes_pending += 1;
+
+ while src_count - 1 != 0 {
+ src_count -= 1;
+ curr_byte = bytes[src_index];
+ src_index += 1;
+ bytes_pending += 1;
+
+ if in_run {
+ if (curr_byte != last_byte) || (bytes_pending > MAX_BYTES) {
+ offset.get_or_insert(write_u8(&mut bufwriter, encode_rept(bytes_pending - 1))?);
+ write_u8(&mut bufwriter, last_byte)?;
+ bytes_written += 2;
+
+ bytes_pending = 1;
+ pending_index = src_index - 1;
+ run_index = 0;
+ in_run = false;
+ }
+ } else {
+ if bytes_pending > MAX_BYTES {
+ // We have as much differing data as we can output in one chunk.
+ // Output MAX_BYTES leaving one byte.
+ offset.get_or_insert(write_u8(&mut bufwriter, encode_diff(MAX_BYTES))?);
+ bufwriter.write(&bytes[pending_index..pending_index + MAX_BYTES as usize])?;
+ bytes_written += 1 + MAX_BYTES as u64;
+
+ pending_index += MAX_BYTES as usize;
+ bytes_pending -= MAX_BYTES;
+ run_index = bytes_pending - 1; // A run could start here
+ } else if curr_byte == last_byte {
+ if (bytes_pending - run_index >= MIN_REPT) || (run_index == 0) {
+ // This is a worthwhile run
+ if run_index != 0 {
+ // Flush differing data out of input buffer
+ offset.get_or_insert(write_u8(&mut bufwriter, encode_diff(run_index))?);
+ bufwriter
+ .write(&bytes[pending_index..pending_index + run_index as usize])?;
+ bytes_written += 1 + run_index as u64;
+ }
+ bytes_pending -= run_index; // Length of run
+ in_run = true;
+ }
+ } else {
+ run_index = bytes_pending - 1; // A run could start here
+ }
+ }
+ last_byte = curr_byte;
+ }
+
+ // Output the remainder
+ if in_run {
+ bytes_written += 2;
+ offset.get_or_insert(write_u8(&mut bufwriter, encode_rept(bytes_pending))?);
+ write_u8(&mut bufwriter, last_byte)?;
+ } else {
+ bytes_written += 1 + bytes_pending as u64;
+ offset.get_or_insert(write_u8(&mut bufwriter, encode_diff(bytes_pending))?);
+ bufwriter.write(&bytes[pending_index..pending_index + bytes_pending as usize])?;
+ }
+
+ bufwriter.flush()?;
+ Ok(bytes_written)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::encoder::compression::tests::TEST_DATA;
+ use std::io::Cursor;
+
+ #[test]
+ fn test_packbits_single_byte() {
+ // compress single byte
+ const UNCOMPRESSED_DATA: [u8; 1] = [0x3F];
+ const EXPECTED_COMPRESSED_DATA: [u8; 2] = [0x00, 0x3F];
+
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Packbits::default()
+ .write_to(&mut writer, &UNCOMPRESSED_DATA)
+ .unwrap();
+ assert_eq!(compressed_data, EXPECTED_COMPRESSED_DATA);
+ }
+
+ #[test]
+ fn test_packbits_rept() {
+ // compress buffer with repetitive sequence
+ const UNCOMPRESSED_DATA: &'static [u8] =
+ b"This strrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrring hangs.";
+ const EXPECTED_COMPRESSED_DATA: &'static [u8] = b"\x06This st\xD1r\x09ing hangs.";
+
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Packbits::default()
+ .write_to(&mut writer, UNCOMPRESSED_DATA)
+ .unwrap();
+ assert_eq!(compressed_data, EXPECTED_COMPRESSED_DATA);
+ }
+
+ #[test]
+ fn test_packbits_large_rept_nonrept() {
+ // compress buffer with large repetitive and non-repetitive sequence
+ let mut data = b"This st".to_vec();
+ for _i in 0..158 {
+ data.push(b'r');
+ }
+ data.extend_from_slice(b"ing hangs.");
+ for i in 0..158 {
+ data.push(i);
+ }
+
+ const EXPECTED_COMPRESSED_DATA: [u8; 182] = [
+ 0x06, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x74, 0x81, 0x72, 0xE3, 0x72, 0x7F, 0x69,
+ 0x6E, 0x67, 0x20, 0x68, 0x61, 0x6E, 0x67, 0x73, 0x2E, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
+ 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
+ 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A,
+ 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x27, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81,
+ 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
+ ];
+
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Packbits::default()
+ .write_to(&mut writer, data.as_slice())
+ .unwrap();
+ assert_eq!(compressed_data, EXPECTED_COMPRESSED_DATA);
+ }
+
+ #[test]
+ fn test_packbits() {
+ // compress teststring
+ const EXPECTED_COMPRESSED_DATA: &'static [u8] =
+ b"\x3CThis is a string for checking various compression algorithms.";
+
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Packbits::default()
+ .write_to(&mut writer, TEST_DATA)
+ .unwrap();
+ assert_eq!(compressed_data, EXPECTED_COMPRESSED_DATA);
+ }
+}
diff --git a/vendor/tiff/src/encoder/compression/uncompressed.rs b/vendor/tiff/src/encoder/compression/uncompressed.rs
new file mode 100644
index 0000000..900426f
--- /dev/null
+++ b/vendor/tiff/src/encoder/compression/uncompressed.rs
@@ -0,0 +1,37 @@
+use crate::{encoder::compression::*, tags::CompressionMethod};
+use std::io::Write;
+
+/// The default algorithm which does not compress at all.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+pub struct Uncompressed;
+
+impl Compression for Uncompressed {
+ const COMPRESSION_METHOD: CompressionMethod = CompressionMethod::None;
+
+ fn get_algorithm(&self) -> Compressor {
+ Compressor::Uncompressed(*self)
+ }
+}
+
+impl CompressionAlgorithm for Uncompressed {
+ fn write_to<W: Write>(&mut self, writer: &mut W, bytes: &[u8]) -> Result<u64, io::Error> {
+ writer.write(bytes).map(|byte_count| byte_count as u64)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::encoder::compression::tests::TEST_DATA;
+ use std::io::Cursor;
+
+ #[test]
+ fn test_no_compression() {
+ let mut compressed_data = Vec::<u8>::new();
+ let mut writer = Cursor::new(&mut compressed_data);
+ Uncompressed::default()
+ .write_to(&mut writer, TEST_DATA)
+ .unwrap();
+ assert_eq!(TEST_DATA, compressed_data);
+ }
+}
diff --git a/vendor/tiff/src/encoder/mod.rs b/vendor/tiff/src/encoder/mod.rs
new file mode 100644
index 0000000..6e39c93
--- /dev/null
+++ b/vendor/tiff/src/encoder/mod.rs
@@ -0,0 +1,681 @@
+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
+ }
+}
diff --git a/vendor/tiff/src/encoder/tiff_value.rs b/vendor/tiff/src/encoder/tiff_value.rs
new file mode 100644
index 0000000..43653f4
--- /dev/null
+++ b/vendor/tiff/src/encoder/tiff_value.rs
@@ -0,0 +1,523 @@
+use std::{borrow::Cow, io::Write, slice::from_ref};
+
+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)
+ }
+
+ /// Access this value as an contiguous sequence of bytes.
+ /// If their is no trivial representation, allocate it on the heap.
+ fn data(&self) -> Cow<[u8]>;
+
+ /// Write this value to a TiffWriter.
+ /// While the default implementation will work in all cases, it may require unnecessary allocations.
+ /// The written bytes of any custom implementation MUST be the same as yielded by `self.data()`.
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_bytes(&self.data())?;
+ Ok(())
+ }
+}
+
+impl TiffValue for [u8] {
+ const BYTE_LEN: u8 = 1;
+ const FIELD_TYPE: Type = Type::BYTE;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(self)
+ }
+}
+
+impl TiffValue for [i8] {
+ const BYTE_LEN: u8 = 1;
+ const FIELD_TYPE: Type = Type::SBYTE;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i8_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [u16] {
+ const BYTE_LEN: u8 = 2;
+ const FIELD_TYPE: Type = Type::SHORT;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u16_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [i16] {
+ const BYTE_LEN: u8 = 2;
+ const FIELD_TYPE: Type = Type::SSHORT;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i16_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [u32] {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::LONG;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u32_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [i32] {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::SLONG;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i32_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [u64] {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::LONG8;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u64_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [i64] {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::SLONG8;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i64_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [f32] {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::FLOAT;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ // We write using native endian so this should be safe
+ Cow::Borrowed(bytecast::f32_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for [f64] {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::DOUBLE;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ // We write using native endian so this should be safe
+ Cow::Borrowed(bytecast::f64_as_ne_bytes(self))
+ }
+}
+
+impl TiffValue for u8 {
+ const BYTE_LEN: u8 = 1;
+ const FIELD_TYPE: Type = Type::BYTE;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u8(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(from_ref(self))
+ }
+}
+
+impl TiffValue for i8 {
+ const BYTE_LEN: u8 = 1;
+ const FIELD_TYPE: Type = Type::SBYTE;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_i8(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i8_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for u16 {
+ const BYTE_LEN: u8 = 2;
+ const FIELD_TYPE: Type = Type::SHORT;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u16(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u16_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for i16 {
+ const BYTE_LEN: u8 = 2;
+ const FIELD_TYPE: Type = Type::SSHORT;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_i16(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i16_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for u32 {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::LONG;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u32(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u32_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for i32 {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::SLONG;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_i32(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i32_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for u64 {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::LONG8;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u64(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u64_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for i64 {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::SLONG8;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_i64(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::i64_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for f32 {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::FLOAT;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_f32(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::f32_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for f64 {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::DOUBLE;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_f64(*self)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::f64_as_ne_bytes(from_ref(self)))
+ }
+}
+
+impl TiffValue for Ifd {
+ const BYTE_LEN: u8 = 4;
+ const FIELD_TYPE: Type = Type::IFD;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u32(self.0)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u32_as_ne_bytes(from_ref(&self.0)))
+ }
+}
+
+impl TiffValue for Ifd8 {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::IFD8;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u64(self.0)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Borrowed(bytecast::u64_as_ne_bytes(from_ref(&self.0)))
+ }
+}
+
+impl TiffValue for Rational {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::RATIONAL;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_u32(self.n)?;
+ writer.write_u32(self.d)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Owned({
+ let first_dword = bytecast::u32_as_ne_bytes(from_ref(&self.n));
+ let second_dword = bytecast::u32_as_ne_bytes(from_ref(&self.d));
+ [first_dword, second_dword].concat()
+ })
+ }
+}
+
+impl TiffValue for SRational {
+ const BYTE_LEN: u8 = 8;
+ const FIELD_TYPE: Type = Type::SRATIONAL;
+
+ fn count(&self) -> usize {
+ 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ writer.write_i32(self.n)?;
+ writer.write_i32(self.d)?;
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Owned({
+ let first_dword = bytecast::i32_as_ne_bytes(from_ref(&self.n));
+ let second_dword = bytecast::i32_as_ne_bytes(from_ref(&self.d));
+ [first_dword, second_dword].concat()
+ })
+ }
+}
+
+impl TiffValue for str {
+ const BYTE_LEN: u8 = 1;
+ const FIELD_TYPE: Type = Type::ASCII;
+
+ fn count(&self) -> usize {
+ self.len() + 1
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> 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))
+ }
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ Cow::Owned({
+ if self.is_ascii() && !self.bytes().any(|b| b == 0) {
+ let bytes: &[u8] = self.as_bytes();
+ [bytes, &[0]].concat()
+ } else {
+ vec![]
+ }
+ })
+ }
+}
+
+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<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ (*self).write(writer)
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ T::data(self)
+ }
+}
+
+macro_rules! impl_tiff_value_for_contiguous_sequence {
+ ($inner_type:ty; $bytes:expr; $field_type:expr) => {
+ impl $crate::encoder::TiffValue for [$inner_type] {
+ const BYTE_LEN: u8 = $bytes;
+ const FIELD_TYPE: Type = $field_type;
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+
+ fn write<W: Write>(&self, writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ for x in self {
+ x.write(writer)?;
+ }
+ Ok(())
+ }
+
+ fn data(&self) -> Cow<[u8]> {
+ let mut buf: Vec<u8> = Vec::with_capacity(Self::BYTE_LEN as usize * self.len());
+ for x in self {
+ buf.extend_from_slice(&x.data());
+ }
+ Cow::Owned(buf)
+ }
+ }
+ };
+}
+
+impl_tiff_value_for_contiguous_sequence!(Ifd; 4; Type::IFD);
+impl_tiff_value_for_contiguous_sequence!(Ifd8; 8; Type::IFD8);
+impl_tiff_value_for_contiguous_sequence!(Rational; 8; Type::RATIONAL);
+impl_tiff_value_for_contiguous_sequence!(SRational; 8; Type::SRATIONAL);
+
+/// 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/vendor/tiff/src/encoder/writer.rs b/vendor/tiff/src/encoder/writer.rs
new file mode 100644
index 0000000..c5139e9
--- /dev/null
+++ b/vendor/tiff/src/encoder/writer.rs
@@ -0,0 +1,188 @@
+use crate::encoder::compression::*;
+use crate::error::TiffResult;
+use std::io::{self, Seek, SeekFrom, Write};
+
+pub fn write_tiff_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
+ #[cfg(target_endian = "little")]
+ let boi: u8 = 0x49;
+ #[cfg(not(target_endian = "little"))]
+ let boi: u8 = 0x4d;
+
+ writer.writer.write_all(&[boi, boi])?;
+ writer.writer.write_all(&42u16.to_ne_bytes())?;
+ writer.offset += 4;
+
+ 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<W: Write>(writer: &mut TiffWriter<W>) -> 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<W> {
+ writer: W,
+ offset: u64,
+ byte_count: u64,
+ compressor: Compressor,
+}
+
+impl<W: Write> TiffWriter<W> {
+ pub fn new(writer: W) -> Self {
+ Self {
+ writer,
+ offset: 0,
+ byte_count: 0,
+ compressor: Compressor::default(),
+ }
+ }
+
+ pub fn set_compression(&mut self, compressor: Compressor) {
+ self.compressor = compressor;
+ }
+
+ pub fn reset_compression(&mut self) {
+ self.compressor = Compressor::default();
+ }
+
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+
+ pub fn last_written(&self) -> u64 {
+ self.byte_count
+ }
+
+ pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), io::Error> {
+ self.byte_count = self.compressor.write_to(&mut self.writer, bytes)?;
+ self.offset += self.byte_count;
+ Ok(())
+ }
+
+ pub fn write_u8(&mut self, n: u8) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+ Ok(())
+ }
+
+ pub fn write_i8(&mut self, n: i8) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+ Ok(())
+ }
+
+ pub fn write_u16(&mut self, n: u16) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_i16(&mut self, n: i16) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_u32(&mut self, n: u32) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_i32(&mut self, n: i32) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_u64(&mut self, n: u64) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_i64(&mut self, n: i64) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &n.to_ne_bytes())?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_f32(&mut self, n: f32) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &u32::to_ne_bytes(n.to_bits()))?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn write_f64(&mut self, n: f64) -> Result<(), io::Error> {
+ self.byte_count = self
+ .compressor
+ .write_to(&mut self.writer, &u64::to_ne_bytes(n.to_bits()))?;
+ self.offset += self.byte_count;
+
+ Ok(())
+ }
+
+ pub fn pad_word_boundary(&mut self) -> Result<(), io::Error> {
+ if self.offset % 4 != 0 {
+ let padding = [0, 0, 0];
+ let padd_len = 4 - (self.offset % 4);
+ self.writer.write_all(&padding[..padd_len as usize])?;
+ self.offset += padd_len;
+ }
+
+ Ok(())
+ }
+}
+
+impl<W: Seek> TiffWriter<W> {
+ pub fn goto_offset(&mut self, offset: u64) -> Result<(), io::Error> {
+ self.offset = offset;
+ self.writer.seek(SeekFrom::Start(offset as u64))?;
+ Ok(())
+ }
+}