1use bytes::Bytes;
2
3use crate::array::Array;
4use crate::decoder::DecoderRegistry;
5use crate::error::{AsyncTiffResult, TiffError, TiffUnsupportedError};
6use crate::ifd::CompressedBytes;
7use crate::predictor::{fix_endianness, unpredict_float, unpredict_hdiff};
8use crate::reader::Endianness;
9use crate::tags::{Compression, PhotometricInterpretation, PlanarConfiguration, Predictor};
10use crate::DataType;
11
12#[derive(Debug, Clone)]
21pub struct Tile {
22 pub(crate) x: usize,
23 pub(crate) y: usize,
24 pub(crate) data_type: Option<DataType>,
25 pub(crate) samples_per_pixel: u16,
26 pub(crate) bits_per_sample: u16,
27 pub(crate) endianness: Endianness,
28 pub(crate) width: u32,
29 pub(crate) height: u32,
30 pub(crate) planar_configuration: PlanarConfiguration,
31 pub(crate) predictor: Predictor,
32 pub(crate) compressed_bytes: CompressedBytes,
33 pub(crate) compression_method: Compression,
34 pub(crate) photometric_interpretation: PhotometricInterpretation,
35 pub(crate) jpeg_tables: Option<Bytes>,
36 pub(crate) lerc_parameters: Option<Vec<u32>>,
39}
40
41impl Tile {
42 pub fn x(&self) -> usize {
44 self.x
45 }
46
47 pub fn y(&self) -> usize {
49 self.y
50 }
51
52 pub fn compressed_bytes(&self) -> &CompressedBytes {
56 &self.compressed_bytes
57 }
58
59 pub fn compression_method(&self) -> Compression {
61 self.compression_method
62 }
63
64 pub fn photometric_interpretation(&self) -> PhotometricInterpretation {
66 self.photometric_interpretation
67 }
68
69 pub fn jpeg_tables(&self) -> Option<&Bytes> {
73 self.jpeg_tables.as_ref()
74 }
75
76 pub fn decode(self, decoder_registry: &DecoderRegistry) -> AsyncTiffResult<Array> {
81 let decoder = decoder_registry
82 .as_ref()
83 .get(&self.compression_method)
84 .ok_or(TiffError::UnsupportedError(
85 TiffUnsupportedError::UnsupportedCompression(self.compression_method),
86 ))?;
87
88 let samples = self.samples_per_pixel as usize;
89 let bits_per_sample = self.bits_per_sample;
90 let tile_width = self.width as usize;
92
93 let mut decoded_tile = match &self.compressed_bytes {
94 CompressedBytes::Chunky(bytes) => decoder.decode_tile(
95 bytes.clone(),
96 self.photometric_interpretation,
97 self.jpeg_tables.as_deref(),
98 self.samples_per_pixel,
99 bits_per_sample,
100 self.lerc_parameters.as_deref(),
101 )?,
102 CompressedBytes::Planar(band_bytes) => {
103 let bytes_per_sample = (bits_per_sample as usize).div_ceil(8);
104 let total_size =
105 band_bytes.len() * tile_width * (self.height as usize) * bytes_per_sample;
106 let mut result = Vec::with_capacity(total_size);
107
108 for band_data in band_bytes {
109 let decoded_band = decoder.decode_tile(
110 band_data.clone(),
111 self.photometric_interpretation,
112 self.jpeg_tables.as_deref(),
113 1,
114 bits_per_sample,
115 self.lerc_parameters.as_deref(),
116 )?;
117 result.extend_from_slice(&decoded_band);
118 }
119
120 debug_assert_eq!(result.len(), total_size);
121 result
122 }
123 };
124
125 let decoded = match self.predictor {
127 Predictor::None => {
128 fix_endianness(&mut decoded_tile, self.endianness, bits_per_sample);
129 decoded_tile
130 }
131 Predictor::Horizontal => unpredict_hdiff(
132 decoded_tile,
133 self.endianness,
134 samples,
135 bits_per_sample,
136 tile_width,
137 ),
138 Predictor::FloatingPoint => {
139 unpredict_float(decoded_tile, samples, bits_per_sample, tile_width)?
140 }
141 };
142
143 let shape = infer_shape(
144 self.planar_configuration,
145 self.width as _,
146 self.height as _,
147 samples,
148 );
149 Array::try_new(decoded, shape, self.data_type)
150 }
151}
152
153fn infer_shape(
154 planar_configuration: PlanarConfiguration,
155 width: usize,
156 height: usize,
157 samples_per_pixel: usize,
158) -> [usize; 3] {
159 match planar_configuration {
160 PlanarConfiguration::Chunky => [height, width, samples_per_pixel],
161 PlanarConfiguration::Planar => [samples_per_pixel, height, width],
162 }
163}