Coverage Report

Created: 2026-03-07 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tiff-0.11.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::{
15
        ByteOrder, CompressionMethod, ExtraSamples, IfdPointer, PhotometricInterpretation,
16
        ResolutionUnit, SampleFormat, Tag, Type, ValueBuffer,
17
    },
18
    Directory, TiffError, TiffFormatError,
19
};
20
21
pub mod colortype;
22
pub mod compression;
23
mod tiff_value;
24
mod writer;
25
26
use self::colortype::*;
27
use self::compression::Compression as Comp;
28
use self::compression::*;
29
use self::writer::*;
30
31
/// Type of prediction to prepare the image with.
32
///
33
/// Image data can be very unpredictable, and thus very hard to compress. Predictors are simple
34
/// passes ran over the image data to prepare it for compression. This is mostly used for LZW
35
/// compression, where using [Predictor::Horizontal] we see a 35% improvement in compression
36
/// ratio over the unpredicted compression !
37
///
38
/// [Predictor::FloatingPoint] is currently not supported.
39
pub type Predictor = crate::tags::Predictor;
40
#[cfg(feature = "deflate")]
41
pub type DeflateLevel = compression::DeflateLevel;
42
43
#[derive(Clone, Copy, PartialEq, Default)]
44
pub enum Compression {
45
    #[default]
46
    Uncompressed,
47
    #[cfg(feature = "lzw")]
48
    Lzw,
49
    #[cfg(feature = "deflate")]
50
    Deflate(DeflateLevel),
51
    Packbits,
52
}
53
54
impl Compression {
55
0
    fn tag(&self) -> CompressionMethod {
56
0
        match self {
57
0
            Compression::Uncompressed => CompressionMethod::None,
58
            #[cfg(feature = "lzw")]
59
0
            Compression::Lzw => CompressionMethod::LZW,
60
            #[cfg(feature = "deflate")]
61
0
            Compression::Deflate(_) => CompressionMethod::Deflate,
62
0
            Compression::Packbits => CompressionMethod::PackBits,
63
        }
64
0
    }
65
66
0
    fn get_algorithm(&self) -> Compressor {
67
0
        match self {
68
0
            Compression::Uncompressed => compression::Uncompressed {}.get_algorithm(),
69
            #[cfg(feature = "lzw")]
70
0
            Compression::Lzw => compression::Lzw {}.get_algorithm(),
71
            #[cfg(feature = "deflate")]
72
0
            Compression::Deflate(level) => compression::Deflate::with_level(*level).get_algorithm(),
73
0
            Compression::Packbits => compression::Packbits {}.get_algorithm(),
74
        }
75
0
    }
76
}
77
78
/// Encoder for Tiff and BigTiff files.
79
///
80
/// With this type you can get a [`DirectoryEncoder`] or a [`ImageEncoder`]
81
/// to encode Tiff/BigTiff ifd directories with images.
82
///
83
/// See [`DirectoryEncoder`] and [`ImageEncoder`].
84
///
85
/// # Examples
86
/// ```
87
/// # extern crate tiff;
88
/// # fn main() {
89
/// # let mut file = std::io::Cursor::new(Vec::new());
90
/// # let image_data = vec![0; 100*100*3];
91
/// use tiff::encoder::*;
92
///
93
/// // create a standard Tiff file
94
/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
95
/// tiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap();
96
///
97
/// // create a BigTiff file
98
/// let mut bigtiff = TiffEncoder::new_big(&mut file).unwrap();
99
/// bigtiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap();
100
///
101
/// # }
102
/// ```
103
pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> {
104
    writer: TiffWriter<W>,
105
    kind: PhantomData<K>,
106
    predictor: Predictor,
107
    compression: Compression,
108
    /// The offset of the last main image directory's `next` field.
109
    last_ifd_chain: NonZeroU64,
110
}
111
112
/// Constructor functions to create standard Tiff files.
113
impl<W: Write + Seek> TiffEncoder<W> {
114
    /// Creates a new encoder for standard Tiff files.
115
    ///
116
    /// To create BigTiff files, use [`new_big`][TiffEncoder::new_big] or
117
    /// [`new_generic`][TiffEncoder::new_generic].
118
0
    pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> {
119
0
        TiffEncoder::new_generic(writer)
120
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_>>::new
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
121
}
122
123
/// Constructor functions to create BigTiff files.
124
impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> {
125
    /// Creates a new encoder for BigTiff files.
126
    ///
127
    /// To create standard Tiff files, use [`new`][TiffEncoder::new] or
128
    /// [`new_generic`][TiffEncoder::new_generic].
129
0
    pub fn new_big(writer: W) -> TiffResult<Self> {
130
0
        TiffEncoder::new_generic(writer)
131
0
    }
132
}
133
134
/// Generic functions that are available for both Tiff and BigTiff encoders.
135
impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
136
    /// Creates a new Tiff or BigTiff encoder, inferred from the return type.
137
0
    pub fn new_generic(writer: W) -> TiffResult<Self> {
138
0
        let mut writer = TiffWriter::new(writer);
139
0
        K::write_header(&mut writer)?;
140
141
0
        let last_ifd_chain = NonZeroU64::new(writer.previous_ifd_pointer::<K>())
142
0
            .expect("Header is at a non-zero offset");
143
144
0
        Ok(TiffEncoder {
145
0
            writer,
146
0
            kind: PhantomData,
147
0
            predictor: Predictor::None,
148
0
            compression: Compression::Uncompressed,
149
0
            last_ifd_chain,
150
0
        })
151
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::new_generic
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_generic
152
153
    /// Set the predictor to use
154
    ///
155
    /// A predictor is used to simplify the file before writing it. This is very
156
    /// useful when writing a file compressed using LZW as it can improve efficiency
157
0
    pub fn with_predictor(mut self, predictor: Predictor) -> Self {
158
0
        self.predictor = predictor;
159
160
0
        self
161
0
    }
162
163
    /// Set the compression method to use
164
0
    pub fn with_compression(mut self, compression: Compression) -> Self {
165
0
        self.compression = compression;
166
167
0
        self
168
0
    }
169
170
    /// Create a [`DirectoryEncoder`] to encode an ifd directory.
171
    #[deprecated = "`image_directory` replaced the old behavior and clarifies the intent"]
172
    #[doc(hidden)]
173
0
    pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
174
0
        Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
175
0
    }
176
177
    /// Create a [`DirectoryEncoder`] to encode an ifd (directory).
178
    ///
179
    /// The caller is responsible for ensuring that the directory is a valid image in the main TIFF
180
    /// IFD sequence. To encode additional directories that are not linked into the sequence, use
181
    /// [`Self::extra_directory`][TiffEncoder::extra_directory].
182
0
    pub fn image_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
183
0
        Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
184
0
    }
