Coverage Report

Created: 2026-01-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tiff-0.10.3/src/encoder/mod.rs
Line
Count
Source
1
pub use tiff_value::*;
2
3
use std::{
4
    cmp,
5
    io::{self, Seek, Write},
6
    marker::PhantomData,
7
    mem,
8
    num::{NonZeroU64, TryFromIntError},
9
};
10
11
use crate::{
12
    decoder::ifd::Entry,
13
    error::{TiffResult, UsageError},
14
    tags::{CompressionMethod, IfdPointer, ResolutionUnit, SampleFormat, Tag, Type},
15
    Directory, TiffError, TiffFormatError,
16
};
17
18
pub mod colortype;
19
pub mod compression;
20
mod tiff_value;
21
mod writer;
22
23
use self::colortype::*;
24
use self::compression::Compression as Comp;
25
use self::compression::*;
26
use self::writer::*;
27
28
/// Type of prediction to prepare the image with.
29
///
30
/// Image data can be very unpredictable, and thus very hard to compress. Predictors are simple
31
/// passes ran over the image data to prepare it for compression. This is mostly used for LZW
32
/// compression, where using [Predictor::Horizontal] we see a 35% improvement in compression
33
/// ratio over the unpredicted compression !
34
///
35
/// [Predictor::FloatingPoint] is currently not supported.
36
pub type Predictor = crate::tags::Predictor;
37
#[cfg(feature = "deflate")]
38
pub type DeflateLevel = compression::DeflateLevel;
39
40
#[derive(Clone, Copy, PartialEq)]
41
pub enum Compression {
42
    Uncompressed,
43
    #[cfg(feature = "lzw")]
44
    Lzw,
45
    #[cfg(feature = "deflate")]
46
    Deflate(DeflateLevel),
47
    Packbits,
48
}
49
50
impl Default for Compression {
51
0
    fn default() -> Self {
52
0
        Self::Uncompressed
53
0
    }
54
}
55
56
impl Compression {
57
0
    fn tag(&self) -> CompressionMethod {
58
0
        match self {
59
0
            Compression::Uncompressed => CompressionMethod::None,
60
            #[cfg(feature = "lzw")]
61
0
            Compression::Lzw => CompressionMethod::LZW,
62
            #[cfg(feature = "deflate")]
63
0
            Compression::Deflate(_) => CompressionMethod::Deflate,
64
0
            Compression::Packbits => CompressionMethod::PackBits,
65
        }
66
0
    }
67
68
0
    fn get_algorithm(&self) -> Compressor {
69
0
        match self {
70
0
            Compression::Uncompressed => compression::Uncompressed {}.get_algorithm(),
71
            #[cfg(feature = "lzw")]
72
0
            Compression::Lzw => compression::Lzw {}.get_algorithm(),
73
            #[cfg(feature = "deflate")]
74
0
            Compression::Deflate(level) => compression::Deflate::with_level(*level).get_algorithm(),
75
0
            Compression::Packbits => compression::Packbits {}.get_algorithm(),
76
        }
77
0
    }
78
}
79
80
/// Encoder for Tiff and BigTiff files.
81
///
82
/// With this type you can get a `DirectoryEncoder` or a `ImageEncoder`
83
/// to encode Tiff/BigTiff ifd directories with images.
84
///
85
/// See `DirectoryEncoder` and `ImageEncoder`.
86
///
87
/// # Examples
88
/// ```
89
/// # extern crate tiff;
90
/// # fn main() {
91
/// # let mut file = std::io::Cursor::new(Vec::new());
92
/// # let image_data = vec![0; 100*100*3];
93
/// use tiff::encoder::*;
94
///
95
/// // create a standard Tiff file
96
/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
97
/// tiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap();
98
///
99
/// // create a BigTiff file
100
/// let mut bigtiff = TiffEncoder::new_big(&mut file).unwrap();
101
/// bigtiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap();
102
///
103
/// # }
104
/// ```
105
pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> {
106
    writer: TiffWriter<W>,
107
    kind: PhantomData<K>,
108
    predictor: Predictor,
109
    compression: Compression,
110
    /// The offset of the last main image directory's `next` field.
111
    last_ifd_chain: NonZeroU64,
112
}
113
114
/// Constructor functions to create standard Tiff files.
115
impl<W: Write + Seek> TiffEncoder<W> {
116
    /// Creates a new encoder for standard Tiff files.
117
    ///
118
    /// To create BigTiff files, use [`new_big`][TiffEncoder::new_big] or
119
    /// [`new_generic`][TiffEncoder::new_generic].
120
0
    pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> {
121
0
        TiffEncoder::new_generic(writer)
122
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_>>::new
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
123
}
124
125
/// Constructor functions to create BigTiff files.
126
impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> {
127
    /// Creates a new encoder for BigTiff files.
128
    ///
129
    /// To create standard Tiff files, use [`new`][TiffEncoder::new] or
130
    /// [`new_generic`][TiffEncoder::new_generic].
131
0
    pub fn new_big(writer: W) -> TiffResult<Self> {
132
0
        TiffEncoder::new_generic(writer)
133
0
    }
134
}
135
136
/// Generic functions that are available for both Tiff and BigTiff encoders.
137
impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
138
    /// Creates a new Tiff or BigTiff encoder, inferred from the return type.
139
0
    pub fn new_generic(writer: W) -> TiffResult<Self> {
140
0
        let mut writer = TiffWriter::new(writer);
141
0
        K::write_header(&mut writer)?;
142
143
0
        let last_ifd_chain = NonZeroU64::new(writer.previous_ifd_pointer::<K>())
144
0
            .expect("Header is at a non-zero offset");
145
146
0
        Ok(TiffEncoder {
147
0
            writer,
148
0
            kind: PhantomData,
149
0
            predictor: Predictor::None,
150
0
            compression: Compression::Uncompressed,
151
0
            last_ifd_chain,
152
0
        })
153
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::new_generic
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_generic
154
155
    /// Set the predictor to use
156
    ///
157
    /// A predictor is used to simplify the file before writing it. This is very
158
    /// useful when writing a file compressed using LZW as it can improve efficiency
159
0
    pub fn with_predictor(mut self, predictor: Predictor) -> Self {
160
0
        self.predictor = predictor;
161
162
0
        self
163
0
    }
164
165
    /// Set the compression method to use
166
0
    pub fn with_compression(mut self, compression: Compression) -> Self {
167
0
        self.compression = compression;
168
169
0
        self
170
0
    }
171
172
    /// Create a [`DirectoryEncoder`] to encode an ifd directory.
173
    #[deprecated = "`image_directory` replaced the old behavior and clarifies the intent"]
174
    #[doc(hidden)]
175
0
    pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
176
0
        Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
177
0
    }
178
179
    /// Create a [`DirectoryEncoder`] to encode an ifd directory.
180
    ///
181
    /// The caller is responsible for ensuring that the directory is a valid image in the main TIFF
182
    /// IFD sequence. To encode additional directories that are not linked into the sequence, use
183
    /// [`Self::extra_directory`][TiffEncoder::extra_directory].
184
0
    pub fn image_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
185
0
        Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
186
0
    }
