1use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};
9use core::marker::PhantomData;
10use core::mem;
11use no_std_io::io::{self, BufRead, Cursor, Read, Seek, Write};
12
13use tiff::decoder::{Decoder, DecodingResult};
14use tiff::tags::Tag;
15
16use crate::color::{ColorType, ExtendedColorType};
17use crate::error::{
18 DecodingError, EncodingError, ImageError, ImageResult, LimitError, LimitErrorKind,
19 ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
20};
21use crate::metadata::Orientation;
22use crate::{utils, ImageDecoder, ImageEncoder, ImageFormat};
23
24const TAG_XML_PACKET: Tag = Tag::Unknown(700);
25
26pub struct TiffDecoder<R>
28where
29 R: BufRead + Seek,
30{
31 dimensions: (u32, u32),
32 color_type: ColorType,
33 original_color_type: ExtendedColorType,
34
35 inner: Option<Decoder<R>>,
37 buffer: DecodingResult,
38}
39
40impl<R> TiffDecoder<R>
41where
42 R: BufRead + Seek,
43{
44 pub fn new(r: R) -> Result<TiffDecoder<R>, ImageError> {
46 let mut inner = Decoder::new(r).map_err(ImageError::from_tiff_decode)?;
47
48 let dimensions = inner.dimensions().map_err(ImageError::from_tiff_decode)?;
49 let tiff_color_type = inner.colortype().map_err(ImageError::from_tiff_decode)?;
50
51 match inner.find_tag_unsigned_vec::<u16>(Tag::SampleFormat) {
52 Ok(Some(sample_formats)) => {
53 for format in sample_formats {
54 check_sample_format(format, tiff_color_type)?;
55 }
56 }
57 Ok(None) => { }
58 Err(other) => return Err(ImageError::from_tiff_decode(other)),
59 }
60
61 let color_type = match tiff_color_type {
62 tiff::ColorType::Gray(1) => ColorType::L8,
63 tiff::ColorType::Gray(8) => ColorType::L8,
64 tiff::ColorType::Gray(16) => ColorType::L16,
65 tiff::ColorType::GrayA(8) => ColorType::La8,
66 tiff::ColorType::GrayA(16) => ColorType::La16,
67 tiff::ColorType::RGB(8) => ColorType::Rgb8,
68 tiff::ColorType::RGB(16) => ColorType::Rgb16,
69 tiff::ColorType::RGBA(8) => ColorType::Rgba8,
70 tiff::ColorType::RGBA(16) => ColorType::Rgba16,
71 tiff::ColorType::CMYK(8) => ColorType::Rgb8,
72 tiff::ColorType::CMYK(16) => ColorType::Rgb16,
73 tiff::ColorType::RGB(32) => ColorType::Rgb32F,
74 tiff::ColorType::RGBA(32) => ColorType::Rgba32F,
75
76 tiff::ColorType::Palette(n) | tiff::ColorType::Gray(n) => {
77 return Err(err_unknown_color_type(n))
78 }
79 tiff::ColorType::GrayA(n) => return Err(err_unknown_color_type(n.saturating_mul(2))),
80 tiff::ColorType::RGB(n) => return Err(err_unknown_color_type(n.saturating_mul(3))),
81 tiff::ColorType::YCbCr(n) => return Err(err_unknown_color_type(n.saturating_mul(3))),
82 tiff::ColorType::RGBA(n) | tiff::ColorType::CMYK(n) => {
83 return Err(err_unknown_color_type(n.saturating_mul(4)))
84 }
85 tiff::ColorType::Multiband {
86 bit_depth,
87 num_samples,
88 } => {
89 return Err(err_unknown_color_type(
90 bit_depth.saturating_mul(num_samples.min(255) as u8),
91 ))
92 }
93 _ => return Err(err_unknown_color_type(0)),
94 };
95
96 let original_color_type = match tiff_color_type {
97 tiff::ColorType::Gray(1) => ExtendedColorType::L1,
98 tiff::ColorType::CMYK(8) => ExtendedColorType::Cmyk8,
99 tiff::ColorType::CMYK(16) => ExtendedColorType::Cmyk16,
100 _ => color_type.into(),
101 };
102
103 Ok(TiffDecoder {
104 dimensions,
105 color_type,
106 original_color_type,
107 inner: Some(inner),
108 buffer: DecodingResult::U8(vec![]),
109 })
110 }
111
112 fn total_bytes_buffer(&self) -> u64 {
114 let dimensions = self.dimensions();
115 let total_pixels = u64::from(dimensions.0) * u64::from(dimensions.1);
116
117 let bytes_per_pixel = match self.original_color_type {
118 ExtendedColorType::Cmyk8 => 4,
119 ExtendedColorType::Cmyk16 => 8,
120 _ => u64::from(self.color_type().bytes_per_pixel()),
121 };
122 total_pixels.saturating_mul(bytes_per_pixel)
123 }
124
125 fn interleave_planes(
127 &mut self,
128 layout: tiff::decoder::BufferLayoutPreference,
129 output: &mut [u8],
130 ) -> ImageResult<()> {
131 if self.original_color_type != self.color_type.into() {
132 return Err(ImageError::Unsupported(
133 UnsupportedError::from_format_and_kind(
134 ImageFormat::Tiff.into(),
135 UnsupportedErrorKind::GenericFeature(
136 "Planar TIFF with CMYK color type is not supported".to_string(),
137 ),
138 ),
139 ));
140 }
141
142 let plane_stride = layout.plane_stride.map_or(0, |n| n.get());
160 let bytes = self.buffer.as_buffer(0);
161
162 let planes = bytes
163 .as_bytes()
164 .chunks_exact(plane_stride)
165 .collect::<Vec<_>>();
166
167 if planes.len() < usize::from(self.color_type.channel_count()) {
170 return Err(ImageError::Decoding(DecodingError::new(
171 ImageFormat::Tiff.into(),
172 "Not enough planes read from TIFF image".to_string(),
173 )));
174 }
175
176 utils::interleave_planes(
177 output,
178 self.color_type,
179 &planes[..usize::from(self.color_type.channel_count())],
180 );
181
182 Ok(())
183 }
184}
185
186fn check_sample_format(sample_format: u16, color_type: tiff::ColorType) -> Result<(), ImageError> {
187 use tiff::{tags::SampleFormat, ColorType};
188 let num_bits = match color_type {
189 ColorType::CMYK(k) => k,
190 ColorType::Gray(k) => k,
191 ColorType::RGB(k) => k,
192 ColorType::RGBA(k) => k,
193 ColorType::GrayA(k) => k,
194 ColorType::Palette(k) | ColorType::YCbCr(k) => {
195 return Err(ImageError::Unsupported(
196 UnsupportedError::from_format_and_kind(
197 ImageFormat::Tiff.into(),
198 UnsupportedErrorKind::GenericFeature(format!(
199 "Unhandled TIFF color type {color_type:?} for {k} bits",
200 )),
201 ),
202 ))
203 }
204 _ => {
205 return Err(ImageError::Unsupported(
206 UnsupportedError::from_format_and_kind(
207 ImageFormat::Tiff.into(),
208 UnsupportedErrorKind::GenericFeature(format!(
209 "Unhandled TIFF color type {color_type:?}",
210 )),
211 ),
212 ))
213 }
214 };
215
216 match SampleFormat::from_u16(sample_format) {
217 Some(SampleFormat::Uint) if num_bits <= 16 => Ok(()),
218 Some(SampleFormat::IEEEFP) if num_bits == 32 => Ok(()),
219 _ => Err(ImageError::Unsupported(
220 UnsupportedError::from_format_and_kind(
221 ImageFormat::Tiff.into(),
222 UnsupportedErrorKind::GenericFeature(format!(
223 "Unhandled TIFF sample format {sample_format:?} for {num_bits} bits",
224 )),
225 ),
226 )),
227 }
228}
229
230fn err_unknown_color_type(value: u8) -> ImageError {
231 ImageError::Unsupported(UnsupportedError::from_format_and_kind(
232 ImageFormat::Tiff.into(),
233 UnsupportedErrorKind::Color(ExtendedColorType::Unknown(value)),
234 ))
235}
236
237impl ImageError {
238 fn from_tiff_decode(err: tiff::TiffError) -> ImageError {
239 match err {
240 tiff::TiffError::IoError(err) => ImageError::IoError(err),
241 err @ (tiff::TiffError::FormatError(_)
242 | tiff::TiffError::IntSizeError
243 | tiff::TiffError::UsageError(_)) => {
244 ImageError::Decoding(DecodingError::new(ImageFormat::Tiff.into(), err))
245 }
246 tiff::TiffError::UnsupportedError(desc) => {
247 ImageError::Unsupported(UnsupportedError::from_format_and_kind(
248 ImageFormat::Tiff.into(),
249 UnsupportedErrorKind::GenericFeature(desc.to_string()),
250 ))
251 }
252 tiff::TiffError::LimitsExceeded => {
253 ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory))
254 }
255 }
256 }
257
258 fn from_tiff_encode(err: tiff::TiffError) -> ImageError {
259 match err {
260 tiff::TiffError::IoError(err) => ImageError::IoError(err),
261 err @ (tiff::TiffError::FormatError(_)
262 | tiff::TiffError::IntSizeError
263 | tiff::TiffError::UsageError(_)) => {
264 ImageError::Encoding(EncodingError::new(ImageFormat::Tiff.into(), err))
265 }
266 tiff::TiffError::UnsupportedError(desc) => {
267 ImageError::Unsupported(UnsupportedError::from_format_and_kind(
268 ImageFormat::Tiff.into(),
269 UnsupportedErrorKind::GenericFeature(desc.to_string()),
270 ))
271 }
272 tiff::TiffError::LimitsExceeded => {
273 ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory))
274 }
275 }
276 }
277}
278
279#[allow(dead_code)]
281#[deprecated]
282pub struct TiffReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
283#[allow(deprecated)]
284impl<R> Read for TiffReader<R> {
285 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
286 self.0.read(buf)
287 }
288
289 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
290 if self.0.position() == 0 && buf.is_empty() {
291 mem::swap(buf, self.0.get_mut());
292 Ok(buf.len())
293 } else {
294 self.0.read_to_end(buf)
295 }
296 }
297}
298
299impl<R: BufRead + Seek> ImageDecoder for TiffDecoder<R> {
300 fn dimensions(&self) -> (u32, u32) {
301 self.dimensions
302 }
303
304 fn color_type(&self) -> ColorType {
305 self.color_type
306 }
307
308 fn original_color_type(&self) -> ExtendedColorType {
309 self.original_color_type
310 }
311
312 fn icc_profile(&mut self) -> ImageResult<Option<Vec<u8>>> {
313 if let Some(decoder) = &mut self.inner {
314 Ok(decoder.get_tag_u8_vec(Tag::IccProfile).ok())
315 } else {
316 Ok(None)
317 }
318 }
319
320 fn xmp_metadata(&mut self) -> ImageResult<Option<Vec<u8>>> {
321 let Some(decoder) = &mut self.inner else {
322 return Ok(None);
323 };
324
325 let value = match decoder.get_tag(TAG_XML_PACKET) {
326 Ok(value) => value,
327 Err(tiff::TiffError::FormatError(tiff::TiffFormatError::RequiredTagNotFound(_))) => {
328 return Ok(None);
329 }
330 Err(err) => return Err(ImageError::from_tiff_decode(err)),
331 };
332 value
333 .into_u8_vec()
334 .map(Some)
335 .map_err(ImageError::from_tiff_decode)
336 }
337
338 fn orientation(&mut self) -> ImageResult<Orientation> {
339 if let Some(decoder) = &mut self.inner {
340 Ok(decoder
341 .find_tag(Tag::Orientation)
342 .map_err(ImageError::from_tiff_decode)?
343 .and_then(|v| Orientation::from_exif(v.into_u16().ok()?.min(255) as u8))
344 .unwrap_or(Orientation::NoTransforms))
345 } else {
346 Ok(Orientation::NoTransforms)
347 }
348 }
349
350 fn set_limits(&mut self, limits: crate::Limits) -> ImageResult<()> {
351 limits.check_support(&crate::LimitSupport::default())?;
352
353 let (width, height) = self.dimensions();
354 limits.check_dimensions(width, height)?;
355
356 let max_alloc = limits.max_alloc.unwrap_or(u64::MAX);
357 let max_intermediate_alloc = max_alloc.saturating_sub(self.total_bytes_buffer());
358
359 let mut tiff_limits: tiff::decoder::Limits = Default::default();
360 tiff_limits.decoding_buffer_size =
361 usize::try_from(max_alloc - max_intermediate_alloc).unwrap_or(usize::MAX);
362 tiff_limits.intermediate_buffer_size =
363 usize::try_from(max_intermediate_alloc).unwrap_or(usize::MAX);
364 tiff_limits.ifd_value_size = tiff_limits.intermediate_buffer_size;
365 self.inner = Some(self.inner.take().unwrap().with_limits(tiff_limits));
366
367 Ok(())
368 }
369
370 fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
371 assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
372
373 let layout = self
374 .inner
375 .as_mut()
376 .unwrap()
377 .read_image_to_buffer(&mut self.buffer)
378 .map_err(ImageError::from_tiff_decode)?;
379
380 if self.buffer.as_buffer(0).as_bytes().len() < layout.complete_len {
382 return Err(ImageError::Limits(LimitError::from_kind(
383 LimitErrorKind::InsufficientMemory,
384 )));
385 }
386
387 if layout.planes > 1 {
388 return self.interleave_planes(layout, buf);
391 }
392
393 match self.buffer {
394 DecodingResult::U8(v) if self.original_color_type == ExtendedColorType::Cmyk8 => {
395 let mut out_cur = Cursor::new(buf);
396 for cmyk in v.as_chunks::<4>().0 {
397 out_cur.write_all(&cmyk_to_rgb(cmyk))?;
398 }
399 }
400 DecodingResult::U16(v) if self.original_color_type == ExtendedColorType::Cmyk16 => {
401 let mut out_cur = Cursor::new(buf);
402 for cmyk in v.as_chunks::<4>().0 {
403 out_cur.write_all(bytemuck::cast_slice(&cmyk_to_rgb16(cmyk)))?;
404 }
405 }
406 DecodingResult::U8(v) if self.original_color_type == ExtendedColorType::L1 => {
407 let width = self.dimensions.0;
408 let row_bytes = width.div_ceil(8);
409
410 for (in_row, out_row) in v
411 .chunks_exact(row_bytes as usize)
412 .zip(buf.chunks_exact_mut(width as usize))
413 {
414 out_row.copy_from_slice(&utils::expand_bits(1, width, in_row));
415 }
416 }
417 DecodingResult::U8(v) => {
418 buf.copy_from_slice(&v);
419 }
420 DecodingResult::U16(v) => {
421 buf.copy_from_slice(bytemuck::cast_slice(&v));
422 }
423 DecodingResult::U32(v) => {
424 buf.copy_from_slice(bytemuck::cast_slice(&v));
425 }
426 DecodingResult::U64(v) => {
427 buf.copy_from_slice(bytemuck::cast_slice(&v));
428 }
429 DecodingResult::I8(v) => {
430 buf.copy_from_slice(bytemuck::cast_slice(&v));
431 }
432 DecodingResult::I16(v) => {
433 buf.copy_from_slice(bytemuck::cast_slice(&v));
434 }
435 DecodingResult::I32(v) => {
436 buf.copy_from_slice(bytemuck::cast_slice(&v));
437 }
438 DecodingResult::I64(v) => {
439 buf.copy_from_slice(bytemuck::cast_slice(&v));
440 }
441 DecodingResult::F32(v) => {
442 buf.copy_from_slice(bytemuck::cast_slice(&v));
443 }
444 DecodingResult::F64(v) => {
445 buf.copy_from_slice(bytemuck::cast_slice(&v));
446 }
447 DecodingResult::F16(_) => unreachable!(),
448 }
449
450 Ok(())
451 }
452
453 fn read_image_boxed(self: Box<Self>, buf: &mut [u8]) -> ImageResult<()> {
454 (*self).read_image(buf)
455 }
456}
457
458pub struct TiffEncoder<W> {
460 w: W,
461 icc: Option<Vec<u8>>,
462}
463
464fn cmyk_to_rgb(cmyk: &[u8; 4]) -> [u8; 3] {
465 let c = f32::from(cmyk[0]);
466 let m = f32::from(cmyk[1]);
467 let y = f32::from(cmyk[2]);
468 let kf = 1. - f32::from(cmyk[3]) / 255.;
469 [
470 ((255. - c) * kf) as u8,
471 ((255. - m) * kf) as u8,
472 ((255. - y) * kf) as u8,
473 ]
474}
475
476fn cmyk_to_rgb16(cmyk: &[u16; 4]) -> [u16; 3] {
477 let c = f32::from(cmyk[0]);
478 let m = f32::from(cmyk[1]);
479 let y = f32::from(cmyk[2]);
480 let kf = 1. - f32::from(cmyk[3]) / 65535.;
481 [
482 ((65535. - c) * kf) as u16,
483 ((65535. - m) * kf) as u16,
484 ((65535. - y) * kf) as u16,
485 ]
486}
487
488fn u8_slice_as_pod<P: bytemuck::Pod>(buf: &[u8]) -> ImageResult<alloc::borrow::Cow<'_, [P]>> {
490 bytemuck::try_cast_slice(buf)
491 .map(alloc::borrow::Cow::Borrowed)
492 .or_else(|err| {
493 match err {
494 bytemuck::PodCastError::TargetAlignmentGreaterAndInputNotAligned => {
495 let vec = bytemuck::allocation::pod_collect_to_vec(buf);
499 Ok(alloc::borrow::Cow::Owned(vec))
500 }
501 _ => {
503 Err(ImageError::Parameter(ParameterError::from_kind(
507 ParameterErrorKind::Generic(format!(
508 "Casting samples to their representation failed: {err:?}",
509 )),
510 )))
511 }
512 }
513 })
514}
515
516impl<W: Write + Seek> TiffEncoder<W> {
517 pub fn new(w: W) -> TiffEncoder<W> {
519 TiffEncoder { w, icc: None }
520 }
521
522 fn write_tiff<C: tiff::encoder::colortype::ColorType<Inner: bytemuck::Pod>>(
524 self,
525 width: u32,
526 height: u32,
527 data: &[u8],
528 ) -> ImageResult<()>
529 where
530 [C::Inner]: tiff::encoder::TiffValue,
531 {
532 let mut encoder =
533 tiff::encoder::TiffEncoder::new(self.w).map_err(ImageError::from_tiff_encode)?;
534 let data = u8_slice_as_pod::<C::Inner>(data)?;
535 let mut img_encoder = encoder
536 .new_image::<C>(width, height)
537 .map_err(ImageError::from_tiff_encode)?;
538 if let Some(icc_profile) = self.icc {
539 let ifd_encoder = img_encoder.encoder(); ifd_encoder
546 .write_tag(Tag::IccProfile, icc_profile.as_slice())
547 .map_err(ImageError::from_tiff_encode)?;
548 }
549 img_encoder
550 .write_data(&data)
551 .map_err(ImageError::from_tiff_encode)
552 }
553
554 #[track_caller]
556 #[deprecated = "Use the `write_image` method from the `ImageEncoder` trait directly."]
557 pub fn encode(
558 self,
559 buf: &[u8],
560 width: u32,
561 height: u32,
562 color_type: ExtendedColorType,
563 ) -> ImageResult<()> {
564 self.write_image(buf, width, height, color_type)
566 }
567}
568
569impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
570 #[track_caller]
578 fn write_image(
579 self,
580 buf: &[u8],
581 width: u32,
582 height: u32,
583 color_type: ExtendedColorType,
584 ) -> ImageResult<()> {
585 use tiff::encoder::colortype::{
586 Gray16, Gray8, RGB32Float, RGBA32Float, RGB16, RGB8, RGBA16, RGBA8,
587 };
588 let expected_buffer_len = color_type.buffer_size(width, height);
589 assert_eq!(
590 expected_buffer_len,
591 buf.len() as u64,
592 "Invalid buffer length: expected {expected_buffer_len} got {} for {width}x{height} image",
593 buf.len(),
594 );
595 match color_type {
596 ExtendedColorType::L8 => self.write_tiff::<Gray8>(width, height, buf),
597 ExtendedColorType::Rgb8 => self.write_tiff::<RGB8>(width, height, buf),
598 ExtendedColorType::Rgba8 => self.write_tiff::<RGBA8>(width, height, buf),
599 ExtendedColorType::L16 => self.write_tiff::<Gray16>(width, height, buf),
600 ExtendedColorType::Rgb16 => self.write_tiff::<RGB16>(width, height, buf),
601 ExtendedColorType::Rgba16 => self.write_tiff::<RGBA16>(width, height, buf),
602 ExtendedColorType::Rgb32F => self.write_tiff::<RGB32Float>(width, height, buf),
603 ExtendedColorType::Rgba32F => self.write_tiff::<RGBA32Float>(width, height, buf),
604 _ => Err(ImageError::Unsupported(
605 UnsupportedError::from_format_and_kind(
606 ImageFormat::Tiff.into(),
607 UnsupportedErrorKind::Color(color_type),
608 ),
609 )),
610 }
611 }
612
613 fn set_icc_profile(&mut self, icc_profile: Vec<u8>) -> Result<(), UnsupportedError> {
614 self.icc = Some(icc_profile);
615 Ok(())
616 }
617}