185
186
    /// Create a [`DirectoryEncoder`] to encode a non-image directory.
187
    ///
188
    /// The directory is not linked into the sequence of directories. For instance, encode Exif
189
    /// directories or SubIfd directories with this method.
190
0
    pub fn extra_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
191
0
        Self::unchained_directory(&mut self.writer)
192
0
    }
193
194
    /// Create an [`ImageEncoder`] to encode an image one slice at a time.
195
0
    pub fn new_image<C: ColorType>(
196
0
        &mut self,
197
0
        width: u32,
198
0
        height: u32,
199
0
    ) -> TiffResult<ImageEncoder<'_, W, C, K>> {
200
0
        let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
201
0
        ImageEncoder::new(encoder, width, height, self.compression, self.predictor)
202
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::new_image::<_>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::RGB32Float>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::RGBA32Float>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::RGB8>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::Gray8>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::RGB16>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::RGBA8>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::Gray16>
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new_image::<tiff::encoder::colortype::RGBA16>
203
204
    /// Convenience function to write an entire image from memory.
205
0
    pub fn write_image<C: ColorType>(
206
0
        &mut self,
207
0
        width: u32,
208
0
        height: u32,
209
0
        data: &[C::Inner],
210
0
    ) -> TiffResult<()>
211
0
    where
212
0
        [C::Inner]: TiffValue,
213
    {
214
0
        let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
215
0
        let image: ImageEncoder<W, C, K> =
216
0
            ImageEncoder::new(encoder, width, height, self.compression, self.predictor)?;
217
0
        image.write_data(data)
218
0
    }
219
220
0
    fn chain_directory<'lt>(
221
0
        writer: &'lt mut TiffWriter<W>,
222
0
        last_ifd_chain: &'lt mut NonZeroU64,
223
0
    ) -> TiffResult<DirectoryEncoder<'lt, W, K>> {
224
0
        let last_ifd = *last_ifd_chain;
225
0
        DirectoryEncoder::new(writer, Some(last_ifd), Some(last_ifd_chain))
226
0
    }
Unexecuted instantiation: <tiff::encoder::TiffEncoder<_, _>>::chain_directory
Unexecuted instantiation: <tiff::encoder::TiffEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::chain_directory
227
228
0
    fn unchained_directory(writer: &mut TiffWriter<W>) -> TiffResult<DirectoryEncoder<'_, W, K>> {
229
0
        DirectoryEncoder::new(writer, None, None)
230
0
    }
231
}
232
233
/// Low level interface to encode ifd directories.
234
///
235
/// You should call `finish` on this when you are finished with it.
236
/// Encoding can silently fail while this is dropping.
237
pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
238
    writer: &'a mut TiffWriter<W>,
239
    /// The position of the previous directory's `next` field, if any.
240
    chained_ifd_pos: Option<NonZeroU64>,
241
    /// An output to write the `next` field offset on completion.
242
    write_chain: Option<&'a mut NonZeroU64>,
243
    kind: PhantomData<K>,
244
    // We use BTreeMap to make sure tags are written in correct order
245
    directory: Directory,
246
    dropped: bool,
247
}
248
249
/// The offset of an encoded directory in the file.
250
///
251
/// Both the `offset` and `pointer` field are a complete description of the start offset of the
252
/// dictionary which is used to point to it. The struct also describes the extent covered by the
253
/// encoding of the directory. The constructors [`new`][DirectoryOffset::new] allow the checked
254
/// conversion. Note that even though the offsets are public do not expect their information to
255
/// propagate when modified.
256
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
257
pub struct DirectoryOffset<K: TiffKind> {
258
    /// The start of the directory as a Tiff value.
259
    ///
260
    /// This is a bit of a wart in the strongly typed design of the encoder. The value _type_ must
261
    /// itself know how to be represented in the Tiff file but that may differ based on endianess
262
    /// as well as the offset size (`u32` or BigTIFF's `u64`). Thankfully we're allowed to
263
    /// represent offsets with `LONG` or `IFD` in the usual case.
264
    pub offset: K::OffsetType,
265
    /// The start of the directory as a pure offset.
266
    pub pointer: IfdPointer,
267
    /// The offset of its sequence link field, in our private representation. Before exposing this
268
    /// make sure that we don't want any invariants (e.g. pointer being smaller than this). The
269
    /// type should be fine.
270
    ifd_chain: NonZeroU64,
271
    /// The kind of Tiff file the offset is for.
272
    kind: PhantomData<K>,
273
}
274
275
impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
276
    /// Construct a directory writer appending to data, assuming the writer is currently positioned
277
    /// immediately after a previously written IFD to which to append.
