1use std::sync::Arc;
4
5#[cfg(feature = "rayon")]
6use parking_lot::Mutex;
7#[cfg(feature = "rayon")]
8use rayon::prelude::*;
9
10use crate::block_decode;
11use crate::cache::{BlockCache, BlockKey, BlockKind};
12use crate::error::{Error, Result};
13use crate::header::ByteOrder;
14use crate::ifd::{Ifd, RasterLayout};
15use crate::source::TiffSource;
16use crate::{
17 allocate_decode_output, checked_layout_add, checked_layout_mul, read_block_payload,
18 read_gdal_block_payload, validate_decode_output_len, DecodeReadOptions, Window,
19};
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 let ifd_offset = ifd.offset();
34 let context = block_decode::BlockDecodeContext::new(ifd, layout, byte_order)?;
35
36 let output_len = window.output_len(&layout)?;
37 let mut output = allocate_decode_output(output_len, options.decode_output_bytes)?;
38
39 let relevant_specs = collect_strip_specs_for_window(ifd, &layout, window, None)?;
40
41 #[cfg(feature = "rayon")]
42 {
43 let output = Mutex::new(output.as_mut_slice());
44 relevant_specs.par_iter().try_for_each(|&spec| {
45 let block = read_strip_block(source, ifd_offset, cache, spec, &context, options)?;
46 copy_strip_window_block(&mut output.lock(), block.as_slice(), spec, &layout, window)?;
47 Ok::<(), Error>(())
48 })?;
49 }
50
51 #[cfg(not(feature = "rayon"))]
52 for spec in relevant_specs {
53 let block = read_strip_block(source, ifd_offset, cache, spec, &context, options)?;
54 copy_strip_window_block(&mut output, block.as_slice(), spec, &layout, window)?;
55 }
56
57 Ok(output)
58}
59
60pub(crate) fn read_window_band(
61 source: &dyn TiffSource,
62 ifd: &Ifd,
63 byte_order: ByteOrder,
64 cache: &BlockCache,
65 window: Window,
66 band_index: usize,
67 options: DecodeReadOptions<'_>,
68) -> Result<Vec<u8>> {
69 let layout = ifd.raster_layout()?;
70 if band_index >= layout.samples_per_pixel {
71 return Err(Error::BandIndexOutOfBounds {
72 index: band_index,
73 band_count: layout.samples_per_pixel,
74 });
75 }
76 if window.is_empty() {
77 return Ok(Vec::new());
78 }
79 let ifd_offset = ifd.offset();
80 let context = block_decode::BlockDecodeContext::new(ifd, layout, byte_order)?;
81
82 let output_len = window.band_output_len(&layout)?;
83 let mut output = allocate_decode_output(output_len, options.decode_output_bytes)?;
84
85 let relevant_specs = collect_strip_specs_for_window(ifd, &layout, window, Some(band_index))?;
86
87 #[cfg(feature = "rayon")]
88 {
89 let output = Mutex::new(output.as_mut_slice());
90 relevant_specs.par_iter().try_for_each(|&spec| {
91 let block = read_strip_block(source, ifd_offset, cache, spec, &context, options)?;
92 copy_strip_band_window_block(
93 &mut output.lock(),
94 block.as_slice(),
95 spec,
96 &layout,
97 window,
98 band_index,
99 )?;
100 Ok::<(), Error>(())
101 })?;
102 }
103
104 #[cfg(not(feature = "rayon"))]
105 for spec in relevant_specs {
106 let block = read_strip_block(source, ifd_offset, cache, spec, &context, options)?;
107 copy_strip_band_window_block(
108 &mut output,
109 block.as_slice(),
110 spec,
111 &layout,
112 window,
113 band_index,
114 )?;
115 }
116
117 Ok(output)
118}
119
120fn copy_strip_window_block(
121 output: &mut [u8],
122 block: &[u8],
123 spec: StripBlockSpec,
124 layout: &RasterLayout,
125 window: Window,
126) -> Result<()> {
127 let pixel_stride = layout.checked_pixel_stride_bytes()?;
128 let window_row_end = window.row_end();
129 let output_row_bytes = checked_layout_mul(window.cols, pixel_stride, "window row byte count")?;
130 let block_row_end = checked_layout_add(spec.row_start, spec.rows_in_strip, "strip row range")?;
131 let copy_row_start = spec.row_start.max(window.row_off);
132 let copy_row_end = block_row_end.min(window_row_end);
133
134 if layout.planar_configuration == 1 {
135 let src_row_bytes = layout.checked_row_bytes()?;
136 let src_col_offset =
137 checked_layout_mul(window.col_off, pixel_stride, "strip source column offset")?;
138 let copy_bytes_per_row = output_row_bytes;
139 for row in copy_row_start..copy_row_end {
140 let src_row_index = row - spec.row_start;
141 let dest_row_index = row - window.row_off;
142 let src_offset = checked_layout_add(
143 checked_layout_mul(src_row_index, src_row_bytes, "strip source row offset")?,
144 src_col_offset,
145 "strip source offset",
146 )?;
147 let dest_offset =
148 checked_layout_mul(dest_row_index, output_row_bytes, "strip output row offset")?;
149 let src_end =
150 checked_layout_add(src_offset, copy_bytes_per_row, "strip source copy range")?;
151 let dest_end =
152 checked_layout_add(dest_offset, copy_bytes_per_row, "strip output copy range")?;
153 output[dest_offset..dest_end].copy_from_slice(&block[src_offset..src_end]);
154 }
155 } else {
156 let src_row_bytes = layout.checked_sample_plane_row_bytes()?;
157 let plane_offset = checked_layout_mul(
158 spec.plane,
159 layout.bytes_per_sample,
160 "strip plane byte offset",
161 )?;
162 for row in copy_row_start..copy_row_end {
163 let src_row_index = row - spec.row_start;
164 let dest_row_index = row - window.row_off;
165 let src_row_offset =
166 checked_layout_mul(src_row_index, src_row_bytes, "strip source row offset")?;
167 let src_row_end =
168 checked_layout_add(src_row_offset, src_row_bytes, "strip source row range")?;
169 let dest_row_offset =
170 checked_layout_mul(dest_row_index, output_row_bytes, "strip output row offset")?;
171 let dest_row_end =
172 checked_layout_add(dest_row_offset, output_row_bytes, "strip output row range")?;
173 let src_row = &block[src_row_offset..src_row_end];
174 let dest_row = &mut output[dest_row_offset..dest_row_end];
175 for col in window.col_off..window.col_end() {
176 let src_offset =
177 checked_layout_mul(col, layout.bytes_per_sample, "strip source column offset")?;
178 let src_end = checked_layout_add(
179 src_offset,
180 layout.bytes_per_sample,
181 "strip source sample range",
182 )?;
183 let src = &src_row[src_offset..src_end];
184 let dest_col_index = col - window.col_off;
185 let pixel_base = checked_layout_add(
186 checked_layout_mul(dest_col_index, pixel_stride, "strip output pixel offset")?,
187 plane_offset,
188 "strip output sample offset",
189 )?;
190 let pixel_end = checked_layout_add(
191 pixel_base,
192 layout.bytes_per_sample,
193 "strip output sample range",
194 )?;
195 dest_row[pixel_base..pixel_end].copy_from_slice(src);
196 }
197 }
198 }
199 Ok(())
200}
201
202fn copy_strip_band_window_block(
203 output: &mut [u8],
204 block: &[u8],
205 spec: StripBlockSpec,
206 layout: &RasterLayout,
207 window: Window,
208 band_index: usize,
209) -> Result<()> {
210 let pixel_stride = layout.checked_pixel_stride_bytes()?;
211 let window_row_end = window.row_end();
212 let output_row_bytes = checked_layout_mul(
213 window.cols,
214 layout.bytes_per_sample,
215 "window band row byte count",
216 )?;
217 let block_row_end = checked_layout_add(spec.row_start, spec.rows_in_strip, "strip row range")?;
218 let copy_row_start = spec.row_start.max(window.row_off);
219 let copy_row_end = block_row_end.min(window_row_end);
220
221 if layout.planar_configuration == 1 {
222 let src_row_bytes = layout.checked_row_bytes()?;
223 let band_offset =
224 checked_layout_mul(band_index, layout.bytes_per_sample, "band byte offset")?;
225 for row in copy_row_start..copy_row_end {
226 let src_row_index = row - spec.row_start;
227 let dest_row_index = row - window.row_off;
228 let src_row_offset =
229 checked_layout_mul(src_row_index, src_row_bytes, "strip source row offset")?;
230 let src_row_end =
231 checked_layout_add(src_row_offset, src_row_bytes, "strip source row range")?;
232 let dest_row_offset =
233 checked_layout_mul(dest_row_index, output_row_bytes, "strip output row offset")?;
234 let dest_row_end =
235 checked_layout_add(dest_row_offset, output_row_bytes, "strip output row range")?;
236 let src_row = &block[src_row_offset..src_row_end];
237 let dest_row = &mut output[dest_row_offset..dest_row_end];
238 for col in window.col_off..window.col_end() {
239 let src_base = checked_layout_add(
240 checked_layout_mul(col, pixel_stride, "strip source column offset")?,
241 band_offset,
242 "strip source band offset",
243 )?;
244 let dest_col_index = col - window.col_off;
245 let dest_base = checked_layout_mul(
246 dest_col_index,
247 layout.bytes_per_sample,
248 "strip output sample offset",
249 )?;
250 let src_end = checked_layout_add(
251 src_base,
252 layout.bytes_per_sample,
253 "strip source sample range",
254 )?;
255 let dest_end = checked_layout_add(
256 dest_base,
257 layout.bytes_per_sample,
258 "strip output sample range",
259 )?;
260 dest_row[dest_base..dest_end].copy_from_slice(&src_row[src_base..src_end]);
261 }
262 }
263 } else {
264 let src_row_bytes = layout.checked_sample_plane_row_bytes()?;
265 let src_col_offset = checked_layout_mul(
266 window.col_off,
267 layout.bytes_per_sample,
268 "strip source column offset",
269 )?;
270 let copy_bytes_per_row = output_row_bytes;
271 for row in copy_row_start..copy_row_end {
272 let src_row_index = row - spec.row_start;
273 let dest_row_index = row - window.row_off;
274 let src_offset = checked_layout_add(
275 checked_layout_mul(src_row_index, src_row_bytes, "strip source row offset")?,
276 src_col_offset,
277 "strip source offset",
278 )?;
279 let dest_offset =
280 checked_layout_mul(dest_row_index, output_row_bytes, "strip output row offset")?;
281 let src_end =
282 checked_layout_add(src_offset, copy_bytes_per_row, "strip source copy range")?;
283 let dest_end =
284 checked_layout_add(dest_offset, copy_bytes_per_row, "strip output copy range")?;
285 output[dest_offset..dest_end].copy_from_slice(&block[src_offset..src_end]);
286 }
287 }
288 Ok(())
289}
290
291fn collect_strip_specs_for_window(
292 ifd: &Ifd,
293 layout: &RasterLayout,
294 window: Window,
295 band_index: Option<usize>,
296) -> Result<Vec<StripBlockSpec>> {
297 let offsets = ifd
298 .strip_offsets()
299 .ok_or(Error::TagNotFound(crate::ifd::TAG_STRIP_OFFSETS))?;
300 let counts = ifd
301 .strip_byte_counts()
302 .ok_or(Error::TagNotFound(crate::ifd::TAG_STRIP_BYTE_COUNTS))?;
303 if offsets.len() != counts.len() {
304 return Err(Error::InvalidImageLayout(format!(
305 "StripOffsets has {} entries but StripByteCounts has {}",
306 offsets.len(),
307 counts.len()
308 )));
309 }
310
311 let rows_per_strip = ifd.rows_per_strip();
312 if rows_per_strip == 0 {
313 return Err(Error::InvalidImageLayout(
314 "RowsPerStrip must be greater than zero".into(),
315 ));
316 }
317 let rows_per_strip = rows_per_strip as usize;
318 let strips_per_plane = layout.height.div_ceil(rows_per_strip);
319 let expected = match layout.planar_configuration {
320 1 => strips_per_plane,
321 2 => strips_per_plane
322 .checked_mul(layout.samples_per_pixel)
323 .ok_or_else(strip_count_overflow)?,
324 planar => return Err(Error::UnsupportedPlanarConfiguration(planar)),
325 };
326 if offsets.len() != expected {
327 return Err(Error::InvalidImageLayout(format!(
328 "expected {expected} strips, found {}",
329 offsets.len()
330 )));
331 }
332
333 let first_strip = window.row_off / rows_per_strip;
334 let last_strip = window
335 .row_end()
336 .div_ceil(rows_per_strip)
337 .min(strips_per_plane);
338 let plane_range = if layout.planar_configuration == 1 {
339 0..1
340 } else if let Some(band_index) = band_index {
341 band_index..band_index + 1
342 } else {
343 0..layout.samples_per_pixel
344 };
345 let spec_count = (last_strip - first_strip)
346 .checked_mul(plane_range.end - plane_range.start)
347 .ok_or_else(strip_count_overflow)?;
348 let mut specs = Vec::with_capacity(spec_count);
349
350 for plane in plane_range {
351 for plane_strip_index in first_strip..last_strip {
352 let strip_index = if layout.planar_configuration == 1 {
353 plane_strip_index
354 } else {
355 plane
356 .checked_mul(strips_per_plane)
357 .and_then(|base| base.checked_add(plane_strip_index))
358 .ok_or_else(strip_count_overflow)?
359 };
360 let row_start = plane_strip_index
361 .checked_mul(rows_per_strip)
362 .ok_or_else(strip_count_overflow)?;
363 let rows_in_strip = rows_per_strip.min(layout.height.saturating_sub(row_start));
364 specs.push(StripBlockSpec {
365 index: strip_index,
366 plane,
367 row_start,
368 offset: offsets[strip_index],
369 byte_count: counts[strip_index],
370 rows_in_strip,
371 });
372 }
373 }
374
375 Ok(specs)
376}
377
378fn strip_count_overflow() -> Error {
379 Error::InvalidImageLayout("strip count overflows usize".into())
380}
381
382#[derive(Clone, Copy)]
383struct StripBlockSpec {
384 index: usize,
385 plane: usize,
386 row_start: usize,
387 offset: u64,
388 byte_count: u64,
389 rows_in_strip: usize,
390}
391
392fn read_strip_block(
393 source: &dyn TiffSource,
394 ifd_offset: u64,
395 cache: &BlockCache,
396 spec: StripBlockSpec,
397 context: &block_decode::BlockDecodeContext<'_>,
398 options: DecodeReadOptions<'_>,
399) -> Result<Arc<Vec<u8>>> {
400 let decode_request = block_decode::BlockDecodeRequest {
401 context,
402 compressed: &[],
403 index: spec.index,
404 block_width: context.layout.width,
405 block_height: spec.rows_in_strip,
406 };
407 let decoded_len = block_decode::decoded_block_len(&decode_request)?;
408 validate_decode_output_len(decoded_len, options.decode_output_bytes)?;
409
410 let cache_key = BlockKey {
411 ifd_offset,
412 kind: BlockKind::Strip,
413 block_index: spec.index,
414 };
415 if let Some(cached) = cache.get(&cache_key) {
416 return Ok(cached);
417 }
418
419 if spec.offset == 0 || spec.byte_count == 0 {
422 let decoded = allocate_decode_output(decoded_len, options.decode_output_bytes)?;
423 return Ok(cache.insert(cache_key, decoded));
424 }
425
426 let byte_count_limit = block_decode::compressed_block_byte_count_limit(&decode_request)?;
427 let compressed = match options.gdal_structural_metadata {
428 Some(metadata) => read_gdal_block_payload(
429 source,
430 metadata,
431 context.byte_order,
432 spec.offset,
433 spec.byte_count,
434 byte_count_limit,
435 spec.index,
436 )?,
437 None => read_block_payload(
438 source,
439 spec.offset,
440 spec.byte_count,
441 byte_count_limit,
442 spec.index,
443 )?,
444 };
445
446 let decoded = block_decode::decode_compressed_block(block_decode::BlockDecodeRequest {
447 context,
448 compressed: &compressed,
449 index: spec.index,
450 block_width: context.layout.width,
451 block_height: spec.rows_in_strip,
452 })?;
453 Ok(cache.insert(cache_key, decoded))
454}