187
188
    /// Create a [`DirectoryEncoder`] to encode an ifd directory.
189
    ///
190
    /// The directory is not linked into the sequence of directories. For instance, encode Exif
191
    /// directories or SubIfd directories with this method.
192
0
    pub fn extra_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
193
0
        Self::unchained_directory(&mut self.writer)
194
0
    }
195
196
    /// Create an [`ImageEncoder`] to encode an image one slice at a time.
197
0
    pub fn new_image<C: ColorType>(
198
0
        &mut self,
199
0
        width: u32,
200
0
        height: u32,
201
0
    ) -> TiffResult<ImageEncoder<'_, W, C, K>> {
202
0
        let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
203
0
        ImageEncoder::new(encoder, width, height, self.compression, self.predictor)
204
0
    }
205
206
    /// Convenience function to write an entire image from memory.
207
0
    pub fn write_image<C: ColorType>(
208
0
        &mut self,
209
0
        width: u32,
210
0
        height: u32,
211
0
        data: &[C::Inner],
212
0
    ) -> TiffResult<()>
213
0
    where
214
0
        [C::Inner]: TiffValue,
215
    {
216
0
        let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
217
0
        let image: ImageEncoder<W, C, K> =
218
0
            ImageEncoder::new(encoder, width, height, self.compression, self.predictor)?;
219
0
        image.write_data(data)
220
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::write_image::<_>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGB32Float>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGBA32Float>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGB8>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::Gray8>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGB16>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGBA8>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::Gray16>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_image::<tiff::encoder::colortype::RGBA16>
221
222
0
    fn chain_directory<'lt>(
223
0
        writer: &'lt mut TiffWriter<W>,
224
0
        last_ifd_chain: &'lt mut NonZeroU64,
225
0
    ) -> TiffResult<DirectoryEncoder<'lt, W, K>> {