278
0
    fn new(
279
0
        writer: &'a mut TiffWriter<W>,
280
0
        chained_ifd_pos: Option<NonZeroU64>,
281
0
        chain_into: Option<&'a mut NonZeroU64>,
282
0
    ) -> TiffResult<Self> {
283
0
        writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff?
284
0
        Ok(Self {
285
0
            writer,
286
0
            chained_ifd_pos,
287
0
            write_chain: chain_into,
288
0
            kind: PhantomData,
289
0
            directory: Directory::empty(),
290
0
            dropped: false,
291
0
        })
292
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
293
294
    /// Write a single ifd tag.
295
0
    pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> {
296
        // Encodes the value if necessary. In the current bytes all integers are taken as native
297
        // endian and thus transparent but this keeps the interface generic.
298
0
        let mut bytes = Vec::with_capacity(value.bytes());
299
        {
300
0
            let mut writer = TiffWriter::new(&mut bytes);
301
0
            value.write(&mut writer)?;
302
        }
303
304
0
        let entry = Self::write_entry_inner(
305
0
            self.writer,
306
            DirectoryEntry {
307
                data_type: <T>::FIELD_TYPE,
308
0
                count: value.count().try_into()?,
309
0
                data: bytes.into(),
310
            },
311
0
        )?;
312
313
0
        self.directory.extend([(tag, entry)]);
314
315
0
        Ok(())
316
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::<tiff::tags::ResolutionUnit>
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_tag::<&[u8]>
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>
317
318
    /// Write a tag-value pair with prepared byte data.
319
    ///
320
    /// Note that the library will _not_ attempt to verify that the data type or the count of the
321
    /// buffered value is permissible for the given tag. The data will be associated with the tag
322
    /// exactly as-is.
323
    ///
324
    /// An error is returned if the byte order of the presented value does not match the byte order
325
    /// of the underlying file (i.e. the [native byte order](`crate::tags::ByteOrder::native`)).
326
0
    pub fn write_tag_buf(&mut self, tag: Tag, value: &ValueBuffer) -> TiffResult<()> {
327
0
        let entry = self.write_entry_buf(value)?;
328
0
        self.directory.extend([(tag, entry)]);
329
330
0
        Ok(())
331
0
    }
332
333
    /// Write some data to the tiff file, the offset of the data is returned.
334
    ///
335
    /// This could be used to write tiff strips. All of the data will be written into the file as a
336
    /// slice of bytes. It can not be used as an entry in a directory directly, where very short
337
    /// values are instead represented in the offset field directly. Use [`Self::write_entry`]
338
    /// instead.
339
0
    pub fn write_data<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> {
340
0
        let offset = self.writer.offset();
341
0
        value.write(self.writer)?;
342
0
        Ok(offset)
343
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]>
344
345
    /// Write some data directly to the tiff file, the offset of the data is returned.
346
    ///
347
    /// All of the data will be written into the file as a slice of bytes. It can not be used as an
348
    /// entry in a directory directly, where very short values are instead represented in the
349
    /// offset field directly. Use [`Self::write_entry_buf`] instead.
350
    ///
351
    /// An error is returned if the byte order of the presented value does not match the byte order
352
    /// of the underlying file (i.e. the [native byte order](`crate::tags::ByteOrder::native`)).
353
0
    pub fn write_data_buf(&mut self, value: &ValueBuffer) -> TiffResult<u64> {
354
0
        self.check_value_byteorder(value)?;
355
0
        let offset = self.writer.offset();
356
0
        self.writer.write_bytes(value.as_bytes())?;
357
0
        Ok(offset)
358
0
    }
359
360
    /// Write a directory value into the file.
361
    ///
362
    /// Returns an [`Entry`]. If the value is short enough it will *not* be written in the file but
363
    /// stored in the entry's offset field.
364
0
    pub fn write_entry<T: TiffValue>(&mut self, value: T) -> TiffResult<Entry> {
365
0
        Self::write_entry_inner(
366
0
            self.writer,
367
            DirectoryEntry {
368
                data_type: T::FIELD_TYPE,
369
0
                count: K::convert_offset(value.count() as u64)?,
370
                // FIXME: not optimal we always allocate here. But the only other method we have
371
                // available is `T::write(&mut TiffWriter<W>)` and we must pass that into
372
                // `write_entry_inner` but then have a combinatorial explosion of instantiations
373
                // which is absurd.
374
0
                data: value.data(),
375
            },
376
        )
377
0
    }
378
379
    /// Write a directory value into the file.
380
    ///
381
    /// An error is returned if the byte order of the presented value does not match the byte order
382
    /// of the underlying file (i.e. the [native byte order](`crate::tags::ByteOrder::native`)).
383
    ///
384
    /// Returns an [`Entry`]. If the value is short enough it will *not* be written in the file but
385
    /// stored in the entry's offset field.
386
0
    pub fn write_entry_buf(&mut self, value: &ValueBuffer) -> TiffResult<Entry> {
387
0
        self.check_value_byteorder(value)?;
388
389
0
        Self::write_entry_inner(
390
0
            self.writer,
391
            DirectoryEntry {
392
0
                data_type: value.data_type(),
393
0
                count: K::convert_offset(value.count())?,
394
0
                data: value.as_bytes().into(),
395
            },
396
        )
397
0
    }
398
399
    /// Write a directory entry by its byte data.
400
    ///
401
    /// The data must be pre-formatted to the byte order expected by the file.
402
    ///
403
    /// Returns an [`Entry`]. If the value is short enough it will *not* be written in the file but
404
    /// stored in the entry's offset field.
405
0
    pub fn write_entry_bytes(&mut self, ty: Type, data: &[u8]) -> TiffResult<Entry> {
406
0
        if data.len() % usize::from(ty.byte_len()) != 0 {
407
0
            return Err(TiffError::UsageError(UsageError::MismatchedEntryLength {
408
0
                ty,
409
0
                found: data.len(),
410
0
            }));
411
0
        }
412
413
0
        let count = data.len() / usize::from(ty.byte_len());
414
0
        let count = u64::try_from(count)?;
415
416
0
        Self::write_entry_inner(
417
0
            self.writer,
418
            DirectoryEntry {
419
0
                data_type: ty,
420
0
                count: K::convert_offset(count)?,
421
0
                data: data.into(),
422
            },
423
        )
424
0
    }
425
426
    /// Insert previously written key-value entries.
427
    ///
428
    /// It is the caller's responsibility to ensure that the data referred to by the entries is
429
    /// actually (or will be) written to the file. Note that small values are necessarily inline in
430
    /// the entry, the size limit depends on the Tiff kind. So do not confuse a directory from a
431
    /// BigTiff in a standard tiff or the other way around.
432
0
    pub fn extend_from(&mut self, dir: &Directory) {
433
0
        let entries = dir.iter().map(|(tag, val)| (tag, val.clone()));
434
0
        self.directory.extend(entries);
435
0
    }
436
437
    /// Define the parent directory.
438
    ///
439
    /// Each directory has an offset based link to its successor, forming a linked list in the
440
    /// file. The encoder writes its own offset into the parent's field when [`Self::finish`] is
441
    /// called or it is dropped. This redefines the parent. An offset representation of the parent
442
    /// must be acquired by finishing it with [`Self::finish_with_offsets`].
443
0
    pub fn set_parent(&mut self, offset: &DirectoryOffset<K>) {
444
0
        self.chained_ifd_pos = Some(offset.ifd_chain);
445
0
    }
446
447
    /// Write out the ifd directory itself.
448
0
    pub fn finish(mut self) -> TiffResult<()> {
449
0
        self.finish_internal()?;
450
0
        Ok(())
451
0
    }
452
453
    /// Write the IFD to the file and return the offset it is written to.
454
    ///
455
    /// The offset can be used as the value, or as part of a list of values, in the entry of
456
    /// another directory. If you're constructing the entry directly you'll want to use an
457
    /// appropriate type variant for this such as [`Type::IFD`].
458
0
    pub fn finish_with_offsets(mut self) -> TiffResult<DirectoryOffset<K>> {
459
0
        self.finish_internal()
460
0
    }
461
462
0
    fn write_directory(&mut self) -> TiffResult<u64> {
463
        // Start by turning all buffered unwritten values into entries.
464
0
        let offset = self.writer.offset();
465
0
        K::write_entry_count(self.writer, self.directory.len())?;
466
467
0
        let offset_bytes = mem::size_of::<K::OffsetType>();
468
0
        for (tag, entry) in self.directory.iter() {
469
0
            self.writer.write_u16(tag.to_u16())?;
470
0
            self.writer.write_u16(entry.field_type().to_u16())?;
471
0
            let count = K::convert_offset(entry.count())?;
472
0
            count.write(self.writer)?;
473
0
            self.writer.write_bytes(&entry.offset()[..offset_bytes])?;
474
        }
475
476
0
        Ok(offset)
477
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
478
479
    // Does it really make sense that this would be a (potentially) compressible write? For actual
480
    // directory values their size must match the data written so there's going to be a silent
481
    // problem if that actually occurs.
482
0
    fn write_entry_inner(
483
0
        writer: &mut TiffWriter<W>,
484
0
        value: DirectoryEntry<K::OffsetType>,
485
0
    ) -> TiffResult<Entry> {
486
        let DirectoryEntry {
487
0
            data: ref bytes,
488
0
            ref count,
489
0
            data_type,
490
0
        } = value;
491
492
0
        let in_entry_bytes = mem::size_of::<K::OffsetType>();
493
494
0
        let mut offset_bytes = [0; 8];
495
496
0
        if bytes.len() > in_entry_bytes {
497
0
            let offset = writer.offset();
498
0
            writer.write_bytes(bytes)?;
499
500
0
            let offset = K::convert_offset(offset)?;
501
0
            offset_bytes[..offset.bytes()].copy_from_slice(&offset.data());
502
0
        } else {
503
0
            // Note: we have indicated our native byte order in the header, hence this
504
0
            // corresponds to our byte order no matter the value type.
505
0
            offset_bytes[..bytes.len()].copy_from_slice(bytes);
506
0
        }
507
508
        // Undoing some hidden type. Offset is either u32 or u64. Due to the trait API being public
509
        // and some oversight, we can not clone the `count: K::OffsetType` and thus not convert it.
510
        // Instead, write it to a buffer...
511
0
        let mut count_bytes = [0; 8];
512
0
        debug_assert!(in_entry_bytes == 4 || in_entry_bytes == 8);
513
        // Nominally Cow but we only expect `Cow::Borrowed`.
514
0
        count_bytes[..count.bytes()].copy_from_slice(&count.data());
515
516
0
        Ok(if in_entry_bytes == 4 {
517
0
            let count = u32::from_ne_bytes(count_bytes[..4].try_into().unwrap());
518
0
            Entry::new(data_type, count, offset_bytes[..4].try_into().unwrap())
519
        } else {
520
0
            debug_assert_eq!(in_entry_bytes, 8);
521
0
            let count = u64::from_ne_bytes(count_bytes);
522
0
            Entry::new_u64(data_type, count, offset_bytes)
523
        })
524
0
    }
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<_, _>>::write_entry_inner
Unexecuted instantiation: <tiff::encoder::DirectoryEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::TiffKindStandard>>::write_entry_inner
525
526
0
    fn check_value_byteorder(&self, value: &ValueBuffer) -> TiffResult<()> {
527
        // FIXME: we should enable writing files with any chosen byte order.
528
0
        if value.byte_order() != ByteOrder::native() {
529
0
            Err(TiffError::UsageError(UsageError::ByteOrderMismatch))
530
        } else {
531
0
            Ok(())
532
        }
533
0
    }
534
535
    /// Provides the number of bytes written by the underlying TiffWriter during the last call.
536
0
    fn last_written(&self) -> u64 {
537
0
        self.writer.last_written()
538
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
539
540
0
    fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
541
0
        let ifd_pointer = self.write_directory()?;
542
0
        let offset = K::convert_offset(ifd_pointer)?;
543
544
0
        if let Some(prior) = self.chained_ifd_pos {
545
0
            let curr_pos = self.writer.offset();
546
547
0
            self.writer.goto_offset(prior.get())?;
548
            // Note how we are not writing the `offset` type itself here as doing so would need to
549
            // go through the `TiffValue` trait—the type is not constrained by much. But for the
550
            // trait we need a `TiffWriter` which comes with a bunch of additional state such as
551
            // compressor etc. that we have no need for.
552
0
            K::write_offset(self.writer, ifd_pointer)?;
553
554
0
            self.writer.goto_offset(curr_pos)?;
555
0
        }
556
557
0
        K::write_offset(self.writer, 0)?;
558
559
0
        let ifd_chain = NonZeroU64::new(self.writer.previous_ifd_pointer::<K>())
560
0
            .expect("IFD chain field is at a non-zero offset");
561
562
0
        if let Some(prior) = self.write_chain.take() {
563
0
            *prior = ifd_chain;
564
0
        }
565
566
0
        self.dropped = true;
567
568
0
        Ok(DirectoryOffset {
569
0
            pointer: IfdPointer(ifd_pointer),
570
0
            offset,
571
0
            ifd_chain,
572
0
            kind: PhantomData,
573
0
        })
574
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
575
}
576
577
impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> {
578
0
    fn drop(&mut self) {
579
0
        if !self.dropped {
580
0
            let _ = self.finish_internal();
581
0
        }
582
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
583
}
584
585
/// Type to encode images strip by strip.
586
///
587
/// You should call `finish` on this when you are finished with it.
588
/// Encoding can silently fail while this is dropping.
589
///
590
/// # Examples
591
/// ```
592
/// # extern crate tiff;
593
/// # fn main() {
594
/// # let mut file = std::io::Cursor::new(Vec::new());
595
/// # let image_data = vec![0; 100*100*3];
596
/// use tiff::encoder::*;
597
/// use tiff::tags::Tag;
598
///
599
/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
600
/// let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap();
601
///
602
/// // You can encode tags here
603
/// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap();
604
///
605
/// // Strip size can be configured before writing data
606
/// image.rows_per_strip(2).unwrap();
607
///
608
/// let mut idx = 0;
609
/// while image.next_strip_sample_count() > 0 {
610
///     let sample_count = image.next_strip_sample_count() as usize;
611
///     image.write_strip(&image_data[idx..idx+sample_count]).unwrap();
612
///     idx += sample_count;
613
/// }
614
/// image.finish().unwrap();
615
/// # }
616
/// ```
617
/// You can also call write_data function wich will encode by strip and finish
618
pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType, K: TiffKind> {
619
    encoder: DirectoryEncoder<'a, W, K>,
620
    strip_idx: u64,
621
    strip_count: u64,
622
    row_samples: u64,
623
    width: u32,
624
    height: u32,
625
    extra_samples: Vec<u16>,
626
    rows_per_strip: u64,
627
    strip_offsets: Vec<K::OffsetType>,
628
    strip_byte_count: Vec<K::OffsetType>,
629
    dropped: bool,
630
    compression: Compression,
631
    predictor: Predictor,
632
    _phantom: ::std::marker::PhantomData<C>,
633
}
634
635
impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> {
636
0
    fn sanity_check(compression: Compression, predictor: Predictor) -> TiffResult<()> {
637
0
        match (predictor, compression, T::SAMPLE_FORMAT[0]) {
638
            (Predictor::Horizontal, _, SampleFormat::IEEEFP | SampleFormat::Void) => {
639
0
                Err(TiffError::UsageError(UsageError::PredictorIncompatible))
640
            }
641
            (Predictor::FloatingPoint, _, _) => {
642
0
                Err(TiffError::UsageError(UsageError::PredictorUnavailable))
643
            }
644
0
            _ => Ok(()),
645
        }
646
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
647
648
0
    fn new(
649
0
        mut encoder: DirectoryEncoder<'a, W, K>,
650
0
        width: u32,
651
0
        height: u32,
652
0
        compression: Compression,
653
0
        predictor: Predictor,
654
0
    ) -> TiffResult<Self> {
655
0
        if width == 0 || height == 0 {
656
0
            return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions(
657
0
                width, height,
658
0
            )));
659
0
        }
660
661
0
        Self::sanity_check(compression, predictor)?;
662
663
0
        let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?;
664
0
        let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
665
666
        // Limit the strip size to prevent potential memory and security issues.
667
        // Also keep the multiple strip handling 'oiled'
668
0
        let rows_per_strip = {
669
0
            match compression.tag() {
670
0
                CompressionMethod::PackBits => 1, // Each row must be packed separately. Do not compress across row boundaries
671
0
                _ => 1_000_000_u64.div_ceil(row_bytes),
672
            }
673
        };
674
675
0
        let strip_count = u64::from(height).div_ceil(rows_per_strip);
676
677
0
        encoder.write_tag(Tag::ImageWidth, width)?;
678
0
        encoder.write_tag(Tag::ImageLength, height)?;
679
0
        encoder.write_tag(Tag::Compression, compression.tag().to_u16())?;
680
0
        encoder.write_tag(Tag::Predictor, predictor.to_u16())?;
681
682
0
        encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?;
683
684
0
        if matches!(<T>::TIFF_VALUE, PhotometricInterpretation::YCbCr) {
685
            // The default for this tag is 2,2 for subsampling but we do not support such a
686
            // transformation. Instead all samples must be provided.
687
0
            encoder.write_tag(Tag::ChromaSubsampling, &[1u16, 1u16][..])?;
688
0
        }
689
690
0
        encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?;
691
692
0
        encoder.write_tag(
693
0
            Tag::SamplesPerPixel,
694
0
            u16::try_from(<T>::BITS_PER_SAMPLE.len())?,
695
0
        )?;
696
0
        encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?;
697
0
        encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?;
698
0
        encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None)?;
699
700
0
        Ok(ImageEncoder {
701
0
            encoder,
702
0
            strip_count,
703
0
            strip_idx: 0,
704
0
            row_samples,
705
0
            rows_per_strip,
706
0
            extra_samples: vec![],
707
0
            width,
708
0
            height,
709
0
            strip_offsets: Vec::new(),
710
0
            strip_byte_count: Vec::new(),
711
0
            dropped: false,
712
0
            compression,
713
0
            predictor,
714
0
            _phantom: ::std::marker::PhantomData,
715
0
        })
716
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
717
718
0
    pub fn extra_samples(&mut self, extra: &[ExtraSamples]) -> Result<(), TiffError> {
719
0
        if self.strip_idx != 0 {
720
0
            return Err(TiffError::UsageError(
721
0
                UsageError::ReconfiguredAfterImageWrite,
722
0
            ));
723
0
        }
724
725
0
        let samples = self.extra_samples.len() + extra.len() + <T>::BITS_PER_SAMPLE.len();
726
0
        let row_samples = u64::from(self.width) * u64::try_from(samples)?;
727
728
0
        self.extra_samples
729
0
            .extend(extra.iter().map(ExtraSamples::to_u16));
730
731
0
        self.encoder
732
0
            .write_tag(Tag::ExtraSamples, &self.extra_samples[..])?;
733
734
0
        self.row_samples = row_samples;
735
736
0
        Ok(())
737
0
    }
738
739
    /// Number of samples the next strip should have.
740
0
    pub fn next_strip_sample_count(&self) -> u64 {
741
0
        if self.strip_idx >= self.strip_count {
742
0
            return 0;
743
0
        }
744
745
0
        let raw_start_row = self.strip_idx * self.rows_per_strip;
746
0
        let start_row = cmp::min(u64::from(self.height), raw_start_row);
747
0
        let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip);
748
749
0
        (end_row - start_row) * self.row_samples
750
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
751
752
    /// Write a single strip.
753
0
    pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()>
754
0
    where
755
0
        [T::Inner]: TiffValue,
756
    {
757
0
        let samples = self.next_strip_sample_count();
758
0
        if u64::try_from(value.len())? != samples {
759
0
            return Err(io::Error::new(
760
0
                io::ErrorKind::InvalidData,
761
0
                "Slice is wrong size for strip",
762
0
            )
763
0
            .into());
764
0
        }
765
766
        // Write the (possible compressed) data to the encoder.
767
0
        let offset = match self.predictor {
768
0
            Predictor::None => self.encoder.write_data(value)?,
769
            Predictor::Horizontal => {
770
0
                let mut row_result = Vec::with_capacity(value.len());
771
0
                for row in value.chunks_exact(self.row_samples as usize) {
772
0
                    T::horizontal_predict(row, &mut row_result);
773
0
                }
774
0
                self.encoder.write_data(row_result.as_slice())?
775
            }
776
0
            _ => unimplemented!(),
777
        };
778
779
0
        let byte_count = self.encoder.last_written() as usize;
780
781
0
        self.strip_offsets.push(K::convert_offset(offset)?);
782
0
        self.strip_byte_count.push(byte_count.try_into()?);
783
784
0
        self.strip_idx += 1;
785
0
        Ok(())
786
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
787
788
    /// Write strips from data
789
0
    pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()>
790
0
    where
791
0
        [T::Inner]: TiffValue,
792
    {
793
0
        let num_pix = usize::try_from(self.width)?
794
0
            .checked_mul(usize::try_from(self.height)?)
795
0
            .ok_or_else(|| {
796
0
                io::Error::new(
797
0
                    io::ErrorKind::InvalidInput,
798
                    "Image width * height exceeds usize",
799
                )
800
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}
801
0
        if data.len() < num_pix {
802
0
            return Err(io::Error::new(
803
0
                io::ErrorKind::InvalidData,
804
0
                "Input data slice is undersized for provided dimensions",
805
0
            )
806
0
            .into());
807
0
        }
808
809
0
        self.encoder
810
0
            .writer
811
0
            .set_compression(self.compression.get_algorithm());
812
813
0
        let mut idx = 0;
814
0
        while self.next_strip_sample_count() > 0 {
815
0
            let sample_count = usize::try_from(self.next_strip_sample_count())?;
816
0
            self.write_strip(&data[idx..idx + sample_count])?;
817
0
            idx += sample_count;
818
        }
819
820
0
        self.encoder.writer.reset_compression();
821
0
        self.finish()?;
822
0
        Ok(())
823
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
824
825
    /// Set image resolution
826
0
    pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
827
0
        self.encoder
828
0
            .write_tag(Tag::ResolutionUnit, unit.to_u16())
829
0
            .unwrap();
830
0
        self.encoder
831
0
            .write_tag(Tag::XResolution, value.clone())
832
0
            .unwrap();
833
0
        self.encoder.write_tag(Tag::YResolution, value).unwrap();
834
0
    }
835
836
    /// Set image resolution unit
837
0
    pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
838
0
        self.encoder
839
0
            .write_tag(Tag::ResolutionUnit, unit.to_u16())
840
0
            .unwrap();
841
0
    }
842
843
    /// Set image x-resolution
844
0
    pub fn x_resolution(&mut self, value: Rational) {
845
0
        self.encoder.write_tag(Tag::XResolution, value).unwrap();
846
0
    }
847
848
    /// Set image y-resolution
849
0
    pub fn y_resolution(&mut self, value: Rational) {
850
0
        self.encoder.write_tag(Tag::YResolution, value).unwrap();
851
0
    }
852
853
    /// Set image number of lines per strip
854
    ///
855
    /// This function needs to be called before any calls to `write_data` or
856
    /// `write_strip` and will return an error otherwise.
857
0
    pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> {
858
0
        if self.strip_idx != 0 {
859
0
            return Err(io::Error::new(
860
0
                io::ErrorKind::InvalidInput,
861
0
                "Cannot change strip size after data was written",
862
0
            )
863
0
            .into());
864
0
        }
865
        // Write tag as 32 bits
866
0
        self.encoder.write_tag(Tag::RowsPerStrip, value)?;
867
868
0
        let value: u64 = value as u64;
869
0
        self.strip_count = (self.height as u64).div_ceil(value);
870
0
        self.rows_per_strip = value;
871
872
0
        Ok(())
873
0
    }
874
875
0
    fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
876
0
        if self.extra_samples.is_empty() {
877
0
            self.encoder
878
0
                .write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?;
879
        } else {
880
0
            let mut sample_format: Vec<_> = <T>::BITS_PER_SAMPLE.to_vec();
881
0
            let replicated =
882
0
                core::iter::repeat_n(<T>::BITS_PER_SAMPLE[0], self.extra_samples.len());
883
0
            sample_format.extend(replicated);
884
885
0
            self.encoder
886
0
                .write_tag(Tag::BitsPerSample, &sample_format[..])?;
887
888
0
            self.encoder.write_tag(
889
0
                Tag::SamplesPerPixel,
890
0
                u16::try_from(<T>::BITS_PER_SAMPLE.len() + self.extra_samples.len())?,
891
0
            )?;
892
        }
893
894
0
        let mut sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect();
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::finish_internal::{closure#0}
895
0
        let extra_format = sample_format
896
0
            .first()
897
0
            .copied()
898
            // Frankly should not occur, we have no sample format without at least one entry. We
899
            // would need an interface upgrade to handle this however. Either decide to support
900
            // heterogeneous sample formats or a way to provide fallback that is used for purely
901
            // extra samples and not provided via a slice used for samples themselves.
902
0
            .unwrap_or(SampleFormat::Void.to_u16());
903
904
0
        sample_format.extend(core::iter::repeat_n(extra_format, self.extra_samples.len()));
905
906
0
        self.encoder
907
0
            .write_tag(Tag::SampleFormat, &sample_format[..])?;
908
909
0
        self.encoder
910
0
            .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?;
911
0
        self.encoder.write_tag(
912
0
            Tag::StripByteCounts,
913
0
            K::convert_slice(&self.strip_byte_count),
914
0
        )?;
915
0
        self.dropped = true;
916
917
0
        self.encoder.finish_internal()
918
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
919
920
    /// Get a reference of the underlying `DirectoryEncoder`
921
0
    pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> {
922
0
        &mut self.encoder
923
0
    }
Unexecuted instantiation: <tiff::encoder::ImageEncoder<_, _, _>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB32Float, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA32Float, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB8, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray8, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGB16, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA8, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::Gray16, tiff::encoder::TiffKindStandard>>::encoder
Unexecuted instantiation: <tiff::encoder::ImageEncoder<&mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>, tiff::encoder::colortype::RGBA16, tiff::encoder::TiffKindStandard>>::encoder
924
925
    /// Write out image and ifd directory.
926
0
    pub fn finish(mut self) -> TiffResult<()> {
927
0
        self.finish_internal()?;
928
0
        Ok(())
929
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
930
}
931
932
impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W, C, K> {
933
0
    fn drop(&mut self) {
934
0
        if !self.dropped {
935
0
            let _ = self.finish_internal();
936
0
        }
937
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
938
}
939
940
struct DirectoryEntry<'data, S> {
941
    data_type: Type,
942
    count: S,
943
    data: std::borrow::Cow<'data, [u8]>,
944
}
945
946
/// Trait to abstract over Tiff/BigTiff differences.
947
///
948
/// Implemented for [`TiffKindStandard`] and [`TiffKindBig`].
949
pub trait TiffKind {
950
    /// The type of offset fields, `u32` for normal Tiff, `u64` for BigTiff.
951
    type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue;
952
953
    /// Needed for the `convert_slice` method.
954
    type OffsetArrayType: ?Sized + TiffValue;
955
956
    /// Write the (Big)Tiff header.
957
    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
958
959
    /// Convert a file offset to `Self::OffsetType`.
960
    ///
961
    /// This returns an error for normal Tiff if the offset is larger than `u32::MAX`.
962
    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>;
963
964
    /// Write an offset value to the given writer.
965
    ///
966
    /// Like `convert_offset`, this errors if `offset > u32::MAX` for normal Tiff.
967
    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>;
968
969
    /// Write the IFD entry count field with the given `count` value.
970
    ///
971
    /// The entry count field is an `u16` for normal Tiff and `u64` for BigTiff. Errors
972
    /// if the given `usize` is larger than the representable values.
973
    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>;
974
975
    /// Internal helper method for satisfying Rust's type checker.
976
    ///
977
    /// The `TiffValue` trait is implemented for both primitive values (e.g. `u8`, `u32`) and
978
    /// slices of primitive values (e.g. `[u8]`, `[u32]`). However, this is not represented in
979
    /// the type system, so there is no guarantee that that for all `T: TiffValue` there is also
980
    /// an implementation of `TiffValue` for `[T]`. This method works around that problem by
981
    /// providing a conversion from `[T]` to some value that implements `TiffValue`, thereby
982
    /// making all slices of `OffsetType` usable with `write_tag` and similar methods.
983
    ///
984
    /// Implementations of this trait should always set `OffsetArrayType` to `[OffsetType]`.
985
    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType;
986
}
987
988
impl<K: TiffKind> DirectoryOffset<K> {
989
    /// Construct the directory pointer information from its raw offset.
990
    ///
991
    /// Fails in these cases:
992
    ///
993
    /// - if start offset is too large to be represented with the chosen TIFF format, i.e. a value
994
    ///   larger than [`u32::MAX`] with a standard tiff which is only valid in a BigTiff. This
995
    ///   returns [`TiffError::IntSizeError`].
996
    /// - the extent of the directory would overflow the file length. This returns a
997
    ///   [`TiffError::UsageError`].
998
    ///
999
    /// The library does *not* validate the contents or offset in any way, it just performs the
1000
    /// necessary math assuming the data is an accurate representation of existing content.
1001
    ///
1002
    /// # Examples
1003
    ///
1004
    /// If you have any custom way of writing a directory to a file that can not go through the
1005
    /// usual [`TiffEncoder::extra_directory`] then you can reconstruct the offset information as
1006
    /// long as you provide all the necessary data to the library. You can then use it as a parent
1007
    /// directory, i.e. have the library overwrite its `next` field.
1008
    ///
1009
    /// ```
1010
    /// use tiff::{
1011
    ///     encoder::{TiffEncoder, DirectoryOffset},
1012
    ///     Directory,
1013
    ///     tags::IfdPointer,
1014
    /// };
1015
    ///
1016
    /// # let mut file = std::io::Cursor::new(Vec::new());
1017
    /// let mut tiff = TiffEncoder::new(&mut file)?;
1018
    ///
1019
    /// // … some custom data writes, assume we know where a directory was written
1020
    /// # fn reconstruction_of_your_directory() -> Directory { Directory::from_iter([]) }
1021
    /// let known_offset = IfdPointer(1024);
1022
    /// let known_contents: Directory = reconstruction_of_your_directory();
1023
    ///
1024
    /// let reconstructed = DirectoryOffset::new(known_offset, &known_contents)?;
1025
    ///
1026
    /// // Now we can use it as if the directory was written by the `TiffEncoder` itself.
1027
    /// let mut chain = tiff.extra_directory()?;
1028
    /// chain.set_parent(&reconstructed);
1029
    /// chain.finish_with_offsets()?;
1030
    ///
1031
    /// # Ok::<_, tiff::TiffError>(())
1032
    /// ```
1033
0
    pub fn new(pointer: IfdPointer, dir: &Directory) -> TiffResult<Self> {
1034
0
        let offset = K::convert_offset(pointer.0)?;
1035
0
        let encoded = dir.encoded_len::<K>();
1036
0
        let offset_field_offset = encoded - mem::size_of_val(&offset) as u64;
1037
1038
0
        let ifd_chain = pointer
1039
0
            .0
1040
0
            .checked_add(offset_field_offset)
1041
0
            .and_then(NonZeroU64::new)
1042
0
            .ok_or(TiffError::UsageError(UsageError::ZeroIfdPointer))?;
1043
1044
0
        Ok(DirectoryOffset {
1045
0
            pointer,
1046
0
            offset,
1047
0
            ifd_chain,
1048
0
            kind: PhantomData,
1049
0
        })
1050
0
    }
1051
}
1052
1053
/// Create a standard Tiff file.
1054
pub struct TiffKindStandard;
1055
1056
impl TiffKind for TiffKindStandard {
1057
    type OffsetType = u32;
1058
    type OffsetArrayType = [u32];
1059
1060
0
    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
1061
0
        write_tiff_header(writer)?;
1062
        // blank the IFD offset location
1063
0
        writer.write_u32(0)?;
1064
1065
0
        Ok(())
1066
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>>>
1067
1068
0
    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
1069
0
        Ok(Self::OffsetType::try_from(offset)?)
1070
0
    }
1071
1072
0
    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
1073
0
        writer.write_u32(u32::try_from(offset)?)?;
1074
0
        Ok(())
1075
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>>>
1076
1077
0
    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
1078
0
        writer.write_u16(u16::try_from(count)?)?;
1079
1080
0
        Ok(())
1081
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>>>
1082
1083
0
    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
1084
0
        slice
1085
0
    }
1086
}
1087
1088
/// Create a BigTiff file.
1089
pub struct TiffKindBig;
1090
1091
impl TiffKind for TiffKindBig {
1092
    type OffsetType = u64;
1093
    type OffsetArrayType = [u64];
1094
1095
0
    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
1096
0
        write_bigtiff_header(writer)?;
1097
        // blank the IFD offset location
1098
0
        writer.write_u64(0)?;
1099
1100
0
        Ok(())
1101
0
    }
1102
1103
0
    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
1104
0
        Ok(offset)
1105
0
    }
1106
1107
0
    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
1108
0
        writer.write_u64(offset)?;
1109
0
        Ok(())
1110
0
    }
1111
1112
0
    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
1113
0
        writer.write_u64(u64::try_from(count)?)?;
1114
0
        Ok(())
1115
0
    }
1116
1117
0
    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
1118
0
        slice
1119
0
    }
