From 5cadbffebf899fe975b7e63a51ebde183dc00334 Mon Sep 17 00:00:00 2001 From: Alan Race Date: Mon, 11 Jul 2022 08:56:35 +0200 Subject: [PATCH] Changed to use `u32` for chunk_index --- src/decoder/image.rs | 97 ++++++++++++++++++++++-------------------- src/decoder/mod.rs | 33 ++++++++------ src/error.rs | 2 +- tests/decode_images.rs | 2 +- tests/encode_images.rs | 2 +- 5 files changed, 74 insertions(+), 62 deletions(-) diff --git a/src/decoder/image.rs b/src/decoder/image.rs index d5cf4fb..d761411 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -67,29 +67,29 @@ impl TileAttributes { pub struct ChunkInfo { /// Width of the chunk as specified (includes potential padding). This has the same /// value for all chunks in the image. - pub chunk_width: usize, + pub chunk_width: u32, /// Height/Length of the chunk as specified (includes potential padding). This has /// the same value for all chunks in the image. - pub chunk_height: usize, + pub chunk_height: u32, /// Width of the data (excluding potential padding). This can take different values /// on the right column of the image due to padding. - pub data_width: usize, + pub data_width: u32, /// Height/Length of the data (excluding potential padding). This can take different values /// on the bottom row of the image due to padding. - pub data_height: usize, + pub data_height: u32, } impl ChunkInfo { #[inline] /// Returns the amount of padding (pixles) on the right-side of the chunk. - pub fn padding_right(&self) -> usize { + pub fn padding_right(&self) -> u32 { self.chunk_width - self.data_width } #[inline] /// Returns the amount of padding (pixles) on the bottom-side of the chunk. - pub fn padding_down(&self) -> usize { + pub fn padding_down(&self) -> u32 { self.chunk_height - self.data_height } } @@ -390,14 +390,20 @@ impl Image { }) } - pub(crate) fn chunk_file_range(&self, chunk: usize) -> TiffResult<(u64, u64)> { - let file_offset = self.chunk_offsets.get(chunk).ok_or(TiffError::FormatError( - TiffFormatError::InconsistentSizesEncountered, - ))?; + pub(crate) fn chunk_file_range(&self, chunk: u32) -> TiffResult<(u64, u64)> { + let file_offset = self + .chunk_offsets + .get(chunk as usize) + .ok_or(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + ))?; - let compressed_bytes = self.chunk_bytes.get(chunk).ok_or(TiffError::FormatError( - TiffFormatError::InconsistentSizesEncountered, - ))?; + let compressed_bytes = + self.chunk_bytes + .get(chunk as usize) + .ok_or(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + ))?; Ok((*file_offset, *compressed_bytes)) } @@ -416,42 +422,39 @@ impl Image { } } - pub(crate) fn chunk_info(&self, chunk_index: usize) -> Option { + pub(crate) fn chunk_info(&self, chunk_index: u32) -> Option { match &self.chunk_type { ChunkType::Strip => { - let rows_per_strip = self.strip_decoder.as_ref().unwrap().rows_per_strip as usize; - - let sized_width = self.width as usize; - let sized_height = self.height as usize; + let rows_per_strip = self.strip_decoder.as_ref().unwrap().rows_per_strip; let strip_height_without_padding = chunk_index .checked_mul(rows_per_strip) - .and_then(|x| sized_height.checked_sub(x))?; + .and_then(|x| self.height.checked_sub(x))?; // Ignore potential vertical padding on the bottommost strip let strip_height = rows_per_strip.min(strip_height_without_padding); Some(ChunkInfo { - chunk_width: sized_width, + chunk_width: self.width, chunk_height: rows_per_strip, - data_width: sized_width, + data_width: self.width, data_height: strip_height, }) } ChunkType::Tile => { let tile_attrs = self.tile_attributes.as_ref().unwrap(); - let (padding_right, padding_down) = tile_attrs.get_padding(chunk_index); + let (padding_right, padding_down) = tile_attrs.get_padding(chunk_index as usize); let tile_width = tile_attrs.tile_width - padding_right; let tile_length = tile_attrs.tile_length - padding_down; Some(ChunkInfo { - chunk_width: tile_attrs.tile_width, - chunk_height: tile_attrs.tile_length, + chunk_width: tile_attrs.tile_width as u32, + chunk_height: tile_attrs.tile_length as u32, - data_width: tile_width, - data_height: tile_length, + data_width: tile_width as u32, + data_height: tile_length as u32, }) } } @@ -463,7 +466,7 @@ impl Image { mut buffer: DecodingBuffer, output_width: usize, byte_order: ByteOrder, - chunk_index: usize, + chunk_index: u32, ) -> TiffResult<()> { // Validate that the provided buffer is of the expected type. let color_type = self.colortype()?; @@ -512,12 +515,12 @@ impl Image { _ => {} } - let compressed_bytes = self - .chunk_bytes - .get(chunk_index) - .ok_or(TiffError::FormatError( - TiffFormatError::InconsistentSizesEncountered, - ))?; + let compressed_bytes = + self.chunk_bytes + .get(chunk_index as usize) + .ok_or(TiffError::FormatError( + TiffFormatError::InconsistentSizesEncountered, + ))?; let byte_len = buffer.byte_len(); let compression_method = self.compression_method; @@ -533,14 +536,15 @@ impl Image { let mut reader = Self::create_reader(reader, compression_method, *compressed_bytes, jpeg_tables)?; - if output_width == chunk_info.data_width && chunk_info.padding_right() == 0 { - let total_samples = chunk_info.data_width * chunk_info.data_height * samples; + if output_width == chunk_info.data_width as usize && chunk_info.padding_right() == 0 { + let total_samples = + chunk_info.data_width as usize * chunk_info.data_height as usize * samples; let tile = &mut buffer.as_bytes_mut()[..total_samples * byte_len]; reader.read_exact(tile)?; - for row in 0..chunk_info.data_height { - let row_start = row * output_width * samples; - let row_end = (row + 1) * output_width * samples; + for row in 0..chunk_info.data_height as usize { + let row_start = row as usize * output_width as usize * samples; + let row_end = (row + 1) * output_width as usize * samples; let row = buffer.subrange(row_start..row_end); super::fix_endianness_and_predict(row, samples, byte_order, predictor); } @@ -550,10 +554,10 @@ impl Image { } 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_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_info.data_width * samples; + let mut encoded = vec![0u8; chunk_info.chunk_width as usize * samples * byte_len]; + for row in 0..chunk_info.data_height as usize { + let row_start = row * output_width as usize * samples; + let row_end = row_start + chunk_info.data_width as usize * samples; reader.read_exact(&mut encoded)?; match buffer.subrange(row_start..row_end) { @@ -566,16 +570,17 @@ impl Image { } } } else { - for row in 0..chunk_info.data_height { - let row_start = row * output_width * samples; - let row_end = row_start + chunk_info.data_width * samples; + for row in 0..chunk_info.data_height as usize { + let row_start = row * output_width as usize * samples; + let row_end = row_start + chunk_info.data_width as usize * samples; let row = &mut buffer.as_bytes_mut()[(row_start * byte_len)..(row_end * byte_len)]; reader.read_exact(row)?; // Skip horizontal padding if chunk_info.padding_right() > 0 { - let len = u64::try_from(chunk_info.padding_right() * samples * byte_len)?; + let len = + u64::try_from(chunk_info.padding_right() as usize * samples * byte_len)?; io::copy(&mut reader.by_ref().take(len), &mut io::sink())?; } diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index b7a6b5d..2dd020a 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -301,7 +301,7 @@ where reader: SmartReader, bigtiff: bool, limits: Limits, - current_chunk: usize, + current_chunk: u32, next_ifd: Option, ifd_offsets: Vec, seen_ifds: HashSet, @@ -1064,13 +1064,13 @@ impl Decoder { Ok(()) } - fn read_chunk_to_buffer( + pub fn read_chunk_to_buffer( &mut self, mut buffer: DecodingBuffer, - tile_index: usize, + chunk_index: u32, output_width: usize, ) -> TiffResult<()> { - let offset = self.image.chunk_file_range(tile_index)?.0; + let offset = self.image.chunk_file_range(chunk_index)?.0; self.goto_offset_u64(offset)?; let byte_order = self.reader.byte_order; @@ -1080,7 +1080,7 @@ impl Decoder { buffer.copy(), output_width, byte_order, - tile_index, + chunk_index, )?; Ok(()) @@ -1143,9 +1143,9 @@ impl Decoder { /// information on the size of the strip read and so the caller must take care of the final /// strip in the image as the data read may be less than the expected strip size. This interface /// may change at a future date to reflect this. - #[deprecated = "Use read_chunk_at instead"] + #[deprecated = "Use read_chunk instead"] pub fn read_strip(&mut self) -> TiffResult { - let result = self.read_chunk_at(self.current_chunk)?; + let result = self.read_chunk(self.current_chunk)?; Ok(result.0) } @@ -1154,9 +1154,9 @@ impl Decoder { /// information on the size of the tile read and so the caller must take care of tiles on the /// rightmost column and the bottommost row in the image as the data read may be less than the /// expected tile size. This interface may change at a future date to reflect this. - #[deprecated = "Use read_chunk_at instead"] + #[deprecated = "Use read_chunk instead"] pub fn read_tile(&mut self) -> TiffResult { - let result = self.read_chunk_at(self.current_chunk)?; + let result = self.read_chunk(self.current_chunk)?; self.current_chunk += 1; @@ -1165,15 +1165,22 @@ impl Decoder { /// 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)> { + pub fn read_chunk(&mut self, chunk_index: u32) -> TiffResult<(DecodingResult, ChunkInfo)> { let chunk_info = self .image() .chunk_info(chunk_index) .ok_or(UsageError::InvalidChunkIndex(chunk_index))?; - let mut result = self.result_buffer(chunk_info.data_width, chunk_info.data_height)?; + let mut result = self.result_buffer( + chunk_info.data_width as usize, + chunk_info.data_height as usize, + )?; - self.read_chunk_to_buffer(result.as_buffer(0), chunk_index, chunk_info.data_width)?; + self.read_chunk_to_buffer( + result.as_buffer(0), + chunk_index, + chunk_info.data_width as usize, + )?; Ok((result, chunk_info)) } @@ -1220,7 +1227,7 @@ impl Decoder { result.as_buffer(buffer_offset).copy(), width, byte_order, - chunk, + chunk as u32, )?; } diff --git a/src/error.rs b/src/error.rs index c03d371..8c8ac8b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -205,7 +205,7 @@ impl fmt::Display for TiffUnsupportedError { #[derive(Debug)] pub enum UsageError { InvalidChunkType(ChunkType, ChunkType), - InvalidChunkIndex(usize), + InvalidChunkIndex(u32), } impl fmt::Display for UsageError { diff --git a/tests/decode_images.rs b/tests/decode_images.rs index f96046e..de92c45 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_chunk_at(tile as usize).unwrap() { + match decoder.read_chunk(tile).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 8db3bac..f336636 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_chunk_at(i as usize).unwrap() { + match decoder.read_chunk(i as u32).unwrap() { (DecodingResult::U8(data), _) => assert_eq!(&img2[..], &data[..]), other => panic!("Incorrect strip type {:?}", other), }