1use bytes::Bytes;
2
3use crate::array::Array;
4use crate::decoder::DecoderRegistry;
5use crate::error::{AsyncTiffResult, TiffError, TiffUnsupportedError};
6use crate::predictor::{fix_endianness, unpredict_float, unpredict_hdiff, PredictorInfo};
7use crate::tags::{CompressionMethod, PhotometricInterpretation, PlanarConfiguration, Predictor};
8use crate::DataType;
9
10#[derive(Debug, Clone)]
19pub struct Tile {
20 pub(crate) x: usize,
21 pub(crate) y: usize,
22 pub(crate) data_type: Option<DataType>,
23 pub(crate) samples_per_pixel: u16,
24 pub(crate) width: u32,
25 pub(crate) height: u32,
26 pub(crate) planar_configuration: PlanarConfiguration,
27 pub(crate) predictor: Predictor,
28 pub(crate) predictor_info: PredictorInfo,
29 pub(crate) compressed_bytes: Bytes,
30 pub(crate) compression_method: CompressionMethod,
31 pub(crate) photometric_interpretation: PhotometricInterpretation,
32 pub(crate) jpeg_tables: Option<Bytes>,
33}
34
35impl Tile {
36 pub fn x(&self) -> usize {
38 self.x
39 }
40
41 pub fn y(&self) -> usize {
43 self.y
44 }
45
46 pub fn compressed_bytes(&self) -> &Bytes {
50 &self.compressed_bytes
51 }
52
53 pub fn compression_method(&self) -> CompressionMethod {
55 self.compression_method
56 }
57
58 pub fn photometric_interpretation(&self) -> PhotometricInterpretation {
60 self.photometric_interpretation
61 }
62
63 pub fn jpeg_tables(&self) -> Option<&Bytes> {
67 self.jpeg_tables.as_ref()
68 }
69
70 pub fn decode(self, decoder_registry: &DecoderRegistry) -> AsyncTiffResult<Array> {
75 let decoder = decoder_registry
76 .as_ref()
77 .get(&self.compression_method)
78 .ok_or(TiffError::UnsupportedError(
79 TiffUnsupportedError::UnsupportedCompressionMethod(self.compression_method),
80 ))?;
81
82 let mut decoded_tile = decoder.decode_tile(
83 self.compressed_bytes.clone(),
84 self.photometric_interpretation,
85 self.jpeg_tables.as_deref(),
86 )?;
87
88 let decoded = match self.predictor {
89 Predictor::None => {
90 fix_endianness(
91 &mut decoded_tile,
92 self.predictor_info.endianness(),
93 self.predictor_info.bits_per_sample(),
94 );
95 Ok(decoded_tile)
96 }
97 Predictor::Horizontal => {
98 unpredict_hdiff(decoded_tile, &self.predictor_info, self.x as _)
99 }
100 Predictor::FloatingPoint => {
101 unpredict_float(decoded_tile, &self.predictor_info, self.x as _, self.y as _)
102 }
103 }?;
104
105 let shape = infer_shape(
106 self.planar_configuration,
107 self.width as _,
108 self.height as _,
109 self.samples_per_pixel as _,
110 );
111 Array::try_new(decoded, shape, self.data_type)
112 }
113}
114
115fn infer_shape(
116 planar_configuration: PlanarConfiguration,
117 width: usize,
118 height: usize,
119 samples_per_pixel: usize,
120) -> [usize; 3] {
121 match planar_configuration {
122 PlanarConfiguration::Chunky => [height, width, samples_per_pixel],
123 PlanarConfiguration::Planar => [samples_per_pixel, height, width],
124 }
125}