tiff/encoder/
mod.rs

1pub use tiff_value::*;
2
3use std::{
4    cmp,
5    collections::BTreeMap,
6    convert::{TryFrom, TryInto},
7    io::{self, Seek, Write},
8    marker::PhantomData,
9    mem,
10    num::TryFromIntError,
11};
12
13use crate::{
14    error::TiffResult,
15    tags::{CompressionMethod, ResolutionUnit, Tag},
16    TiffError, TiffFormatError,
17};
18
19pub mod colortype;
20pub mod compression;
21mod tiff_value;
22mod writer;
23
24use self::colortype::*;
25use self::compression::*;
26use self::writer::*;
27
28/// Encoder for Tiff and BigTiff files.
29///
30/// With this type you can get a `DirectoryEncoder` or a `ImageEncoder`
31/// to encode Tiff/BigTiff ifd directories with images.
32///
33/// See `DirectoryEncoder` and `ImageEncoder`.
34///
35/// # Examples
36/// ```
37/// # extern crate tiff;
38/// # fn main() {
39/// # let mut file = std::io::Cursor::new(Vec::new());
40/// # let image_data = vec![0; 100*100*3];
41/// use tiff::encoder::*;
42///
43/// // create a standard Tiff file
44/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
45/// tiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap();
46///
47/// // create a BigTiff file
48/// let mut bigtiff = TiffEncoder::new_big(&mut file).unwrap();
49/// bigtiff.write_image::<colortype::RGB8>(100, 100, &image_data).unwrap();
50///
51/// # }
52/// ```
53pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> {
54    writer: TiffWriter<W>,
55    kind: PhantomData<K>,
56}
57
58/// Constructor functions to create standard Tiff files.
59impl<W: Write + Seek> TiffEncoder<W> {
60    /// Creates a new encoder for standard Tiff files.
61    ///
62    /// To create BigTiff files, use [`new_big`][TiffEncoder::new_big] or
63    /// [`new_generic`][TiffEncoder::new_generic].
64    pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> {
65        TiffEncoder::new_generic(writer)
66    }
67}
68
69/// Constructor functions to create BigTiff files.
70impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> {
71    /// Creates a new encoder for BigTiff files.
72    ///
73    /// To create standard Tiff files, use [`new`][TiffEncoder::new] or
74    /// [`new_generic`][TiffEncoder::new_generic].
75    pub fn new_big(writer: W) -> TiffResult<Self> {
76        TiffEncoder::new_generic(writer)
77    }
78}
79
80/// Generic functions that are available for both Tiff and BigTiff encoders.
81impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
82    /// Creates a new Tiff or BigTiff encoder, inferred from the return type.
83    pub fn new_generic(writer: W) -> TiffResult<Self> {
84        let mut encoder = TiffEncoder {
85            writer: TiffWriter::new(writer),
86            kind: PhantomData,
87        };
88
89        K::write_header(&mut encoder.writer)?;
90
91        Ok(encoder)
92    }
93
94    /// Create a [`DirectoryEncoder`] to encode an ifd directory.
95    pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<W, K>> {
96        DirectoryEncoder::new(&mut self.writer)
97    }
98
99    /// Create an [`ImageEncoder`] to encode an image one slice at a time.
100    pub fn new_image<C: ColorType>(
101        &mut self,
102        width: u32,
103        height: u32,
104    ) -> TiffResult<ImageEncoder<W, C, K, Uncompressed>> {
105        let encoder = DirectoryEncoder::new(&mut self.writer)?;
106        ImageEncoder::new(encoder, width, height)
107    }
108
109    /// Create an [`ImageEncoder`] to encode an image one slice at a time.
110    pub fn new_image_with_compression<C: ColorType, D: Compression>(
111        &mut self,
112        width: u32,
113        height: u32,
114        compression: D,
115    ) -> TiffResult<ImageEncoder<W, C, K, D>> {
116        let encoder = DirectoryEncoder::new(&mut self.writer)?;
117        ImageEncoder::with_compression(encoder, width, height, compression)
118    }
119
120    /// Convenience function to write an entire image from memory.
121    pub fn write_image<C: ColorType>(
122        &mut self,
123        width: u32,
124        height: u32,
125        data: &[C::Inner],
126    ) -> TiffResult<()>
127    where
128        [C::Inner]: TiffValue,
129    {
130        let encoder = DirectoryEncoder::new(&mut self.writer)?;
131        let image: ImageEncoder<W, C, K> = ImageEncoder::new(encoder, width, height)?;
132        image.write_data(data)
133    }
134
135    /// Convenience function to write an entire image from memory with a given compression.
136    pub fn write_image_with_compression<C: ColorType, D: Compression>(
137        &mut self,
138        width: u32,
139        height: u32,
140        compression: D,
141        data: &[C::Inner],
142    ) -> TiffResult<()>
143    where
144        [C::Inner]: TiffValue,
145    {
146        let encoder = DirectoryEncoder::new(&mut self.writer)?;
147        let image: ImageEncoder<W, C, K, D> =
148            ImageEncoder::with_compression(encoder, width, height, compression)?;
149        image.write_data(data)
150    }
151}
152
153/// Low level interface to encode ifd directories.
154///
155/// You should call `finish` on this when you are finished with it.
156/// Encoding can silently fail while this is dropping.
157pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
158    writer: &'a mut TiffWriter<W>,
159    dropped: bool,
160    // We use BTreeMap to make sure tags are written in correct order
161    ifd_pointer_pos: u64,
162    ifd: BTreeMap<u16, DirectoryEntry<K::OffsetType>>,
163}
164
165impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
166    fn new(writer: &'a mut TiffWriter<W>) -> TiffResult<Self> {
167        // the previous word is the IFD offset position
168        let ifd_pointer_pos = writer.offset() - mem::size_of::<K::OffsetType>() as u64;
169        writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff?
170        Ok(DirectoryEncoder {
171            writer,
172            dropped: false,
173            ifd_pointer_pos,
174            ifd: BTreeMap::new(),
175        })
176    }
177
178    /// Write a single ifd tag.
179    pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> {
180        let mut bytes = Vec::with_capacity(value.bytes());
181        {
182            let mut writer = TiffWriter::new(&mut bytes);
183            value.write(&mut writer)?;
184        }
185
186        self.ifd.insert(
187            tag.to_u16(),
188            DirectoryEntry {
189                data_type: <T>::FIELD_TYPE.to_u16(),
190                count: value.count().try_into()?,
191                data: bytes,
192            },
193        );
194
195        Ok(())
196    }
197
198    fn write_directory(&mut self) -> TiffResult<u64> {
199        // Start by writing out all values
200        for &mut DirectoryEntry {
201            data: ref mut bytes,
202            ..
203        } in self.ifd.values_mut()
204        {
205            let data_bytes = mem::size_of::<K::OffsetType>();
206
207            if bytes.len() > data_bytes {
208                let offset = self.writer.offset();
209                self.writer.write_bytes(bytes)?;
210                *bytes = vec![0; data_bytes];
211                let mut writer = TiffWriter::new(bytes as &mut [u8]);
212                K::write_offset(&mut writer, offset)?;
213            } else {
214                while bytes.len() < data_bytes {
215                    bytes.push(0);
216                }
217            }
218        }
219
220        let offset = self.writer.offset();
221
222        K::write_entry_count(self.writer, self.ifd.len())?;
223        for (
224            tag,
225            DirectoryEntry {
226                data_type: field_type,
227                count,
228                data: offset,
229            },
230        ) in self.ifd.iter()
231        {
232            self.writer.write_u16(*tag)?;
233            self.writer.write_u16(*field_type)?;
234            (*count).write(self.writer)?;
235            self.writer.write_bytes(offset)?;
236        }
237
238        Ok(offset)
239    }
240
241    /// Write some data to the tiff file, the offset of the data is returned.
242    ///
243    /// This could be used to write tiff strips.
244    pub fn write_data<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> {
245        let offset = self.writer.offset();
246        value.write(self.writer)?;
247        Ok(offset)
248    }
249
250    /// Provides the number of bytes written by the underlying TiffWriter during the last call.
251    fn last_written(&self) -> u64 {
252        self.writer.last_written()
253    }
254
255    fn finish_internal(&mut self) -> TiffResult<()> {
256        let ifd_pointer = self.write_directory()?;
257        let curr_pos = self.writer.offset();
258
259        self.writer.goto_offset(self.ifd_pointer_pos)?;
260        K::write_offset(self.writer, ifd_pointer)?;
261        self.writer.goto_offset(curr_pos)?;
262        K::write_offset(self.writer, 0)?;
263
264        self.dropped = true;
265
266        Ok(())
267    }
268
269    /// Write out the ifd directory.
270    pub fn finish(mut self) -> TiffResult<()> {
271        self.finish_internal()
272    }
273}
274
275impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> {
276    fn drop(&mut self) {
277        if !self.dropped {
278            let _ = self.finish_internal();
279        }
280    }
281}
282
283/// Type to encode images strip by strip.
284///
285/// You should call `finish` on this when you are finished with it.
286/// Encoding can silently fail while this is dropping.
287///
288/// # Examples
289/// ```
290/// # extern crate tiff;
291/// # fn main() {
292/// # let mut file = std::io::Cursor::new(Vec::new());
293/// # let image_data = vec![0; 100*100*3];
294/// use tiff::encoder::*;
295/// use tiff::tags::Tag;
296///
297/// let mut tiff = TiffEncoder::new(&mut file).unwrap();
298/// let mut image = tiff.new_image::<colortype::RGB8>(100, 100).unwrap();
299///
300/// // You can encode tags here
301/// image.encoder().write_tag(Tag::Artist, "Image-tiff").unwrap();
302///
303/// // Strip size can be configured before writing data
304/// image.rows_per_strip(2).unwrap();
305///
306/// let mut idx = 0;
307/// while image.next_strip_sample_count() > 0 {
308///     let sample_count = image.next_strip_sample_count() as usize;
309///     image.write_strip(&image_data[idx..idx+sample_count]).unwrap();
310///     idx += sample_count;
311/// }
312/// image.finish().unwrap();
313/// # }
314/// ```
315/// You can also call write_data function wich will encode by strip and finish
316pub struct ImageEncoder<
317    'a,
318    W: 'a + Write + Seek,
319    C: ColorType,
320    K: TiffKind,
321    D: Compression = Uncompressed,
322> {
323    encoder: DirectoryEncoder<'a, W, K>,
324    strip_idx: u64,
325    strip_count: u64,
326    row_samples: u64,
327    width: u32,
328    height: u32,
329    rows_per_strip: u64,
330    strip_offsets: Vec<K::OffsetType>,
331    strip_byte_count: Vec<K::OffsetType>,
332    dropped: bool,
333    compression: D,
334    _phantom: ::std::marker::PhantomData<C>,
335}
336
337impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind, D: Compression>
338    ImageEncoder<'a, W, T, K, D>
339{
340    fn new(encoder: DirectoryEncoder<'a, W, K>, width: u32, height: u32) -> TiffResult<Self>
341    where
342        D: Default,
343    {
344        Self::with_compression(encoder, width, height, D::default())
345    }
346
347    fn with_compression(
348        mut encoder: DirectoryEncoder<'a, W, K>,
349        width: u32,
350        height: u32,
351        compression: D,
352    ) -> TiffResult<Self> {
353        if width == 0 || height == 0 {
354            return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions(
355                width, height,
356            )));
357        }
358
359        let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?;
360        let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
361
362        // Limit the strip size to prevent potential memory and security issues.
363        // Also keep the multiple strip handling 'oiled'
364        let rows_per_strip = {
365            match D::COMPRESSION_METHOD {
366                CompressionMethod::PackBits => 1, // Each row must be packed separately. Do not compress across row boundaries
367                _ => (1_000_000 + row_bytes - 1) / row_bytes,
368            }
369        };
370
371        let strip_count = (u64::from(height) + rows_per_strip - 1) / rows_per_strip;
372
373        encoder.write_tag(Tag::ImageWidth, width)?;
374        encoder.write_tag(Tag::ImageLength, height)?;
375        encoder.write_tag(Tag::Compression, D::COMPRESSION_METHOD.to_u16())?;
376
377        encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?;
378        let sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect();
379        encoder.write_tag(Tag::SampleFormat, &sample_format[..])?;
380        encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?;
381
382        encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?;
383
384        encoder.write_tag(
385            Tag::SamplesPerPixel,
386            u16::try_from(<T>::BITS_PER_SAMPLE.len())?,
387        )?;
388        encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?;
389        encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?;
390        encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?;
391
392        Ok(ImageEncoder {
393            encoder,
394            strip_count,
395            strip_idx: 0,
396            row_samples,
397            rows_per_strip,
398            width,
399            height,
400            strip_offsets: Vec::new(),
401            strip_byte_count: Vec::new(),
402            dropped: false,
403            compression,
404            _phantom: ::std::marker::PhantomData,
405        })
406    }
407
408    /// Number of samples the next strip should have.
409    pub fn next_strip_sample_count(&self) -> u64 {
410        if self.strip_idx >= self.strip_count {
411            return 0;
412        }
413
414        let raw_start_row = self.strip_idx * self.rows_per_strip;
415        let start_row = cmp::min(u64::from(self.height), raw_start_row);
416        let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip);
417
418        (end_row - start_row) * self.row_samples
419    }
420
421    /// Write a single strip.
422    pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()>
423    where
424        [T::Inner]: TiffValue,
425    {
426        let samples = self.next_strip_sample_count();
427        if u64::try_from(value.len())? != samples {
428            return Err(io::Error::new(
429                io::ErrorKind::InvalidData,
430                "Slice is wrong size for strip",
431            )
432            .into());
433        }
434
435        // Write the (possible compressed) data to the encoder.
436        let offset = self.encoder.write_data(value)?;
437        let byte_count = self.encoder.last_written() as usize;
438
439        self.strip_offsets.push(K::convert_offset(offset)?);
440        self.strip_byte_count.push(byte_count.try_into()?);
441
442        self.strip_idx += 1;
443        Ok(())
444    }
445
446    /// Write strips from data
447    pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()>
448    where
449        [T::Inner]: TiffValue,
450    {
451        let num_pix = usize::try_from(self.width)?
452            .checked_mul(usize::try_from(self.height)?)
453            .ok_or_else(|| {
454                io::Error::new(
455                    io::ErrorKind::InvalidInput,
456                    "Image width * height exceeds usize",
457                )
458            })?;
459        if data.len() < num_pix {
460            return Err(io::Error::new(
461                io::ErrorKind::InvalidData,
462                "Input data slice is undersized for provided dimensions",
463            )
464            .into());
465        }
466
467        self.encoder
468            .writer
469            .set_compression(self.compression.get_algorithm());
470
471        let mut idx = 0;
472        while self.next_strip_sample_count() > 0 {
473            let sample_count = usize::try_from(self.next_strip_sample_count())?;
474            self.write_strip(&data[idx..idx + sample_count])?;
475            idx += sample_count;
476        }
477
478        self.encoder.writer.reset_compression();
479        self.finish()?;
480        Ok(())
481    }
482
483    /// Set image resolution
484    pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
485        self.encoder
486            .write_tag(Tag::ResolutionUnit, unit.to_u16())
487            .unwrap();
488        self.encoder
489            .write_tag(Tag::XResolution, value.clone())
490            .unwrap();
491        self.encoder.write_tag(Tag::YResolution, value).unwrap();
492    }
493
494    /// Set image resolution unit
495    pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
496        self.encoder
497            .write_tag(Tag::ResolutionUnit, unit.to_u16())
498            .unwrap();
499    }
500
501    /// Set image x-resolution
502    pub fn x_resolution(&mut self, value: Rational) {
503        self.encoder.write_tag(Tag::XResolution, value).unwrap();
504    }
505
506    /// Set image y-resolution
507    pub fn y_resolution(&mut self, value: Rational) {
508        self.encoder.write_tag(Tag::YResolution, value).unwrap();
509    }
510
511    /// Set image number of lines per strip
512    ///
513    /// This function needs to be called before any calls to `write_data` or
514    /// `write_strip` and will return an error otherwise.
515    pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> {
516        if self.strip_idx != 0 {
517            return Err(io::Error::new(
518                io::ErrorKind::InvalidInput,
519                "Cannot change strip size after data was written",
520            )
521            .into());
522        }
523        // Write tag as 32 bits
524        self.encoder.write_tag(Tag::RowsPerStrip, value)?;
525
526        let value: u64 = value as u64;
527        self.strip_count = (self.height as u64 + value - 1) / value;
528        self.rows_per_strip = value;
529
530        Ok(())
531    }
532
533    fn finish_internal(&mut self) -> TiffResult<()> {
534        self.encoder
535            .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?;
536        self.encoder.write_tag(
537            Tag::StripByteCounts,
538            K::convert_slice(&self.strip_byte_count),
539        )?;
540        self.dropped = true;
541
542        self.encoder.finish_internal()
543    }
544
545    /// Get a reference of the underlying `DirectoryEncoder`
546    pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> {
547        &mut self.encoder
548    }
549
550    /// Write out image and ifd directory.
551    pub fn finish(mut self) -> TiffResult<()> {
552        self.finish_internal()
553    }
554}
555
556impl<'a, W: Write + Seek, C: ColorType, K: TiffKind, D: Compression> Drop
557    for ImageEncoder<'a, W, C, K, D>
558{
559    fn drop(&mut self) {
560        if !self.dropped {
561            let _ = self.finish_internal();
562        }
563    }
564}
565
566struct DirectoryEntry<S> {
567    data_type: u16,
568    count: S,
569    data: Vec<u8>,
570}
571
572/// Trait to abstract over Tiff/BigTiff differences.
573///
574/// Implemented for [`TiffKindStandard`] and [`TiffKindBig`].
575pub trait TiffKind {
576    /// The type of offset fields, `u32` for normal Tiff, `u64` for BigTiff.
577    type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue;
578
579    /// Needed for the `convert_slice` method.
580    type OffsetArrayType: ?Sized + TiffValue;
581
582    /// Write the (Big)Tiff header.
583    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
584
585    /// Convert a file offset to `Self::OffsetType`.
586    ///
587    /// This returns an error for normal Tiff if the offset is larger than `u32::MAX`.
588    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>;
589
590    /// Write an offset value to the given writer.
591    ///
592    /// Like `convert_offset`, this errors if `offset > u32::MAX` for normal Tiff.
593    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>;
594
595    /// Write the IFD entry count field with the given `count` value.
596    ///
597    /// The entry count field is an `u16` for normal Tiff and `u64` for BigTiff. Errors
598    /// if the given `usize` is larger than the representable values.
599    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>;
600
601    /// Internal helper method for satisfying Rust's type checker.
602    ///
603    /// The `TiffValue` trait is implemented for both primitive values (e.g. `u8`, `u32`) and
604    /// slices of primitive values (e.g. `[u8]`, `[u32]`). However, this is not represented in
605    /// the type system, so there is no guarantee that that for all `T: TiffValue` there is also
606    /// an implementation of `TiffValue` for `[T]`. This method works around that problem by
607    /// providing a conversion from `[T]` to some value that implements `TiffValue`, thereby
608    /// making all slices of `OffsetType` usable with `write_tag` and similar methods.
609    ///
610    /// Implementations of this trait should always set `OffsetArrayType` to `[OffsetType]`.
611    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType;
612}
613
614/// Create a standard Tiff file.
615pub struct TiffKindStandard;
616
617impl TiffKind for TiffKindStandard {
618    type OffsetType = u32;
619    type OffsetArrayType = [u32];
620
621    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
622        write_tiff_header(writer)?;
623        // blank the IFD offset location
624        writer.write_u32(0)?;
625
626        Ok(())
627    }
628
629    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
630        Ok(Self::OffsetType::try_from(offset)?)
631    }
632
633    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
634        writer.write_u32(u32::try_from(offset)?)?;
635        Ok(())
636    }
637
638    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
639        writer.write_u16(u16::try_from(count)?)?;
640
641        Ok(())
642    }
643
644    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
645        slice
646    }
647}
648
649/// Create a BigTiff file.
650pub struct TiffKindBig;
651
652impl TiffKind for TiffKindBig {
653    type OffsetType = u64;
654    type OffsetArrayType = [u64];
655
656    fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
657        write_bigtiff_header(writer)?;
658        // blank the IFD offset location
659        writer.write_u64(0)?;
660
661        Ok(())
662    }
663
664    fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
665        Ok(offset)
666    }
667
668    fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
669        writer.write_u64(offset)?;
670        Ok(())
671    }
672
673    fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
674        writer.write_u64(u64::try_from(count)?)?;
675        Ok(())
676    }
677
678    fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
679        slice
680    }
681}