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::{
15 ByteOrder, CompressionMethod, ExtraSamples, IfdPointer, PhotometricInterpretation,
16 ResolutionUnit, SampleFormat, Tag, Type, ValueBuffer,
17 },
18 Directory, TiffError, TiffFormatError,
19};
20
21pub mod colortype;
22pub mod compression;
23mod tiff_value;
24mod writer;
25
26use self::colortype::*;
27use self::compression::Compression as Comp;
28use self::compression::*;
29use self::writer::*;
30
31pub type Predictor = crate::tags::Predictor;
40#[cfg(feature = "deflate")]
41pub type DeflateLevel = compression::DeflateLevel;
42
43#[derive(Clone, Copy, PartialEq, Default)]
44pub enum Compression {
45 #[default]
46 Uncompressed,
47 #[cfg(feature = "lzw")]
48 Lzw,
49 #[cfg(feature = "deflate")]
50 Deflate(DeflateLevel),
51 Packbits,
52}
53
54impl Compression {
55 fn tag(&self) -> CompressionMethod {
56 match self {
57 Compression::Uncompressed => CompressionMethod::None,
58 #[cfg(feature = "lzw")]
59 Compression::Lzw => CompressionMethod::LZW,
60 #[cfg(feature = "deflate")]
61 Compression::Deflate(_) => CompressionMethod::Deflate,
62 Compression::Packbits => CompressionMethod::PackBits,
63 }
64 }
65
66 fn get_algorithm(&self) -> Compressor {
67 match self {
68 Compression::Uncompressed => compression::Uncompressed {}.get_algorithm(),
69 #[cfg(feature = "lzw")]
70 Compression::Lzw => compression::Lzw {}.get_algorithm(),
71 #[cfg(feature = "deflate")]
72 Compression::Deflate(level) => compression::Deflate::with_level(*level).get_algorithm(),
73 Compression::Packbits => compression::Packbits {}.get_algorithm(),
74 }
75 }
76}
77
78pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> {
104 writer: TiffWriter<W>,
105 kind: PhantomData<K>,
106 predictor: Predictor,
107 compression: Compression,
108 last_ifd_chain: NonZeroU64,
110}
111
112impl<W: Write + Seek> TiffEncoder<W> {
114 pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> {
119 TiffEncoder::new_generic(writer)
120 }
121}
122
123impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> {
125 pub fn new_big(writer: W) -> TiffResult<Self> {
130 TiffEncoder::new_generic(writer)
131 }
132}
133
134impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
136 pub fn new_generic(writer: W) -> TiffResult<Self> {
138 let mut writer = TiffWriter::new(writer);
139 K::write_header(&mut writer)?;
140
141 let last_ifd_chain = NonZeroU64::new(writer.previous_ifd_pointer::<K>())
142 .expect("Header is at a non-zero offset");
143
144 Ok(TiffEncoder {
145 writer,
146 kind: PhantomData,
147 predictor: Predictor::None,
148 compression: Compression::Uncompressed,
149 last_ifd_chain,
150 })
151 }
152
153 pub fn with_predictor(mut self, predictor: Predictor) -> Self {
158 self.predictor = predictor;
159
160 self
161 }
162
163 pub fn with_compression(mut self, compression: Compression) -> Self {
165 self.compression = compression;
166
167 self
168 }
169
170 #[deprecated = "`image_directory` replaced the old behavior and clarifies the intent"]
172 #[doc(hidden)]
173 pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
174 Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
175 }
176
177 pub fn image_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
183 Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)
184 }
185
186 pub fn extra_directory(&mut self) -> TiffResult<DirectoryEncoder<'_, W, K>> {
191 Self::unchained_directory(&mut self.writer)
192 }
193
194 pub fn new_image<C: ColorType>(
196 &mut self,
197 width: u32,
198 height: u32,
199 ) -> TiffResult<ImageEncoder<'_, W, C, K>> {
200 let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
201 ImageEncoder::new(encoder, width, height, self.compression, self.predictor)
202 }
203
204 pub fn write_image<C: ColorType>(
206 &mut self,
207 width: u32,
208 height: u32,
209 data: &[C::Inner],
210 ) -> TiffResult<()>
211 where
212 [C::Inner]: TiffValue,
213 {
214 let encoder = Self::chain_directory(&mut self.writer, &mut self.last_ifd_chain)?;
215 let image: ImageEncoder<W, C, K> =
216 ImageEncoder::new(encoder, width, height, self.compression, self.predictor)?;
217 image.write_data(data)
218 }
219
220 fn chain_directory<'lt>(
221 writer: &'lt mut TiffWriter<W>,
222 last_ifd_chain: &'lt mut NonZeroU64,
223 ) -> TiffResult<DirectoryEncoder<'lt, W, K>> {
224 let last_ifd = *last_ifd_chain;
225 DirectoryEncoder::new(writer, Some(last_ifd), Some(last_ifd_chain))
226 }
227
228 fn unchained_directory(writer: &mut TiffWriter<W>) -> TiffResult<DirectoryEncoder<'_, W, K>> {
229 DirectoryEncoder::new(writer, None, None)
230 }
231}
232
233pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
238 writer: &'a mut TiffWriter<W>,
239 chained_ifd_pos: Option<NonZeroU64>,
241 write_chain: Option<&'a mut NonZeroU64>,
243 kind: PhantomData<K>,
244 directory: Directory,
246 dropped: bool,
247}
248
249#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
257pub struct DirectoryOffset<K: TiffKind> {
258 pub offset: K::OffsetType,
265 pub pointer: IfdPointer,
267 ifd_chain: NonZeroU64,
271 kind: PhantomData<K>,
273}
274
275impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
276 fn new(
279 writer: &'a mut TiffWriter<W>,
280 chained_ifd_pos: Option<NonZeroU64>,
281 chain_into: Option<&'a mut NonZeroU64>,
282 ) -> TiffResult<Self> {
283 writer.pad_word_boundary()?; Ok(Self {
285 writer,
286 chained_ifd_pos,
287 write_chain: chain_into,
288 kind: PhantomData,
289 directory: Directory::empty(),
290 dropped: false,
291 })
292 }
293
294 pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> {
296 let mut bytes = Vec::with_capacity(value.bytes());
299 {
300 let mut writer = TiffWriter::new(&mut bytes);
301 value.write(&mut writer)?;
302 }
303
304 let entry = Self::write_entry_inner(
305 self.writer,
306 DirectoryEntry {
307 data_type: <T>::FIELD_TYPE,
308 count: value.count().try_into()?,
309 data: bytes.into(),
310 },
311 )?;
312
313 self.directory.extend([(tag, entry)]);
314
315 Ok(())
316 }
317
318 pub fn write_tag_buf(&mut self, tag: Tag, value: &ValueBuffer) -> TiffResult<()> {
327 let entry = self.write_entry_buf(value)?;
328 self.directory.extend([(tag, entry)]);
329
330 Ok(())
331 }
332
333 pub fn write_data<T: TiffValue>(&mut self, value: T) -> TiffResult<u64> {
340 let offset = self.writer.offset();
341 value.write(self.writer)?;
342 Ok(offset)
343 }
344
345 pub fn write_data_buf(&mut self, value: &ValueBuffer) -> TiffResult<u64> {
354 self.check_value_byteorder(value)?;
355 let offset = self.writer.offset();
356 self.writer.write_bytes(value.as_bytes())?;
357 Ok(offset)
358 }
359
360 pub fn write_entry<T: TiffValue>(&mut self, value: T) -> TiffResult<Entry> {
365 Self::write_entry_inner(
366 self.writer,
367 DirectoryEntry {
368 data_type: T::FIELD_TYPE,
369 count: K::convert_offset(value.count() as u64)?,
370 data: value.data(),
375 },
376 )
377 }
378
379 pub fn write_entry_buf(&mut self, value: &ValueBuffer) -> TiffResult<Entry> {
387 self.check_value_byteorder(value)?;
388
389 Self::write_entry_inner(
390 self.writer,
391 DirectoryEntry {
392 data_type: value.data_type(),
393 count: K::convert_offset(value.count())?,
394 data: value.as_bytes().into(),
395 },
396 )
397 }
398
399 pub fn write_entry_bytes(&mut self, ty: Type, data: &[u8]) -> TiffResult<Entry> {
406 if data.len() % usize::from(ty.byte_len()) != 0 {
407 return Err(TiffError::UsageError(UsageError::MismatchedEntryLength {
408 ty,
409 found: data.len(),
410 }));
411 }
412
413 let count = data.len() / usize::from(ty.byte_len());
414 let count = u64::try_from(count)?;
415
416 Self::write_entry_inner(
417 self.writer,
418 DirectoryEntry {
419 data_type: ty,
420 count: K::convert_offset(count)?,
421 data: data.into(),
422 },
423 )
424 }
425
426 pub fn extend_from(&mut self, dir: &Directory) {
433 let entries = dir.iter().map(|(tag, val)| (tag, val.clone()));
434 self.directory.extend(entries);
435 }
436
437 pub fn set_parent(&mut self, offset: &DirectoryOffset<K>) {
444 self.chained_ifd_pos = Some(offset.ifd_chain);
445 }
446
447 pub fn finish(mut self) -> TiffResult<()> {
449 self.finish_internal()?;
450 Ok(())
451 }
452
453 pub fn finish_with_offsets(mut self) -> TiffResult<DirectoryOffset<K>> {
459 self.finish_internal()
460 }
461
462 fn write_directory(&mut self) -> TiffResult<u64> {
463 let offset = self.writer.offset();
465 K::write_entry_count(self.writer, self.directory.len())?;
466
467 let offset_bytes = mem::size_of::<K::OffsetType>();
468 for (tag, entry) in self.directory.iter() {
469 self.writer.write_u16(tag.to_u16())?;
470 self.writer.write_u16(entry.field_type().to_u16())?;
471 let count = K::convert_offset(entry.count())?;
472 count.write(self.writer)?;
473 self.writer.write_bytes(&entry.offset()[..offset_bytes])?;
474 }
475
476 Ok(offset)
477 }
478
479 fn write_entry_inner(
483 writer: &mut TiffWriter<W>,
484 value: DirectoryEntry<K::OffsetType>,
485 ) -> TiffResult<Entry> {
486 let DirectoryEntry {
487 data: ref bytes,
488 ref count,
489 data_type,
490 } = value;
491
492 let in_entry_bytes = mem::size_of::<K::OffsetType>();
493
494 let mut offset_bytes = [0; 8];
495
496 if bytes.len() > in_entry_bytes {
497 let offset = writer.offset();
498 writer.write_bytes(bytes)?;
499
500 let offset = K::convert_offset(offset)?;
501 offset_bytes[..offset.bytes()].copy_from_slice(&offset.data());
502 } else {
503 offset_bytes[..bytes.len()].copy_from_slice(bytes);
506 }
507
508 let mut count_bytes = [0; 8];
512 debug_assert!(in_entry_bytes == 4 || in_entry_bytes == 8);
513 count_bytes[..count.bytes()].copy_from_slice(&count.data());
515
516 Ok(if in_entry_bytes == 4 {
517 let count = u32::from_ne_bytes(count_bytes[..4].try_into().unwrap());
518 Entry::new(data_type, count, offset_bytes[..4].try_into().unwrap())
519 } else {
520 debug_assert_eq!(in_entry_bytes, 8);
521 let count = u64::from_ne_bytes(count_bytes);
522 Entry::new_u64(data_type, count, offset_bytes)
523 })
524 }
525
526 fn check_value_byteorder(&self, value: &ValueBuffer) -> TiffResult<()> {
527 if value.byte_order() != ByteOrder::native() {
529 Err(TiffError::UsageError(UsageError::ByteOrderMismatch))
530 } else {
531 Ok(())
532 }
533 }
534
535 fn last_written(&self) -> u64 {
537 self.writer.last_written()
538 }
539
540 fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
541 let ifd_pointer = self.write_directory()?;
542 let offset = K::convert_offset(ifd_pointer)?;
543
544 if let Some(prior) = self.chained_ifd_pos {
545 let curr_pos = self.writer.offset();
546
547 self.writer.goto_offset(prior.get())?;
548 K::write_offset(self.writer, ifd_pointer)?;
553
554 self.writer.goto_offset(curr_pos)?;
555 }
556
557 K::write_offset(self.writer, 0)?;
558
559 let ifd_chain = NonZeroU64::new(self.writer.previous_ifd_pointer::<K>())
560 .expect("IFD chain field is at a non-zero offset");
561
562 if let Some(prior) = self.write_chain.take() {
563 *prior = ifd_chain;
564 }
565
566 self.dropped = true;
567
568 Ok(DirectoryOffset {
569 pointer: IfdPointer(ifd_pointer),
570 offset,
571 ifd_chain,
572 kind: PhantomData,
573 })
574 }
575}
576
577impl<'a, W: Write + Seek, K: TiffKind> Drop for DirectoryEncoder<'a, W, K> {
578 fn drop(&mut self) {
579 if !self.dropped {
580 let _ = self.finish_internal();
581 }
582 }
583}
584
585pub 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
635impl<'a, W: 'a + Write + Seek, T: ColorType, K: TiffKind> ImageEncoder<'a, W, T, K> {
636 fn sanity_check(compression: Compression, predictor: Predictor) -> TiffResult<()> {
637 match (predictor, compression, T::SAMPLE_FORMAT[0]) {
638 (Predictor::Horizontal, _, SampleFormat::IEEEFP | SampleFormat::Void) => {
639 Err(TiffError::UsageError(UsageError::PredictorIncompatible))
640 }
641 (Predictor::FloatingPoint, _, _) => {
642 Err(TiffError::UsageError(UsageError::PredictorUnavailable))
643 }
644 _ => Ok(()),
645 }
646 }
647
648 fn new(
649 mut encoder: DirectoryEncoder<'a, W, K>,
650 width: u32,
651 height: u32,
652 compression: Compression,
653 predictor: Predictor,
654 ) -> TiffResult<Self> {
655 if width == 0 || height == 0 {
656 return Err(TiffError::FormatError(TiffFormatError::InvalidDimensions(
657 width, height,
658 )));
659 }
660
661 Self::sanity_check(compression, predictor)?;
662
663 let row_samples = u64::from(width) * u64::try_from(<T>::BITS_PER_SAMPLE.len())?;
664 let row_bytes = row_samples * u64::from(<T::Inner>::BYTE_LEN);
665
666 let rows_per_strip = {
669 match compression.tag() {
670 CompressionMethod::PackBits => 1, _ => 1_000_000_u64.div_ceil(row_bytes),
672 }
673 };
674
675 let strip_count = u64::from(height).div_ceil(rows_per_strip);
676
677 encoder.write_tag(Tag::ImageWidth, width)?;
678 encoder.write_tag(Tag::ImageLength, height)?;
679 encoder.write_tag(Tag::Compression, compression.tag().to_u16())?;
680 encoder.write_tag(Tag::Predictor, predictor.to_u16())?;
681
682 encoder.write_tag(Tag::PhotometricInterpretation, <T>::TIFF_VALUE.to_u16())?;
683
684 if matches!(<T>::TIFF_VALUE, PhotometricInterpretation::YCbCr) {
685 encoder.write_tag(Tag::ChromaSubsampling, &[1u16, 1u16][..])?;
688 }
689
690 encoder.write_tag(Tag::RowsPerStrip, u32::try_from(rows_per_strip)?)?;
691
692 encoder.write_tag(
693 Tag::SamplesPerPixel,
694 u16::try_from(<T>::BITS_PER_SAMPLE.len())?,
695 )?;
696 encoder.write_tag(Tag::XResolution, Rational { n: 1, d: 1 })?;
697 encoder.write_tag(Tag::YResolution, Rational { n: 1, d: 1 })?;
698 encoder.write_tag(Tag::ResolutionUnit, ResolutionUnit::None)?;
699
700 Ok(ImageEncoder {
701 encoder,
702 strip_count,
703 strip_idx: 0,
704 row_samples,
705 rows_per_strip,
706 extra_samples: vec![],
707 width,
708 height,
709 strip_offsets: Vec::new(),
710 strip_byte_count: Vec::new(),
711 dropped: false,
712 compression,
713 predictor,
714 _phantom: ::std::marker::PhantomData,
715 })
716 }
717
718 pub fn extra_samples(&mut self, extra: &[ExtraSamples]) -> Result<(), TiffError> {
719 if self.strip_idx != 0 {
720 return Err(TiffError::UsageError(
721 UsageError::ReconfiguredAfterImageWrite,
722 ));
723 }
724
725 let samples = self.extra_samples.len() + extra.len() + <T>::BITS_PER_SAMPLE.len();
726 let row_samples = u64::from(self.width) * u64::try_from(samples)?;
727
728 self.extra_samples
729 .extend(extra.iter().map(ExtraSamples::to_u16));
730
731 self.encoder
732 .write_tag(Tag::ExtraSamples, &self.extra_samples[..])?;
733
734 self.row_samples = row_samples;
735
736 Ok(())
737 }
738
739 pub fn next_strip_sample_count(&self) -> u64 {
741 if self.strip_idx >= self.strip_count {
742 return 0;
743 }
744
745 let raw_start_row = self.strip_idx * self.rows_per_strip;
746 let start_row = cmp::min(u64::from(self.height), raw_start_row);
747 let end_row = cmp::min(u64::from(self.height), raw_start_row + self.rows_per_strip);
748
749 (end_row - start_row) * self.row_samples
750 }
751
752 pub fn write_strip(&mut self, value: &[T::Inner]) -> TiffResult<()>
754 where
755 [T::Inner]: TiffValue,
756 {
757 let samples = self.next_strip_sample_count();
758 if u64::try_from(value.len())? != samples {
759 return Err(io::Error::new(
760 io::ErrorKind::InvalidData,
761 "Slice is wrong size for strip",
762 )
763 .into());
764 }
765
766 let offset = match self.predictor {
768 Predictor::None => self.encoder.write_data(value)?,
769 Predictor::Horizontal => {
770 let mut row_result = Vec::with_capacity(value.len());
771 for row in value.chunks_exact(self.row_samples as usize) {
772 T::horizontal_predict(row, &mut row_result);
773 }
774 self.encoder.write_data(row_result.as_slice())?
775 }
776 _ => unimplemented!(),
777 };
778
779 let byte_count = self.encoder.last_written() as usize;
780
781 self.strip_offsets.push(K::convert_offset(offset)?);
782 self.strip_byte_count.push(byte_count.try_into()?);
783
784 self.strip_idx += 1;
785 Ok(())
786 }
787
788 pub fn write_data(mut self, data: &[T::Inner]) -> TiffResult<()>
790 where
791 [T::Inner]: TiffValue,
792 {
793 let num_pix = usize::try_from(self.width)?
794 .checked_mul(usize::try_from(self.height)?)
795 .ok_or_else(|| {
796 io::Error::new(
797 io::ErrorKind::InvalidInput,
798 "Image width * height exceeds usize",
799 )
800 })?;
801 if data.len() < num_pix {
802 return Err(io::Error::new(
803 io::ErrorKind::InvalidData,
804 "Input data slice is undersized for provided dimensions",
805 )
806 .into());
807 }
808
809 self.encoder
810 .writer
811 .set_compression(self.compression.get_algorithm());
812
813 let mut idx = 0;
814 while self.next_strip_sample_count() > 0 {
815 let sample_count = usize::try_from(self.next_strip_sample_count())?;
816 self.write_strip(&data[idx..idx + sample_count])?;
817 idx += sample_count;
818 }
819
820 self.encoder.writer.reset_compression();
821 self.finish()?;
822 Ok(())
823 }
824
825 pub fn resolution(&mut self, unit: ResolutionUnit, value: Rational) {
827 self.encoder
828 .write_tag(Tag::ResolutionUnit, unit.to_u16())
829 .unwrap();
830 self.encoder
831 .write_tag(Tag::XResolution, value.clone())
832 .unwrap();
833 self.encoder.write_tag(Tag::YResolution, value).unwrap();
834 }
835
836 pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
838 self.encoder
839 .write_tag(Tag::ResolutionUnit, unit.to_u16())
840 .unwrap();
841 }
842
843 pub fn x_resolution(&mut self, value: Rational) {
845 self.encoder.write_tag(Tag::XResolution, value).unwrap();
846 }
847
848 pub fn y_resolution(&mut self, value: Rational) {
850 self.encoder.write_tag(Tag::YResolution, value).unwrap();
851 }
852
853 pub fn rows_per_strip(&mut self, value: u32) -> TiffResult<()> {
858 if self.strip_idx != 0 {
859 return Err(io::Error::new(
860 io::ErrorKind::InvalidInput,
861 "Cannot change strip size after data was written",
862 )
863 .into());
864 }
865 self.encoder.write_tag(Tag::RowsPerStrip, value)?;
867
868 let value: u64 = value as u64;
869 self.strip_count = (self.height as u64).div_ceil(value);
870 self.rows_per_strip = value;
871
872 Ok(())
873 }
874
875 fn finish_internal(&mut self) -> TiffResult<DirectoryOffset<K>> {
876 if self.extra_samples.is_empty() {
877 self.encoder
878 .write_tag(Tag::BitsPerSample, <T>::BITS_PER_SAMPLE)?;
879 } else {
880 let mut sample_format: Vec<_> = <T>::BITS_PER_SAMPLE.to_vec();
881 let replicated =
882 core::iter::repeat_n(<T>::BITS_PER_SAMPLE[0], self.extra_samples.len());
883 sample_format.extend(replicated);
884
885 self.encoder
886 .write_tag(Tag::BitsPerSample, &sample_format[..])?;
887
888 self.encoder.write_tag(
889 Tag::SamplesPerPixel,
890 u16::try_from(<T>::BITS_PER_SAMPLE.len() + self.extra_samples.len())?,
891 )?;
892 }
893
894 let mut sample_format: Vec<_> = <T>::SAMPLE_FORMAT.iter().map(|s| s.to_u16()).collect();
895 let extra_format = sample_format
896 .first()
897 .copied()
898 .unwrap_or(SampleFormat::Void.to_u16());
903
904 sample_format.extend(core::iter::repeat_n(extra_format, self.extra_samples.len()));
905
906 self.encoder
907 .write_tag(Tag::SampleFormat, &sample_format[..])?;
908
909 self.encoder
910 .write_tag(Tag::StripOffsets, K::convert_slice(&self.strip_offsets))?;
911 self.encoder.write_tag(
912 Tag::StripByteCounts,
913 K::convert_slice(&self.strip_byte_count),
914 )?;
915 self.dropped = true;
916
917 self.encoder.finish_internal()
918 }
919
920 pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> {
922 &mut self.encoder
923 }
924
925 pub fn finish(mut self) -> TiffResult<()> {
927 self.finish_internal()?;
928 Ok(())
929 }
930}
931
932impl<'a, W: Write + Seek, C: ColorType, K: TiffKind> Drop for ImageEncoder<'a, W, C, K> {
933 fn drop(&mut self) {
934 if !self.dropped {
935 let _ = self.finish_internal();
936 }
937 }
938}
939
940struct DirectoryEntry<'data, S> {
941 data_type: Type,
942 count: S,
943 data: std::borrow::Cow<'data, [u8]>,
944}
945
946pub trait TiffKind {
950 type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue;
952
953 type OffsetArrayType: ?Sized + TiffValue;
955
956 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
958
959 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>;
963
964 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>;
968
969 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>;
974
975 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType;
986}
987
988impl<K: TiffKind> DirectoryOffset<K> {
989 pub fn new(pointer: IfdPointer, dir: &Directory) -> TiffResult<Self> {
1034 let offset = K::convert_offset(pointer.0)?;
1035 let encoded = dir.encoded_len::<K>();
1036 let offset_field_offset = encoded - mem::size_of_val(&offset) as u64;
1037
1038 let ifd_chain = pointer
1039 .0
1040 .checked_add(offset_field_offset)
1041 .and_then(NonZeroU64::new)
1042 .ok_or(TiffError::UsageError(UsageError::ZeroIfdPointer))?;
1043
1044 Ok(DirectoryOffset {
1045 pointer,
1046 offset,
1047 ifd_chain,
1048 kind: PhantomData,
1049 })
1050 }
1051}
1052
1053pub struct TiffKindStandard;
1055
1056impl TiffKind for TiffKindStandard {
1057 type OffsetType = u32;
1058 type OffsetArrayType = [u32];
1059
1060 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
1061 write_tiff_header(writer)?;
1062 writer.write_u32(0)?;
1064
1065 Ok(())
1066 }
1067
1068 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
1069 Ok(Self::OffsetType::try_from(offset)?)
1070 }
1071
1072 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
1073 writer.write_u32(u32::try_from(offset)?)?;
1074 Ok(())
1075 }
1076
1077 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
1078 writer.write_u16(u16::try_from(count)?)?;
1079
1080 Ok(())
1081 }
1082
1083 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
1084 slice
1085 }
1086}
1087
1088pub struct TiffKindBig;
1090
1091impl TiffKind for TiffKindBig {
1092 type OffsetType = u64;
1093 type OffsetArrayType = [u64];
1094
1095 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()> {
1096 write_bigtiff_header(writer)?;
1097 writer.write_u64(0)?;
1099
1100 Ok(())
1101 }
1102
1103 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType> {
1104 Ok(offset)
1105 }
1106
1107 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()> {
1108 writer.write_u64(offset)?;
1109 Ok(())
1110 }
1111
1112 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()> {
1113 writer.write_u64(u64::try_from(count)?)?;
1114 Ok(())
1115 }
1116
1117 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType {
1118 slice
1119 }
1120}
1121
1122#[test]
1123fn 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 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}