diff --git a/src/decoder/image.rs b/src/decoder/image.rs index 35fcfeb..172feb7 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -512,9 +512,12 @@ impl Image { _ => {} } - let compressed_bytes = self.chunk_bytes.get(chunk).ok_or(TiffError::FormatError( - TiffFormatError::InconsistentSizesEncountered, - ))?; + let compressed_bytes = self + .chunk_bytes + .get(chunk_index) + .ok_or(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + ))?; let byte_len = buffer.byte_len(); let compression_method = self.compression_method; @@ -535,7 +538,7 @@ impl Image { let tile = &mut buffer.as_bytes_mut()[..total_samples * byte_len]; reader.read_exact(tile)?; - for row in 0..(chunk_dimensions.1 - padding.1) { + for row in 0..chunk_info.data_height { let row_start = row * output_width * samples; let row_end = (row + 1) * output_width * samples; let row = buffer.subrange(row_start..row_end); @@ -544,13 +547,13 @@ impl Image { if photometric_interpretation == PhotometricInterpretation::WhiteIsZero { super::invert_colors(&mut buffer.subrange(0..total_samples), color_type); } - } else if padding.0 > 0 && self.predictor == Predictor::FloatingPoint { + } else if chunk_info.padding_right() > 0 && self.predictor == Predictor::FloatingPoint { // The floating point predictor shuffles the padding bytes into the encoded output, so // this case is handled specially when needed. - let mut encoded = vec![0u8; chunk_dimensions.0 * samples * byte_len]; - for row in 0..(chunk_dimensions.1 - padding.1) { + let mut encoded = vec![0u8; chunk_info.chunk_width * samples * byte_len]; + for row in 0..chunk_info.data_height { let row_start = row * output_width * samples; - let row_end = row_start + (chunk_dimensions.0 - padding.0) * samples; + let row_end = row_start + chunk_info.data_width * samples; reader.read_exact(&mut encoded)?; match buffer.subrange(row_start..row_end) { diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 1555858..27e1465 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -1042,6 +1042,7 @@ impl Decoder { self.read_image() } + #[deprecated = "Use read_chunk_to_buffer instead"] pub fn read_strip_to_buffer(&mut self, mut buffer: DecodingBuffer) -> TiffResult<()> { self.check_chunk_type(ChunkType::Strip)?; @@ -1063,6 +1064,7 @@ impl Decoder { Ok(()) } + #[deprecated = "Use read_chunk_to_buffer instead"] fn read_tile_to_buffer( &mut self, mut buffer: DecodingBuffer, @@ -1087,6 +1089,28 @@ impl Decoder { Ok(()) } + fn read_chunk_to_buffer( + &mut self, + mut buffer: DecodingBuffer, + tile_index: usize, + output_width: usize, + ) -> TiffResult<()> { + let offset = self.image.chunk_file_range(tile_index)?.0; + self.goto_offset_u64(offset)?; + + let byte_order = self.reader.byte_order; + + self.image.expand_chunk( + &mut self.reader, + buffer.copy(), + output_width, + byte_order, + tile_index, + )?; + + Ok(()) + } + fn result_buffer(&self, width: usize, height: usize) -> TiffResult { let buffer_size = match width .checked_mul(height) @@ -1146,6 +1170,8 @@ impl Decoder { /// may change at a future date to reflect this. /// /// `read_strip_at` can be used to get both the strip data and the strip size. + /// + #[deprecated = "Use read_chunk instead"] pub fn read_strip(&mut self) -> TiffResult { let result = self.read_strip_at(self.current_chunk)?; @@ -1154,6 +1180,8 @@ impl Decoder { /// Read the specified strip (at index `strip_index`) and return the binary data as a Vector and /// `ChunkInfo` describing the size of the strip. + /// + #[deprecated = "Use read_chunk instead"] pub fn read_strip_at(&mut self, strip_index: usize) -> TiffResult<(DecodingResult, ChunkInfo)> { self.check_chunk_type(ChunkType::Strip)?; @@ -1174,6 +1202,7 @@ impl Decoder { /// expected tile size. This interface may change at a future date to reflect this. /// /// `read_tile_at` can be used to get both the tile data and the tile size. + #[deprecated = "Use read_chunk instead"] pub fn read_tile(&mut self) -> TiffResult { let result = self.read_tile_at(self.current_chunk)?; @@ -1184,6 +1213,7 @@ impl Decoder { /// Read the specified tile (at index `tile_index`) and return the binary data as a Vector and /// `ChunkInfo` describing the size of the tile. + #[deprecated = "Use read_chunk_at instead"] pub fn read_tile_at(&mut self, tile_index: usize) -> TiffResult<(DecodingResult, ChunkInfo)> { self.check_chunk_type(ChunkType::Tile)?; @@ -1199,6 +1229,35 @@ impl Decoder { Ok((result, chunk_info)) } + /// Read a single chunk from the image and return it as a Vector. This method does not return + /// information on the size of the chunk read and so the caller must take care of chunks on the + /// rightmost column and the bottommost row in the image as the data read may be less than the + /// expected chunk size. This interface may change at a future date to reflect this. + /// + /// `read_chunk_at` can be used to get both the chunk data and the tile size. + pub fn read_chunk(&mut self) -> TiffResult { + let result = self.read_chunk_at(self.current_chunk)?; + + self.current_chunk += 1; + + Ok(result.0) + } + + /// Read the specified chunk (at index `chunk_index`) and return the binary data as a Vector and + /// `ChunkInfo` describing the size of the chunk. + pub fn read_chunk_at(&mut self, chunk_index: usize) -> TiffResult<(DecodingResult, ChunkInfo)> { + let chunk_info = self + .image() + .chunk_info(chunk_index) + .ok_or(TiffFormatError::InvalidChunkIndex(chunk_index))?; + + let mut result = self.result_buffer(chunk_info.data_width, chunk_info.data_height)?; + + self.read_chunk_to_buffer(result.as_buffer(0), chunk_index, chunk_info.data_width)?; + + Ok((result, chunk_info)) + } + /// Decodes the entire image and return it as a Vector pub fn read_image(&mut self) -> TiffResult { let width = usize::try_from(self.image().width)?; diff --git a/tests/decode_images.rs b/tests/decode_images.rs index df43524..b0f08d5 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -275,7 +275,7 @@ fn test_tiled_incremental() { assert_eq!(tiles as usize, sums.len()); for tile in 0..tiles { - match decoder.read_tile().unwrap() { + match decoder.read_chunk().unwrap() { DecodingResult::U8(res) => { let sum: u64 = res.into_iter().map(::from).sum(); assert_eq!(sum, sums[tile as usize]); diff --git a/tests/encode_images.rs b/tests/encode_images.rs index a8e1ca3..af35d91 100644 --- a/tests/encode_images.rs +++ b/tests/encode_images.rs @@ -512,7 +512,7 @@ fn test_rows_per_strip() { for i in 0..50 { let img2 = [i; 2 * 100]; - match decoder.read_strip().unwrap() { + match decoder.read_chunk().unwrap() { DecodingResult::U8(data) => assert_eq!(&img2[..], &data[..]), other => panic!("Incorrect strip type {:?}", other), }