226
0
        let last_ifd = *last_ifd_chain;
227
0
        DirectoryEncoder::new(writer, Some(last_ifd), Some(last_ifd_chain))
228
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::chain_directory
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::chain_directory
229
230
0
    fn unchained_directory(writer: &mut TiffWriter<W>) -> TiffResult<DirectoryEncoder<'_, W, K>> {
231
0
        DirectoryEncoder::new(writer, None, None)
232
0
    }
233
}
234
235
/// Low level interface to encode ifd directories.
236
///
237
/// You should call `finish` on this when you are finished with it.
238
/// Encoding can silently fail while this is dropping.
239
pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
240
    writer: &'a mut TiffWriter<W>,
241
    /// The position of the previous directory's `next` field, if any.
242
    chained_ifd_pos: Option<NonZeroU64>,
243
    /// An output to write the `next` field offset on completion.
244
    write_chain: Option<&'a mut NonZeroU64>,
245
    kind: PhantomData<K>,
246
    // We use BTreeMap to make sure tags are written in correct order
247
    directory: Directory,
248
    dropped: bool,
249
}
250
251
/// The offset of an encoded directory in the file.
252
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
253
pub struct DirectoryOffset<K: TiffKind> {
254
    /// The start of the directory as a Tiff value.
255
    ///
256
    /// This is a bit of a wart in the strongly typed design of the encoder. The value _type_ must
257
    /// itself know how to be represented in the Tiff file but that may differ based on endianess
258
    /// as well as the offset size (`u32` or BigTIFF's `u64`). Thankfully we're allowed to
259
    /// represent offsets with `LONG` or `IFD` in the usual case.
260
    pub offset: K::OffsetType,
261
    /// The start of the directory as a pure offset.
262
    pub pointer: IfdPointer,
263
    /// The offset of its sequence link field, in our private representation.
264
    ifd_chain: NonZeroU64,
265
    /// The kind of Tiff file the offset is for.
266
    kind: PhantomData<K>,
267
}
268
269
impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
270
    /// Construct a directory writer appending to data, assuming the writer is currently positioned
271
    /// immediately after a previously written IFD to which to append.
