1pub use tiff_value::*;
2
3use std::{
4 cmp,
5 io::{self, Seek, Write},
6 marker::PhantomData,
7 mem,
8 num::{NonZeroU64, TryFromIntError},
9};
10
11use crate::{
12 decoder::ifd::Entry,
13 error::{TiffResult, UsageError},
14 tags::{CompressionMethod, IfdPointer, ResolutionUnit, SampleFormat, Tag, Type},
15 Directory, TiffError, TiffFormatError,
16};
17
18pub mod colortype;
19pub mod compression;
20mod tiff_value;
21mod writer;
22
23use self::colortype::*;
24use self::compression::Compression as Comp;
25use self::compression::*;
26use self::writer::*;
27
28pub type Predictor = crate::tags::Predictor;
37#[cfg(feature = "deflate")]
38pub type DeflateLevel = compression::DeflateLevel;
39
40#[derive(Clone, Copy, PartialEq)]
41pub enum Compression {
42 Uncompressed,
43 #[cfg(feature = "lzw")]
44 Lzw,
45 #[cfg(feature = "deflate")]
46 Deflate(DeflateLevel),
47 Packbits,
48}
49
50impl Default for Compression {
51 fn default() -> Self {
52 Self::Uncompressed
53 }
54}
55
56impl Compression {
57 fn tag(&self) -> CompressionMethod {
58 match self {
59 Compression::Uncompressed => CompressionMethod::None,
60 #[cfg(feature = "lzw")]
61 Compression::Lzw => CompressionMethod::LZW,
62 #[cfg(feature = "deflate")]
63 Compression::Deflate(_) => CompressionMethod::Deflate,
64 Compression::Packbits => CompressionMethod::PackBits,
65 }
66 }
67
68 fn get_algorithm(&self) -> Compressor {
69 match self {
70 Compression::Uncompressed => compression::Uncompressed {}.get_algorithm(),
71 #[cfg(feature = "lzw")]
72 Compression::Lzw => compression::Lzw {}.get_algorithm(),
73 #[cfg(feature = "deflate")]
74 Compression::Deflate(level) => compression::Deflate::with_level(*level).get_algorithm(),
75 Compression::Packbits => compression::Packbits {}.get_algorithm(),
76 }
77 }
78}
79
80pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> {
106 writer: TiffWriter<W>,
107 kind: PhantomData<K>,
108 predictor: Predictor,
109 compression: Compression,
110 last_ifd_chain: NonZeroU64,
112}
113
114impl<W: Write + Seek> TiffEncoder<W> {
116 pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> {
121 TiffEncoder::new_generic(writer)
122 }
123}
124
125impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> {
127 pub fn new_big(writer: W) -> TiffResult<Self> {
132 TiffEncoder::new_generic(writer)
133 }
134}
135
136impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
138 pub fn new_generic(writer: W) -> TiffResult<Self> {
140 let mut writer = TiffWriter::new(writer);
141 K::write_header(&mut writer)?;
142
143 let last_ifd_chain = NonZeroU64::new(writer.previous_ifd_pointer::<K>())
144 .expect("Header is at a non-zero offset");
145
146 Ok(TiffEncoder {
147 writer,
148 kind: PhantomData,
149 predictor: Predictor::None,
150 compression: Compression::Uncompressed,
151 last_ifd_chain,
152 })
153 }
154
155 pub fn with_predictor(mut self, predictor: Predictor) -> Self {
160 self.predictor = predictor;
161
162 self
163 }
164
165 pub fn with_compression(mut self, compression: Compression) -> Self {
167 self.compression = compression;
168
169 self
170 }
171
172 #[deprecated = "`image_directory` replaced the old behavior and clarifies the intent"]
174 #[doc(hidden)]
175 pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
176 Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
177 }
178
179 pub fn image_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
185 Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
186 }
187
188 pub fn extra_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
193 Self::unchained_directory(&mut self.writer)
194 }
195
196 pub fn new_image<C: ColorType>(
198 &mut self,
199 width: u32,
200 height: u32,
201 ) -> TiffResult<ImageEncoder<'_, W, C, K>> {
202 let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
203 ImageEncoder::new(encoder, width, height, self.compression, self.predictor)
204 }
205
206 pub fn write_image<C: ColorType>(
208 &mut self,
209 width: u32,
210 height: u32,
211 data: &[C::Inner],
212 ) -> TiffResult<()>
213 where
214 [C::Inner]: TiffValue,
215 {
216 let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
217 let image: ImageEncoder<W, C, K> =
218 ImageEncoder::new(encoder, width, height, self.compression, self.predictor)?;
219 image.write_data(data)
220 }
221
222 fn chain_directory<'lt>(
223 writer: &'lt mut TiffWriter<W>,
224 last_ifd_chain: &'lt mut NonZeroU64,
225 ) -> TiffResult<DirectoryEncoder<'lt, W, K>> {
226 let last_ifd = *last_ifd_chain;
227 DirectoryEncoder::new(writer, Some(last_ifd), Some(last_ifd_chain))
228 }
229
230 fn unchained_directory(writer: &mut TiffWriter<W>) -> TiffResult<DirectoryEncoder<'_, W, K>> {
231 DirectoryEncoder::new(writer, None, None)
232 }
233}
234
235pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
240 writer: &'a mut TiffWriter<W>,
241 chained_ifd_pos: Option<NonZeroU64>,
243 write_chain: Option<&'a mut NonZeroU64>,
245 kind: PhantomData<K>,
246 directory: Directory,
248 dropped: bool,
249}
250
251#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
253pub struct DirectoryOffset<K: TiffKind> {
254 pub offset: K::OffsetType,
261 pub pointer: IfdPointer,
263 ifd_chain: NonZeroU64,
265 kind: PhantomData<K>,
267}
268
269impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
270 fn new(
273 writer: &'a mut TiffWriter<W>,
274 chained_ifd_pos: Option<NonZeroU64>,
275 chain_into: Option<&'a mut NonZeroU64>,
276 ) -> TiffResult<Self> {
277 writer.pad_word_boundary()?; Ok(Self {
279 writer,
280 chained_ifd_pos,
281 write_chain: chain_into,
282 kind: PhantomData,
283 directory: Directory::empty(),
284 dropped: false,
285 })
286 }
287
288 pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> {
290 let mut bytes = Vec::with_capacity(value.bytes());
293 {
294 let mut writer = TiffWriter::new(&mut bytes);
295 value.write(&mut writer)?;
296 }
297
298 let entry = Self::write_value(
299 self.writer,
300 &DirectoryEntry {
301 data_type: <T>::FIELD_TYPE,
302 count: value.count().try_into()?,
303 data: bytes,
304 },
305 )?;
306
307 self.directory.extend([(tag, entry)]);
308
309 Ok(())
310 }
311
312 pub fn write_data<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> {
316 let offset = self.writer.offset();
317 value.write(self.writer)?;
318 Ok(offset)
319 }
320
321 pub fn set_parent(&mut self, offset: &DirectoryOffset<K>) {
328 self.chained_ifd_pos = Some(offset.ifd_chain);
329 }
330
331 pub fn finish(mut self) -> TiffResult<()> {
333 self.finish_internal()?;
334 Ok(())
335 }
336
337 pub fn finish_with_offsets(mut self) -> TiffResult<DirectoryOffset<K>> {
338 self.finish_internal()
339 }
340
341 fn write_directory(&mut self) -> TiffResult<u64> {
342 let offset = self.writer.offset();
344 K::write_entry_count(self.writer, self.directory.len())?;
345
346 let offset_bytes = mem::size_of::<K::OffsetType>();
347 for (tag, entry) in self.directory.iter() {
348 self.writer.write_u16(tag.to_u16())?;
349 self.writer.write_u16(entry.field_type().to_u16())?;
350 let count = K::convert_offset(entry.count())?;
351 count.write(self.writer)?;
352 self.writer.write_bytes(&entry.offset()[..offset_bytes])?;
353 }
354
355 Ok(offset)
356 }
357
358 fn write_value(
359 writer: &mut TiffWriter<W>,
360 value: &DirectoryEntry<K::OffsetType>,
361 ) -> TiffResult<Entry> {
362 let &DirectoryEntry {
363 data: ref bytes,
364 ref count,
365 data_type,
366 } = value;
367
368 let in_entry_bytes = mem::size_of::<K::OffsetType>();
369 let mut offset_bytes = [0; 8];
370
371 if bytes.len() > in_entry_bytes {
372 let offset = writer.offset();
373 writer.write_bytes(bytes)?;
374
375 let offset = K::convert_offset(offset)?;
376 offset_bytes[..offset.bytes()].copy_from_slice(&offset.data());
377 } else {
378 offset_bytes[..bytes.len()].copy_from_slice(bytes);
381 }
382
383 let mut count_bytes = [0; 8];
387 count_bytes[..count.bytes()].copy_from_slice(&count.data());
389
390 Ok(if in_entry_bytes == 4 {
391 let count = u32::from_ne_bytes(count_bytes[..4].try_into().unwrap());
392 Entry::new(data_type, count, offset_bytes[..4].try_into().unwrap())
393 } else {
394 debug_assert_eq!(in_entry_bytes, 8);
395 let count = u64::from_ne_bytes(count_bytes);
396 Entry::new_u64(data_type, count, offset_bytes)
397 })
398 }
399
400 fn last_written(&self) -> u64 {
402 self.writer.last_written()
403 }
404
405 fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
406 let ifd_pointer = self.write_directory()?;
407 let offset = K::convert_offset(ifd_pointer)?;
408
409 if let Some(prior) = self.chained_ifd_pos {
410 let curr_pos = self.writer.offset();
411
412 self.writer.goto_offset(prior.get())?;
413 K::write_offset(self.writer, ifd_pointer)?;
418
419 self.writer.goto_offset(curr_pos)?;
420 }
421
422 K::write_offset(self.writer, 0)?;
423
424 let ifd_chain = NonZeroU64::new(self.writer.previous_ifd_pointer::<K>())
425 .expect("IFD chain field is at a non-zero offset");
426
427 if let Some(prior) = self.write_chain.take() {
428 *prior = ifd_chain;
429 }
430
431 self.dropped = true;
432
433 Ok(DirectoryOffset {
434 pointer: IfdPointer(ifd_pointer),
435 offset,
436 ifd_chain,
437 kind: PhantomData,
438 })
439 }
440}
441
442impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> {
443 fn drop(&mut self) {
444 if !self.dropped {
445 let _ = self.finish_internal();
446 }
447 }
448}
449
450pub struct ImageEncoder<'a, W: 'a + Write + Seek, C: ColorType, K: TiffKind> {
484 encoder: DirectoryEncoder<'a, W, K>,
485 strip_idx: u64,
486 strip_count: u64,
487 row_samples: u64,
488 width: u32,
489 height: u32,
490 rows_per_strip: u64,
491 strip_offsets: Vec<K::OffsetType>,
492 strip_byte_count: Vec<K::OffsetType>,
493 dropped: bool,
494 compression: Compression,
495 predictor: Predictor,
496 _phantom: ::std::marker::PhantomData<C>,
497}
498
499impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> {
500 fn sanity_check(compression: Compression, predictor: Predictor) -> TiffResult<()> {
501 match (predictor, compression, T::SAMPLE_FORMAT[0]) {
502 (Predictor::Horizontal, _, SampleFormat::IEEEFP | SampleFormat::Void) => {
503 Err(TiffError::UsageError(UsageError::PredictorIncompatible))
504 }
505 (Predictor::FloatingPoint, _, _) => {
506 Err(TiffError::UsageError(UsageError::PredictorUnavailable))
507 }
508 _ => Ok(()),
509 }
510 }
511
512 fn new(
513 mut encoder: DirectoryEncoder<'a, W, K>,
514 width: u32,
515 height: u32,
516 compression: Compression,
517 predictor: Predictor,
518 ) -> TiffResult<Self> {
519 if width == 0 || height == 0 {
520 return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions(
521 width, height,
522 )));
523 }
524
525 Self::sanity_check(compression, predictor)?;
526
527 let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?;
528 let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
529
530 let rows_per_strip = {
533 match compression.tag() {
534 CompressionMethod::PackBits => 1, _ => 1_000_000_u64.div_ceil(row_bytes),
536 }
537 };
538
539 let strip_count = u64::from(height).div_ceil(rows_per_strip);
540
541 encoder.write_tag(Tag::ImageWidth, width)?;
542 encoder.write_tag(Tag::ImageLength, height)?;
543 encoder.write_tag(Tag::Compression, compression.tag().to_u16())?;
544 encoder.write_tag(Tag::Predictor, predictor.to_u16())?;
545
546 encoder.write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?;
547 let sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect();
548 encoder.write_tag(Tag::SampleFormat, &sample_format[..])?;
549 encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?;
550
551 encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?;
552
553 encoder.write_tag(
554 Tag::SamplesPerPixel,
555 u16::try_from(<T>::BITS_PER_SAMPLE.len())?,
556 )?;
557 encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?;
558 encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?;
559 encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None.to_u16())?;
560
561 Ok(ImageEncoder {
562 encoder,
563 strip_count,
564 strip_idx: 0,
565 row_samples,
566 rows_per_strip,
567 width,
568 height,
569 strip_offsets: Vec::new(),
570 strip_byte_count: Vec::new(),
571 dropped: false,
572 compression,
573 predictor,
574 _phantom: ::std::marker::PhantomData,
575 })
576 }
577
578 pub fn next_strip_sample_count(&self) -> u64 {
580 if self.strip_idx >= self.strip_count {
581 return 0;
582 }
583
584 let raw_start_row = self.strip_idx * self.rows_per_strip;
585 let start_row = cmp::min(u64::from(self.height), raw_start_row);
586 let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip);
587
588 (end_row - start_row) * self.row_samples
589 }
590
591 pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()>
593 where
594 [T::Inner]: TiffValue,
595 {
596 let samples = self.next_strip_sample_count();
597 if u64::try_from(value.len())? != samples {
598 return Err(io::Error::new(
599 io::ErrorKind::InvalidData,
600 "Slice is wrong size for strip",
601 )
602 .into());
603 }
604
605 let offset = match self.predictor {
607 Predictor::None => self.encoder.write_data(value)?,
608 Predictor::Horizontal => {
609 let mut row_result = Vec::with_capacity(value.len());
610 for row in value.chunks_exact(self.row_samples as usize) {
611 T::horizontal_predict(row, &mut row_result);
612 }
613 self.encoder.write_data(row_result.as_slice())?
614 }
615 _ => unimplemented!(),
616 };
617
618 let byte_count = self.encoder.last_written() as usize;
619
620 self.strip_offsets.push(K::convert_offset(offset)?);
621 self.strip_byte_count.push(byte_count.try_into()?);
622
623 self.strip_idx += 1;
624 Ok(())
625 }
626
627 pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()>
629 where
630 [T::Inner]: TiffValue,
631 {
632 let num_pix = usize::try_from(self.width)?
633 .checked_mul(usize::try_from(self.height)?)
634 .ok_or_else(|| {
635 io::Error::new(
636 io::ErrorKind::InvalidInput,
637 "Image width * height exceeds usize",
638 )
639 })?;
640 if data.len() < num_pix {
641 return Err(io::Error::new(
642 io::ErrorKind::InvalidData,
643 "Input data slice is undersized for provided dimensions",
644 )
645 .into());
646 }
647
648 self.encoder
649 .writer
650 .set_compression(self.compression.get_algorithm());
651
652 let mut idx = 0;
653 while self.next_strip_sample_count() > 0 {
654 let sample_count = usize::try_from(self.next_strip_sample_count())?;
655 self.write_strip(&data[idx..idx + sample_count])?;
656 idx += sample_count;
657 }
658
659 self.encoder.writer.reset_compression();
660 self.finish()?;
661 Ok(())
662 }
663
664 pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
666 self.encoder
667 .write_tag(Tag::ResolutionUnit, unit.to_u16())
668 .unwrap();
669 self.encoder
670 .write_tag(Tag::XResolution, value.clone())
671 .unwrap();
672 self.encoder.write_tag(Tag::YResolution, value).unwrap();
673 }
674
675 pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
677 self.encoder
678 .write_tag(Tag::ResolutionUnit, unit.to_u16())
679 .unwrap();
680 }
681
682 pub fn x_resolution(&mut self, value: Rational) {
684 self.encoder.write_tag(Tag::XResolution, value).unwrap();
685 }
686
687 pub fn y_resolution(&mut self, value: Rational) {
689 self.encoder.write_tag(Tag::YResolution, value).unwrap();
690 }
691
692 pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> {
697 if self.strip_idx != 0 {
698 return Err(io::Error::new(
699 io::ErrorKind::InvalidInput,
700 "Cannot change strip size after data was written",
701 )
702 .into());
703 }
704 self.encoder.write_tag(Tag::RowsPerStrip, value)?;
706
707 let value: u64 = value as u64;
708 self.strip_count = (self.height as u64).div_ceil(value);
709 self.rows_per_strip = value;
710
711 Ok(())
712 }
713
714 fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
715 self.encoder
716 .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?;
717 self.encoder.write_tag(
718 Tag::StripByteCounts,
719 K::convert_slice(&self.strip_byte_count),
720 )?;
721 self.dropped = true;
722
723 self.encoder.finish_internal()
724 }
725
726 pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> {
728 &mut self.encoder
729 }
730
731 pub fn finish(mut self) -> TiffResult<()> {
733 self.finish_internal()?;
734 Ok(())
735 }
736}
737
738impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W, C, K> {
739 fn drop(&mut self) {
740 if !self.dropped {
741 let _ = self.finish_internal();
742 }
743 }
744}
745
746struct DirectoryEntry<S> {
747 data_type: Type,
748 count: S,
749 data: Vec<u8>,
750}
751
752pub trait TiffKind {
756 type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue;
758
759 type OffsetArrayType: ?Sized + TiffValue;
761
762 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
764
765 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>;
769
770 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>;
774
775 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>;
780
781 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType;
792}
793
794pub struct TiffKindStandard;
796
797impl TiffKind for TiffKindStandard {
798 type OffsetType = u32;
799 type OffsetArrayType = [u32];
800
801 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
802 write_tiff_header(writer)?;
803 writer.write_u32(0)?;
805
806 Ok(())
807 }
808
809 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
810 Ok(Self::OffsetType::try_from(offset)?)
811 }
812
813 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
814 writer.write_u32(u32::try_from(offset)?)?;
815 Ok(())
816 }
817
818 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
819 writer.write_u16(u16::try_from(count)?)?;
820
821 Ok(())
822 }
823
824 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
825 slice
826 }
827}
828
829pub struct TiffKindBig;
831
832impl TiffKind for TiffKindBig {
833 type OffsetType = u64;
834 type OffsetArrayType = [u64];
835
836 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
837 write_bigtiff_header(writer)?;
838 writer.write_u64(0)?;
840
841 Ok(())
842 }
843
844 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
845 Ok(offset)
846 }
847
848 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
849 writer.write_u64(offset)?;
850 Ok(())
851 }
852
853 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
854 writer.write_u64(u64::try_from(count)?)?;
855 Ok(())
856 }
857
858 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
859 slice
860 }
861}