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
28pub struct TiffEncoder<W, K: TiffKind = TiffKindStandard> {
54 writer: TiffWriter<W>,
55 kind: PhantomData<K>,
56}
57
58impl<W: Write + Seek> TiffEncoder<W> {
60 pub fn new(writer: W) -> TiffResult<TiffEncoder<W, TiffKindStandard>> {
65 TiffEncoder::new_generic(writer)
66 }
67}
68
69impl<W: Write + Seek> TiffEncoder<W, TiffKindBig> {
71 pub fn new_big(writer: W) -> TiffResult<Self> {
76 TiffEncoder::new_generic(writer)
77 }
78}
79
80impl<W: Write + Seek, K: TiffKind> TiffEncoder<W, K> {
82 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 pub fn new_directory(&mut self) -> TiffResult<DirectoryEncoder<W, K>> {
96 DirectoryEncoder::new(&mut self.writer)
97 }
98
99 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 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 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 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
153pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
158 writer: &'a mut TiffWriter<W>,
159 dropped: bool,
160 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 let ifd_pointer_pos = writer.offset() - mem::size_of::<K::OffsetType>() as u64;
169 writer.pad_word_boundary()?; Ok(DirectoryEncoder {
171 writer,
172 dropped: false,
173 ifd_pointer_pos,
174 ifd: BTreeMap::new(),
175 })
176 }
177
178 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 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 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 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 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
283pub 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 let rows_per_strip = {
365 match D::COMPRESSION_METHOD {
366 CompressionMethod::PackBits => 1, _ => (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 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 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 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 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 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 pub fn resolution_unit(&mut self, unit: ResolutionUnit) {
496 self.encoder
497 .write_tag(Tag::ResolutionUnit, unit.to_u16())
498 .unwrap();
499 }
500
501 pub fn x_resolution(&mut self, value: Rational) {
503 self.encoder.write_tag(Tag::XResolution, value).unwrap();
504 }
505
506 pub fn y_resolution(&mut self, value: Rational) {
508 self.encoder.write_tag(Tag::YResolution, value).unwrap();
509 }
510
511 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 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 pub fn encoder(&mut self) -> &mut DirectoryEncoder<'a, W, K> {
547 &mut self.encoder
548 }
549
550 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
572pub trait TiffKind {
576 type OffsetType: TryFrom<usize, Error = TryFromIntError> + Into<u64> + TiffValue;
578
579 type OffsetArrayType: ?Sized + TiffValue;
581
582 fn write_header<W: Write>(writer: &mut TiffWriter<W>) -> TiffResult<()>;
584
585 fn convert_offset(offset: u64) -> TiffResult<Self::OffsetType>;
589
590 fn write_offset<W: Write>(writer: &mut TiffWriter<W>, offset: u64) -> TiffResult<()>;
594
595 fn write_entry_count<W: Write>(writer: &mut TiffWriter<W>, count: usize) -> TiffResult<()>;
600
601 fn convert_slice(slice: &[Self::OffsetType]) -> &Self::OffsetArrayType;
612}
613
614pub 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 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
649pub 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 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}