1120
}
1121
1122
#[test]
1123
fn directory_offset_new_equivalent_to_writing() {
1124
    type K = TiffKindStandard;
1125
1126
    let dir = Directory::from_iter(vec![
1127
        (
1128
            Tag::ImageWidth,
1129
            Entry::new(Type::LONG, 1, 100u32.to_ne_bytes()),
1130
        ),
1131
        (
1132
            Tag::ImageLength,
1133
            Entry::new(Type::LONG, 1, 200u32.to_ne_bytes()),
1134
        ),
1135
    ]);
1136
1137
    let data = std::io::Cursor::new(vec![]);
1138
    let mut file = TiffEncoder::new(data).unwrap();
1139
1140
    let mut as_dir_encoder = file.extra_directory().unwrap();
1141
    as_dir_encoder.extend_from(&dir);
1142
    let dir_extent = as_dir_encoder.finish_with_offsets().unwrap();
1143
1144
    // Check we can recreate the extent had we written ourselves.
1145
    let synth = DirectoryOffset::<K>::new(dir_extent.pointer, &dir).unwrap();
1146
1147
    assert_eq!(synth.pointer, dir_extent.pointer);
1148
    assert_eq!(synth.offset, dir_extent.offset);
1149
    assert_eq!(synth.ifd_chain, dir_extent.ifd_chain);
1150
}