1use std::sync::Arc;
4
5#[cfg(feature = "rayon")]
6use rayon::prelude::*;
7
8use crate::block_decode;
9use crate::cache::{BlockCache, BlockKey, BlockKind};
10use crate::error::{Error, Result};
11use crate::header::ByteOrder;
12use crate::ifd::{Ifd, RasterLayout};
13use crate::source::TiffSource;
14use crate::{
15 allocate_decode_output, read_block_payload, read_gdal_block_payload, DecodeReadOptions,
16 GdalStructuralMetadata, Window,
17};
18
19const TAG_JPEG_TABLES: u16 = 347;
20
21pub(crate) fn read_window(
22 source: &dyn TiffSource,
23 ifd: &Ifd,
24 byte_order: ByteOrder,
25 cache: &BlockCache,
26 window: Window,
27 options: DecodeReadOptions<'_>,
28) -> Result<Vec<u8>> {
29 let layout = ifd.raster_layout()?;
30 if window.is_empty() {
31 return Ok(Vec::new());
32 }
33
34 let output_len = window.output_len(&layout)?;
35 let mut output = allocate_decode_output(output_len, options.decode_output_bytes)?;
36 let window_row_end = window.row_end();
37 let output_row_bytes = window.cols * layout.pixel_stride_bytes();
38
39 let relevant_specs = collect_strip_specs_for_window(ifd, &layout, window, None)?;
40
41 #[cfg(not(feature = "rayon"))]
42 let decoded_blocks: Result<Vec<_>> = relevant_specs
43 .iter()
44 .map(|&spec| {
45 read_strip_block(
46 source,
47 ifd,
48 byte_order,
49 cache,
50 spec,
51 &layout,
52 options.gdal_structural_metadata,
53 )
54 .map(|block| (spec, block))
55 })
56 .collect();
57
58 #[cfg(feature = "rayon")]
59 let decoded_blocks: Result<Vec<_>> = relevant_specs
60 .par_iter()
61 .map(|&spec| {
62 read_strip_block(
63 source,
64 ifd,
65 byte_order,
66 cache,
67 spec,
68 &layout,
69 options.gdal_structural_metadata,
70 )
71 .map(|block| (spec, block))
72 })
73 .collect();
74
75 for (spec, block) in decoded_blocks? {
76 let block = &*block;
77 let block_row_end = spec.row_start + spec.rows_in_strip;
78 let copy_row_start = spec.row_start.max(window.row_off);
79 let copy_row_end = block_row_end.min(window_row_end);
80
81 if layout.planar_configuration == 1 {
82 let src_row_bytes = layout.row_bytes();
83 let copy_bytes_per_row = window.cols * layout.pixel_stride_bytes();
84 for row in copy_row_start..copy_row_end {
85 let src_row_index = row - spec.row_start;
86 let dest_row_index = row - window.row_off;
87 let src_offset =
88 src_row_index * src_row_bytes + window.col_off * layout.pixel_stride_bytes();
89 let dest_offset = dest_row_index * output_row_bytes;
90 output[dest_offset..dest_offset + copy_bytes_per_row]
91 .copy_from_slice(&block[src_offset..src_offset + copy_bytes_per_row]);
92 }
93 } else {
94 let src_row_bytes = layout.sample_plane_row_bytes();
95 for row in copy_row_start..copy_row_end {
96 let src_row_index = row - spec.row_start;
97 let dest_row_index = row - window.row_off;
98 let src_row =
99 &block[src_row_index * src_row_bytes..(src_row_index + 1) * src_row_bytes];
100 let dest_row = &mut output
101 [dest_row_index * output_row_bytes..(dest_row_index + 1) * output_row_bytes];
102 for col in window.col_off..window.col_end() {
103 let src = &src_row
104 [col * layout.bytes_per_sample..(col + 1) * layout.bytes_per_sample];
105 let dest_col_index = col - window.col_off;
106 let pixel_base = dest_col_index * layout.pixel_stride_bytes()
107 + spec.plane * layout.bytes_per_sample;
108 dest_row[pixel_base..pixel_base + layout.bytes_per_sample].copy_from_slice(src);
109 }
110 }
111 }
112 }
113
114 Ok(output)
115}
116
117pub(crate) fn read_window_band(
118 source: &dyn TiffSource,
119 ifd: &Ifd,
120 byte_order: ByteOrder,
121 cache: &BlockCache,
122 window: Window,
123 band_index: usize,
124 options: DecodeReadOptions<'_>,
125) -> Result<Vec<u8>> {
126 let layout = ifd.raster_layout()?;
127 if band_index >= layout.samples_per_pixel {
128 return Err(Error::BandIndexOutOfBounds {
129 index: band_index,
130 band_count: layout.samples_per_pixel,
131 });
132 }
133 if window.is_empty() {
134 return Ok(Vec::new());
135 }
136
137 let output_len = window.band_output_len(&layout)?;
138 let mut output = allocate_decode_output(output_len, options.decode_output_bytes)?;
139 let window_row_end = window.row_end();
140 let output_row_bytes = window.cols * layout.bytes_per_sample;
141
142 let relevant_specs = collect_strip_specs_for_window(ifd, &layout, window, Some(band_index))?;
143
144 #[cfg(not(feature = "rayon"))]
145 let decoded_blocks: Result<Vec<_>> = relevant_specs
146 .iter()
147 .map(|&spec| {
148 read_strip_block(
149 source,
150 ifd,
151 byte_order,
152 cache,
153 spec,
154 &layout,
155 options.gdal_structural_metadata,
156 )
157 .map(|block| (spec, block))
158 })
159 .collect();
160
161 #[cfg(feature = "rayon")]
162 let decoded_blocks: Result<Vec<_>> = relevant_specs
163 .par_iter()
164 .map(|&spec| {
165 read_strip_block(
166 source,
167 ifd,
168 byte_order,
169 cache,
170 spec,
171 &layout,
172 options.gdal_structural_metadata,
173 )
174 .map(|block| (spec, block))
175 })
176 .collect();
177
178 for (spec, block) in decoded_blocks? {
179 let block = &*block;
180 let block_row_end = spec.row_start + spec.rows_in_strip;
181 let copy_row_start = spec.row_start.max(window.row_off);
182 let copy_row_end = block_row_end.min(window_row_end);
183
184 if layout.planar_configuration == 1 {
185 let src_row_bytes = layout.row_bytes();
186 let band_offset = band_index * layout.bytes_per_sample;
187 for row in copy_row_start..copy_row_end {
188 let src_row_index = row - spec.row_start;
189 let dest_row_index = row - window.row_off;
190 let src_row =
191 &block[src_row_index * src_row_bytes..(src_row_index + 1) * src_row_bytes];
192 let dest_row = &mut output
193 [dest_row_index * output_row_bytes..(dest_row_index + 1) * output_row_bytes];
194 for col in window.col_off..window.col_end() {
195 let src_base = col * layout.pixel_stride_bytes() + band_offset;
196 let dest_col_index = col - window.col_off;
197 let dest_base = dest_col_index * layout.bytes_per_sample;
198 dest_row[dest_base..dest_base + layout.bytes_per_sample]
199 .copy_from_slice(&src_row[src_base..src_base + layout.bytes_per_sample]);
200 }
201 }
202 } else {
203 let src_row_bytes = layout.sample_plane_row_bytes();
204 let copy_bytes_per_row = window.cols * layout.bytes_per_sample;
205 for row in copy_row_start..copy_row_end {
206 let src_row_index = row - spec.row_start;
207 let dest_row_index = row - window.row_off;
208 let src_offset =
209 src_row_index * src_row_bytes + window.col_off * layout.bytes_per_sample;
210 let dest_offset = dest_row_index * output_row_bytes;
211 output[dest_offset..dest_offset + copy_bytes_per_row]
212 .copy_from_slice(&block[src_offset..src_offset + copy_bytes_per_row]);
213 }
214 }
215 }
216
217 Ok(output)
218}
219
220fn collect_strip_specs_for_window(
221 ifd: &Ifd,
222 layout: &RasterLayout,
223 window: Window,
224 band_index: Option<usize>,
225) -> Result<Vec<StripBlockSpec>> {
226 let offsets = ifd
227 .strip_offsets()
228 .ok_or(Error::TagNotFound(crate::ifd::TAG_STRIP_OFFSETS))?;
229 let counts = ifd
230 .strip_byte_counts()
231 .ok_or(Error::TagNotFound(crate::ifd::TAG_STRIP_BYTE_COUNTS))?;
232 if offsets.len() != counts.len() {
233 return Err(Error::InvalidImageLayout(format!(
234 "StripOffsets has {} entries but StripByteCounts has {}",
235 offsets.len(),
236 counts.len()
237 )));
238 }
239
240 let rows_per_strip = ifd.rows_per_strip().unwrap_or(ifd.height());
241 if rows_per_strip == 0 {
242 return Err(Error::InvalidImageLayout(
243 "RowsPerStrip must be greater than zero".into(),
244 ));
245 }
246 let rows_per_strip = rows_per_strip as usize;
247 let strips_per_plane = layout.height.div_ceil(rows_per_strip);
248 let expected = match layout.planar_configuration {
249 1 => strips_per_plane,
250 2 => strips_per_plane * layout.samples_per_pixel,
251 planar => return Err(Error::UnsupportedPlanarConfiguration(planar)),
252 };
253 if offsets.len() != expected {
254 return Err(Error::InvalidImageLayout(format!(
255 "expected {expected} strips, found {}",
256 offsets.len()
257 )));
258 }
259
260 let first_strip = window.row_off / rows_per_strip;
261 let last_strip = window
262 .row_end()
263 .div_ceil(rows_per_strip)
264 .min(strips_per_plane);
265 let plane_range = if layout.planar_configuration == 1 {
266 0..1
267 } else if let Some(band_index) = band_index {
268 band_index..band_index + 1
269 } else {
270 0..layout.samples_per_pixel
271 };
272 let spec_count = (last_strip - first_strip).saturating_mul(plane_range.end - plane_range.start);
273 let mut specs = Vec::with_capacity(spec_count);
274
275 for plane in plane_range {
276 for plane_strip_index in first_strip..last_strip {
277 let strip_index = if layout.planar_configuration == 1 {
278 plane_strip_index
279 } else {
280 plane * strips_per_plane + plane_strip_index
281 };
282 let row_start = plane_strip_index * rows_per_strip;
283 let rows_in_strip = rows_per_strip.min(layout.height.saturating_sub(row_start));
284 specs.push(StripBlockSpec {
285 index: strip_index,
286 plane,
287 row_start,
288 offset: offsets[strip_index],
289 byte_count: counts[strip_index],
290 rows_in_strip,
291 });
292 }
293 }
294
295 Ok(specs)
296}
297
298#[derive(Clone, Copy)]
299struct StripBlockSpec {
300 index: usize,
301 plane: usize,
302 row_start: usize,
303 offset: u64,
304 byte_count: u64,
305 rows_in_strip: usize,
306}
307
308fn read_strip_block(
309 source: &dyn TiffSource,
310 ifd: &Ifd,
311 byte_order: ByteOrder,
312 cache: &BlockCache,
313 spec: StripBlockSpec,
314 layout: &RasterLayout,
315 gdal_structural_metadata: Option<&GdalStructuralMetadata>,
316) -> Result<Arc<Vec<u8>>> {
317 let cache_key = BlockKey {
318 ifd_index: ifd.index,
319 kind: BlockKind::Strip,
320 block_index: spec.index,
321 };
322 if let Some(cached) = cache.get(&cache_key) {
323 return Ok(cached);
324 }
325
326 let jpeg_tables = ifd
327 .tag(TAG_JPEG_TABLES)
328 .and_then(|tag| tag.value.as_bytes());
329 let byte_count_limit =
330 block_decode::compressed_block_byte_count_limit(&block_decode::BlockDecodeRequest {
331 ifd,
332 layout: *layout,
333 byte_order,
334 compressed: &[],
335 index: spec.index,
336 jpeg_tables,
337 block_width: layout.width,
338 block_height: spec.rows_in_strip,
339 })?;
340 let compressed = match gdal_structural_metadata {
341 Some(metadata) => read_gdal_block_payload(
342 source,
343 metadata,
344 byte_order,
345 spec.offset,
346 spec.byte_count,
347 byte_count_limit,
348 spec.index,
349 )?,
350 None => read_block_payload(
351 source,
352 spec.offset,
353 spec.byte_count,
354 byte_count_limit,
355 spec.index,
356 )?,
357 };
358
359 let decoded = block_decode::decode_compressed_block(block_decode::BlockDecodeRequest {
360 ifd,
361 layout: *layout,
362 byte_order,
363 compressed: &compressed,
364 index: spec.index,
365 jpeg_tables,
366 block_width: layout.width,
367 block_height: spec.rows_in_strip,
368 })?;
369 Ok(cache.insert(cache_key, decoded))
370}