272
0
    fn new(
273
0
        writer: &'a mut TiffWriter<W>,
274
0
        chained_ifd_pos: Option<NonZeroU64>,
275
0
        chain_into: Option<&'a mut NonZeroU64>,
276
0
    ) -> TiffResult<Self> {
277
0
        writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff?
278
0
        Ok(Self {
279
0
            writer,
280
0
            chained_ifd_pos,
281
0
            write_chain: chain_into,
282
0
            kind: PhantomData,
283
0
            directory: Directory::empty(),
284
0
            dropped: false,
285
0
        })
286
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::new
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::new
287
288
    /// Write a single ifd tag.
289
0
    pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> {
290
        // Encodes the value if necessary. In the current bytes all integers are taken as native
291
        // endian and thus transparent but this keeps the interface generic.
292
0
        let mut bytes = Vec::with_capacity(value.bytes());
293
        {
294
0
            let mut writer = TiffWriter::new(&mut bytes);
295
0
            value.write(&mut writer)?;
296
        }
297
298
0
        let entry = Self::write_value(
299
0
            self.writer,
300
            &DirectoryEntry {
301
                data_type: <T>::FIELD_TYPE,
302
0
                count: value.count().try_into()?,
303
0
                data: bytes,
304
            },
305
0
        )?;
306
307
0
        self.directory.extend([(tag, entry)]);
308
309
0
        Ok(())
310
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_tag::<_>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<tiff::encoder::tiff_value::Rational>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<&[u32]>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<&[u16]>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<u32>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<u16>
311
312
    /// Write some data to the tiff file, the offset of the data is returned.
313
    ///
314
    /// This could be used to write tiff strips.
315
0
    pub fn write_data<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> {
316
0
        let offset = self.writer.offset();
317
0
        value.write(self.writer)?;
318
0
        Ok(offset)
319
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_data::<_>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_data::<&[f32]>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_data::<&[u8]>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_data::<&[u16]>
320
321
    /// Define the parent directory.
322
    ///
323
    /// Each directory has an offset based link to its successor, forming a linked list in the
324
    /// file. The encoder writes its own offset into the parent's field when [`Self::finish`] is
325
    /// called or it is dropped. This redefines the parent. An offset representation of the parent
326
    /// must be acquired by finishing it with [`Self::finish_with_offsets`].
327
0
    pub fn set_parent(&mut self, offset: &DirectoryOffset<K>) {
328
0
        self.chained_ifd_pos = Some(offset.ifd_chain);
329
0
    }
330
331
    /// Write out the ifd directory itself.
332
0
    pub fn finish(mut self) -> TiffResult<()> {
333
0
        self.finish_internal()?;
334
0
        Ok(())
335
0
    }
336
337
0
    pub fn finish_with_offsets(mut self) -> TiffResult<DirectoryOffset<K>> {
338
0
        self.finish_internal()
339
0
    }
340
341
0
    fn write_directory(&mut self) -> TiffResult<u64> {
342
        // Start by turning all buffered unwritten values into entries.
343
0
        let offset = self.writer.offset();
344
0
        K::write_entry_count(self.writer, self.directory.len())?;
345
346
0
        let offset_bytes = mem::size_of::<K::OffsetType>();
347
0
        for (tag, entry) in self.directory.iter() {
348
0
            self.writer.write_u16(tag.to_u16())?;
349
0
            self.writer.write_u16(entry.field_type().to_u16())?;
350
0
            let count = K::convert_offset(entry.count())?;
351
0
            count.write(self.writer)?;
352
0
            self.writer.write_bytes(&entry.offset()[..offset_bytes])?;
353
        }
354
355
0
        Ok(offset)
356
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_directory
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_directory
357
358
0
    fn write_value(
359
0
        writer: &mut TiffWriter<W>,
360
0
        value: &DirectoryEntry<K::OffsetType>,
361
0
    ) -> TiffResult<Entry> {
362
        let &DirectoryEntry {
363
0
            data: ref bytes,
364
0
            ref count,
365
0
            data_type,
366
0
        } = value;
367
368
0
        let in_entry_bytes = mem::size_of::<K::OffsetType>();
369
0
        let mut offset_bytes = [0; 8];
370
371
0
        if bytes.len() > in_entry_bytes {
372
0
            let offset = writer.offset();
373
0
            writer.write_bytes(bytes)?;
374
375
0
            let offset = K::convert_offset(offset)?;
376
0
            offset_bytes[..offset.bytes()].copy_from_slice(&offset.data());
377
0
        } else {
378
0
            // Note: we have indicated our native byte order in the header, hence this
379
0
            // corresponds to our byte order no matter the value type.
380
0
            offset_bytes[..bytes.len()].copy_from_slice(bytes);
381
0
        }
382
383
        // Undoing some hidden type. Offset is either u32 or u64. Due to the trait API being public
384
        // and some oversight, we can not clone the `count: K::OffsetType` and thus not convert it.
385
        // Instead, write it to a buffer...
386
0
        let mut count_bytes = [0; 8];
387
        // Nominally Cow but we only expect `Cow::Borrowed`.
388
0
        count_bytes[..count.bytes()].copy_from_slice(&count.data());
389
390
0
        Ok(if in_entry_bytes == 4 {
391
0
            let count = u32::from_ne_bytes(count_bytes[..4].try_into().unwrap());
392
0
            Entry::new(data_type, count, offset_bytes[..4].try_into().unwrap())
393
        } else {
394
0
            debug_assert_eq!(in_entry_bytes, 8);
395
0
            let count = u64::from_ne_bytes(count_bytes);
396
0
            Entry::new_u64(data_type, count, offset_bytes)
397
        })
398
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_value
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_value
399
400
    /// Provides the number of bytes written by the underlying TiffWriter during the last call.
401
0
    fn last_written(&self) -> u64 {
402
0
        self.writer.last_written()
403
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::last_written
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::last_written
404
405
0
    fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
406
0
        let ifd_pointer = self.write_directory()?;
407
0
        let offset = K::convert_offset(ifd_pointer)?;
408
409
0
        if let Some(prior) = self.chained_ifd_pos {
410
0
            let curr_pos = self.writer.offset();
411
412
0
            self.writer.goto_offset(prior.get())?;
413
            // Note how we are not writing the `offset` type itself here as doing so would need to
414
            // go through the `TiffValue` trait—the type is not constrained by much. But for the
415
            // trait we need a `TiffWriter` which comes with a bunch of additional state such as
416
            // compressor etc. that we have no need for.
417
0
            K::write_offset(self.writer, ifd_pointer)?;
418
419
0
            self.writer.goto_offset(curr_pos)?;
420
0
        }
421
422
0
        K::write_offset(self.writer, 0)?;
423
424
0
        let ifd_chain = NonZeroU64::new(self.writer.previous_ifd_pointer::<K>())
425
0
            .expect("IFD chain field is at a non-zero offset");
426
427
0
        if let Some(prior) = self.write_chain.take() {
428
0
            *prior = ifd_chain;
429
0
        }
430
431
0
        self.dropped = true;
432
433
0
        Ok(DirectoryOffset {
434
0
            pointer: IfdPointer(ifd_pointer),
435
0
            offset,
436
0
            ifd_chain,
437
0
            kind: PhantomData,
438
0
        })
439
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::finish_internal
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::finish_internal
440
}
441
442
impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> {
443
0
    fn drop(&mut self) {
444
0
        if !self.dropped {
445
0
            let _ = self.finish_internal();
446
0
        }
447
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
448
}
449
450
/// Type to encode images strip by strip.
451
///
452
/// You should call `finish` on this when you are finished with it.
453
/// Encoding can silently fail while this is dropping.
454
///
455
/// # Examples
456
/// ```
457
/// # extern crate tiff;
458
/// # fn main() {
459
/// # let mut file = std::io::Cursor::new(Vec::new());
460
/// # let image_data = vec![0; 100*100*3];
461
/// use tiff::encoder::*;
462
/// use tiff::tags::Tag;
463
///
464
/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
465
/// let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap();
466
///
467
/// // You can encode tags here
468
/// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap();
469
///
470
/// // Strip size can be configured before writing data
471
/// image.rows_per_strip(2).unwrap();
472
///
473
/// let mut idx = 0;
474
/// while image.next_strip_sample_count() > 0 {
475
///     let sample_count = image.next_strip_sample_count() as usize;
476
///     image.write_strip(&image_data[idx..idx+sample_count]).unwrap();
477
///     idx += sample_count;
478
/// }
479
/// image.finish().unwrap();
480
/// # }
481
/// ```
482
/// You can also call write_data function wich will encode by strip and finish
483
pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType, K: TiffKind> {
484
    encoder: DirectoryEncoder<'a, W, K>,
485
    strip_idx: u64,
486
    strip_count: u64,
487
    row_samples: u64,
488
    width: u32,
489
    height: u32,
490
    rows_per_strip: u64,
491
    strip_offsets: Vec<K::OffsetType>,
492
    strip_byte_count: Vec<K::OffsetType>,
493
    dropped: bool,
494
    compression: Compression,
495
    predictor: Predictor,
496
    _phantom: ::std::marker::PhantomData<C>,
497
}
498
499
impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> {
500
0
    fn sanity_check(compression: Compression, predictor: Predictor) -> TiffResult<()> {
501
0
        match (predictor, compression, T::SAMPLE_FORMAT[0]) {
502
            (Predictor::Horizontal, _, SampleFormat::IEEEFP | SampleFormat::Void) => {
503
0
                Err(TiffError::UsageError(UsageError::PredictorIncompatible))
504
            }
505
            (Predictor::FloatingPoint, _, _) => {
506
0
                Err(TiffError::UsageError(UsageError::PredictorUnavailable))
507
            }
508
0
            _ => Ok(()),
509
        }
510
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::sanity_check
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::sanity_check
511
512
0
    fn new(
513
0
        mut encoder: DirectoryEncoder<'a, W, K>,
514
0
        width: u32,
515
0
        height: u32,
516
0
        compression: Compression,
517
0
        predictor: Predictor,
518
0
    ) -> TiffResult<Self> {
519
0
        if width == 0 || height == 0 {
520
0
            return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions(
521
0
                width, height,
522
0
            )));
523
0
        }
524
525
0
        Self::sanity_check(compression, predictor)?;
526
527
0
        let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?;
528
0
        let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
529
530
        // Limit the strip size to prevent potential memory and security issues.
531
        // Also keep the multiple strip handling 'oiled'
532
0
        let rows_per_strip = {
533
0
            match compression.tag() {
534
0
                CompressionMethod::PackBits => 1, // Each row must be packed separately. Do not compress across row boundaries
535
0
                _ => 1_000_000_u64.div_ceil(row_bytes),
536
            }
537
        };
538
539
0
        let strip_count = u64::from(height).div_ceil(rows_per_strip);
540
541
0
        encoder.write_tag(Tag::ImageWidth, width)?;
542
0
        encoder.write_tag(Tag::ImageLength, height)?;
543
0
        encoder.write_tag(Tag::Compression, compression.tag().to_u16())?;
544
0
        encoder.write_tag(Tag::Predictor, predictor.to_u16())?;
545
546
0
        encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?;
547
0
        let sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect();
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::new::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::new::{closure#0}
548
0
        encoder.write_tag(Tag::SampleFormat, &sample_format[..])?;
549
0
        encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?;
550
551
0
        encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?;
552
553
0
        encoder.write_tag(
554
0
            Tag::SamplesPerPixel,
555
0
            u16::try_from(<T>::BITS_PER_SAMPLE.len())?,
556
0
        )?;
557
0
        encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?;
558
0
        encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?;
559
0
        encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?;
560
561
0
        Ok(ImageEncoder {
562
0
            encoder,
563
0
            strip_count,
564
0
            strip_idx: 0,
565
0
            row_samples,
566
0
            rows_per_strip,
567
0
            width,
568
0
            height,
569
0
            strip_offsets: Vec::new(),
570
0
            strip_byte_count: Vec::new(),
571
0
            dropped: false,
572
0
            compression,
573
0
            predictor,
574
0
            _phantom: ::std::marker::PhantomData,
575
0
        })
576
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::new
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::new
577
578
    /// Number of samples the next strip should have.
579
0
    pub fn next_strip_sample_count(&self) -> u64 {
580
0
        if self.strip_idx >= self.strip_count {
581
0
            return 0;
582
0
        }
583
584
0
        let raw_start_row = self.strip_idx * self.rows_per_strip;
585
0
        let start_row = cmp::min(u64::from(self.height), raw_start_row);
586
0
        let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip);
587
588
0
        (end_row - start_row) * self.row_samples
589
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::next_strip_sample_count
590
591
    /// Write a single strip.
592
0
    pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()>
593
0
    where
594
0
        [T::Inner]: TiffValue,
595
    {
596
0
        let samples = self.next_strip_sample_count();
597
0
        if u64::try_from(value.len())? != samples {
598
0
            return Err(io::Error::new(
599
0
                io::ErrorKind::InvalidData,
600
0
                "Slice is wrong size for strip",
601
0
            )
602
0
            .into());
603
0
        }
604
605
        // Write the (possible compressed) data to the encoder.
606
0
        let offset = match self.predictor {
607
0
            Predictor::None => self.encoder.write_data(value)?,
608
            Predictor::Horizontal => {
609
0
                let mut row_result = Vec::with_capacity(value.len());
610
0
                for row in value.chunks_exact(self.row_samples as usize) {
611
0
                    T::horizontal_predict(row, &mut row_result);
612
0
                }
613
0
                self.encoder.write_data(row_result.as_slice())?
614
            }
615
0
            _ => unimplemented!(),
616
        };
617
618
0
        let byte_count = self.encoder.last_written() as usize;
619
620
0
        self.strip_offsets.push(K::convert_offset(offset)?);
621
0
        self.strip_byte_count.push(byte_count.try_into()?);
622
623
0
        self.strip_idx += 1;
624
0
        Ok(())
625
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::write_strip
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::write_strip
626
627
    /// Write strips from data
628
0
    pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()>
629
0
    where
630
0
        [T::Inner]: TiffValue,
631
    {
632
0
        let num_pix = usize::try_from(self.width)?
633
0
            .checked_mul(usize::try_from(self.height)?)
634
0
            .ok_or_else(|| {
635
0
                io::Error::new(
636
0
                    io::ErrorKind::InvalidInput,
637
                    "Image width * height exceeds usize",
638
                )
639
0
            })?;
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::write_data::{closure#0}
640
0
        if data.len() < num_pix {
641
0
            return Err(io::Error::new(
642
0
                io::ErrorKind::InvalidData,
643
0
                "Input data slice is undersized for provided dimensions",
644
0
            )
645
0
            .into());
646
0
        }
647
648
0
        self.encoder
649
0
            .writer
650
0
            .set_compression(self.compression.get_algorithm());
651
652
0
        let mut idx = 0;
653
0
        while self.next_strip_sample_count() > 0 {
654
0
            let sample_count = usize::try_from(self.next_strip_sample_count())?;
655
0
            self.write_strip(&data[idx..idx + sample_count])?;
656
0
            idx += sample_count;
657
        }
658
659
0
        self.encoder.writer.reset_compression();
660
0
        self.finish()?;
661
0
        Ok(())
662
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::write_data
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::write_data
663
664
    /// Set image resolution
665
0
    pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
666
0
        self.encoder
667
0
            .write_tag(Tag::ResolutionUnit, unit.to_u16())
668
0
            .unwrap();
669
0
        self.encoder
670
0
            .write_tag(Tag::XResolution, value.clone())
671
0
            .unwrap();
672
0
        self.encoder.write_tag(Tag::YResolution, value).unwrap();
673
0
    }
674
675
    /// Set image resolution unit
676
0
    pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
677
0
        self.encoder
678
0
            .write_tag(Tag::ResolutionUnit, unit.to_u16())
679
0
            .unwrap();
680
0
    }
681
682
    /// Set image x-resolution
683
0
    pub fn x_resolution(&mut self, value: Rational) {
684
0
        self.encoder.write_tag(Tag::XResolution, value).unwrap();
685
0
    }
686
687
    /// Set image y-resolution
688
0
    pub fn y_resolution(&mut self, value: Rational) {
689
0
        self.encoder.write_tag(Tag::YResolution, value).unwrap();
690
0
    }
691
692
    /// Set image number of lines per strip
693
    ///
694
    /// This function needs to be called before any calls to `write_data` or
695
    /// `write_strip` and will return an error otherwise.
696
0
    pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> {
697
0
        if self.strip_idx != 0 {
698
0
            return Err(io::Error::new(
699
0
                io::ErrorKind::InvalidInput,
700
0
                "Cannot change strip size after data was written",
701
0
            )
702
0
            .into());
703
0
        }
704
        // Write tag as 32 bits
705
0
        self.encoder.write_tag(Tag::RowsPerStrip, value)?;
706
707
0
        let value: u64 = value as u64;
708
0
        self.strip_count = (self.height as u64).div_ceil(value);
709
0
        self.rows_per_strip = value;
710
711
0
        Ok(())
712
0
    }
713
714
0
    fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
715
0
        self.encoder
716
0
            .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?;
717
0
        self.encoder.write_tag(
718
0
            Tag::StripByteCounts,
719
0
            K::convert_slice(&self.strip_byte_count),
720
0
        )?;
721
0
        self.dropped = true;
722
723
0
        self.encoder.finish_internal()
724
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::finish_internal
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::finish_internal
725
726
    /// Get a reference of the underlying `DirectoryEncoder`
727
0
    pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> {
728
0
        &mut self.encoder
729
0
    }
730
731
    /// Write out image and ifd directory.
732
0
    pub fn finish(mut self) -> TiffResult<()> {
733
0
        self.finish_internal()?;
734
0
        Ok(())
735
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::finish
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::finish
736
}
737
738
impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W, C, K> {
739
0
    fn drop(&mut self) {
740
0
        if !self.dropped {
741
0
            let _ = self.finish_internal();
742
0
        }
743
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard> as core::ops::drop::Drop>::drop
744
}
745
746
struct DirectoryEntry<S> {
747
    data_type: Type,
748
    count: S,
749
    data: Vec<u8>,
750
}
751
752
/// Trait to abstract over Tiff/BigTiff differences.
753
///
754
/// Implemented for [`TiffKindStandard`] and [`TiffKindBig`].
755
pub trait TiffKind {
756
    /// The type of offset fields, `u32` for normal Tiff, `u64` for BigTiff.
757
    type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue;
758
759
    /// Needed for the `convert_slice` method.
760
    type OffsetArrayType: ?Sized + TiffValue;
761
762
    /// Write the (Big)Tiff header.
763
    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
764
765
    /// Convert a file offset to `Self::OffsetType`.
766
    ///
767
    /// This returns an error for normal Tiff if the offset is larger than `u32::MAX`.
768
    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>;
769
770
    /// Write an offset value to the given writer.
771
    ///
772
    /// Like `convert_offset`, this errors if `offset > u32::MAX` for normal Tiff.
773
    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>;
774
775
    /// Write the IFD entry count field with the given `count` value.
776
    ///
777
    /// The entry count field is an `u16` for normal Tiff and `u64` for BigTiff. Errors
778
    /// if the given `usize` is larger than the representable values.
779
    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>;
780
781
    /// Internal helper method for satisfying Rust's type checker.
782
    ///
783
    /// The `TiffValue` trait is implemented for both primitive values (e.g. `u8`, `u32`) and
784
    /// slices of primitive values (e.g. `[u8]`, `[u32]`). However, this is not represented in
785
    /// the type system, so there is no guarantee that that for all `T: TiffValue` there is also
786
    /// an implementation of `TiffValue` for `[T]`. This method works around that problem by
787
    /// providing a conversion from `[T]` to some value that implements `TiffValue`, thereby
788
    /// making all slices of `OffsetType` usable with `write_tag` and similar methods.
789
    ///
790
    /// Implementations of this trait should always set `OffsetArrayType` to `[OffsetType]`.
791
    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType;
792
}
793
794
/// Create a standard Tiff file.
795
pub struct TiffKindStandard;
796
797
impl TiffKind for TiffKindStandard {
798
    type OffsetType = u32;
799
    type OffsetArrayType = [u32];
800
801
0
    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
802
0
        write_tiff_header(writer)?;
803
        // blank the IFD offset location
804
0
        writer.write_u32(0)?;
805
806
0
        Ok(())
807
0
    }
Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_header::<_>
Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_header::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
808
809
0
    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
810
0
        Ok(Self::OffsetType::try_from(offset)?)
811
0
    }
812
813
0
    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
814
0
        writer.write_u32(u32::try_from(offset)?)?;
815
0
        Ok(())
816
0
    }
Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_offset::<_>
Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_offset::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
817
818
0
    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
819
0
        writer.write_u16(u16::try_from(count)?)?;
820
821
0
        Ok(())
822
0
    }
Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_entry_count::<_>
Unexecuted instantiation: <tiff::encoder::TiffKindStandard as tiff::encoder::TiffKind>::write_entry_count::<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>
823
824
0
    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
825
0
        slice
826
0
    }
827
}
828
829
/// Create a BigTiff file.
830
pub struct TiffKindBig;
831
832
impl TiffKind for TiffKindBig {
833
    type OffsetType = u64;
834
    type OffsetArrayType = [u64];
835
836
0
    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
837
0
        write_bigtiff_header(writer)?;
838
        // blank the IFD offset location
839
0
        writer.write_u64(0)?;
840
841
0
        Ok(())
842
0
    }
843
844
0
    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
845
0
        Ok(offset)
846
0
    }
847
848
0
    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
849
0
        writer.write_u64(offset)?;
850
0
        Ok(())
851
0
    }
852
853
0
    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
854
0
        writer.write_u64(u64::try_from(count)?)?;
855
0
        Ok(())
856
0
    }
857
858
0
    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
859
0
        slice
860
0
    }
861
}