Compute tile attributes on demand
This commit is contained in:
1 parent
a36cd6bd90
commit
6ba5553d20
1 file changed
+52
-48
+52
-48
@@ -241,42 +241,58 @@ struct StripDecodeState {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Computed values useful for tile decoding
|
/// Computed values useful for tile decoding
|
||||||
struct TileAttributes {
|
struct TileAttributes {
|
||||||
|
image_width: usize,
|
||||||
|
image_height: usize,
|
||||||
|
samples_per_pixel: usize,
|
||||||
|
|
||||||
tile_width: usize,
|
tile_width: usize,
|
||||||
tile_length: usize,
|
tile_length: usize,
|
||||||
tiles_down: usize,
|
|
||||||
tiles_across: usize,
|
|
||||||
/// Length of padding for rightmost tiles in pixels
|
|
||||||
padding_right: usize,
|
|
||||||
/// length of padding for bottommost tile in pixels
|
|
||||||
padding_down: usize,
|
|
||||||
tile_samples: usize,
|
|
||||||
/// Sample count of one row of one tile
|
|
||||||
row_samples: usize,
|
|
||||||
/// Sample count of one row of tiles
|
|
||||||
tile_strip_samples: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileAttributes {
|
impl TileAttributes {
|
||||||
|
fn tiles_across(&self) -> usize {
|
||||||
|
(self.image_width + self.tile_width - 1) / self.tile_width
|
||||||
|
}
|
||||||
|
fn tiles_down(&self) -> usize {
|
||||||
|
(self.image_height + self.tile_length - 1) / self.tile_length
|
||||||
|
}
|
||||||
|
fn padding_right(&self) -> usize {
|
||||||
|
self.tile_width - self.image_width % self.tile_width
|
||||||
|
}
|
||||||
|
fn padding_down(&self) -> usize {
|
||||||
|
self.tile_length - self.image_height % self.tile_length
|
||||||
|
}
|
||||||
|
fn row_samples(&self) -> usize {
|
||||||
|
self.tile_width * self.samples_per_pixel
|
||||||
|
}
|
||||||
|
fn tile_samples(&self) -> usize {
|
||||||
|
self.tile_length * self.tile_width * self.samples_per_pixel
|
||||||
|
}
|
||||||
|
fn tile_strip_samples(&self) -> usize {
|
||||||
|
(self.tile_samples() * self.tiles_across())
|
||||||
|
- (self.padding_right() * self.tile_length * self.samples_per_pixel)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the tile offset in the result buffer, counted in samples
|
/// Returns the tile offset in the result buffer, counted in samples
|
||||||
fn get_offset(&self, tile: usize) -> usize {
|
fn get_offset(&self, tile: usize) -> usize {
|
||||||
let row = tile / self.tiles_across;
|
let row = tile / self.tiles_across();
|
||||||
let column = tile % self.tiles_across;
|
let column = tile % self.tiles_across();
|
||||||
|
|
||||||
(row * self.tile_strip_samples) + (column * self.row_samples)
|
(row * self.tile_strip_samples()) + (column * self.row_samples())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_padding(&self, tile: usize) -> (usize, usize) {
|
fn get_padding(&self, tile: usize) -> (usize, usize) {
|
||||||
let row = tile / self.tiles_across;
|
let row = tile / self.tiles_across();
|
||||||
let column = tile % self.tiles_across;
|
let column = tile % self.tiles_across();
|
||||||
|
|
||||||
let padding_right = if column == self.tiles_across - 1 {
|
let padding_right = if column == self.tiles_across() - 1 {
|
||||||
self.padding_right
|
self.padding_right()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
let padding_down = if row == self.tiles_down - 1 {
|
let padding_down = if row == self.tiles_down() - 1 {
|
||||||
self.padding_down
|
self.padding_down()
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
@@ -757,29 +773,24 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
return Err(TiffFormatError::InvalidTagValueType(Tag::TileLength).into());
|
return Err(TiffFormatError::InvalidTagValueType(Tag::TileLength).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let tiles_across = (usize::try_from(self.width)? + tile_width - 1) / tile_width;
|
|
||||||
let tiles_down = (usize::try_from(self.height)? + tile_length - 1) / tile_length;
|
|
||||||
|
|
||||||
let samples_per_pixel = self.bits_per_sample.len();
|
|
||||||
|
|
||||||
let tile_samples = tile_length * tile_width * samples_per_pixel;
|
|
||||||
let padding_right = (tiles_across * tile_width) - usize::try_from(self.width)?;
|
|
||||||
let tile_strip_samples = (tile_samples * tiles_across)
|
|
||||||
- (padding_right * tile_length * samples_per_pixel);
|
|
||||||
|
|
||||||
self.tile_attributes = Some(TileAttributes {
|
self.tile_attributes = Some(TileAttributes {
|
||||||
|
image_width: usize::try_from(self.width)?,
|
||||||
|
image_height: usize::try_from(self.height)?,
|
||||||
|
samples_per_pixel: self.bits_per_sample.len(),
|
||||||
tile_width,
|
tile_width,
|
||||||
tile_length,
|
tile_length,
|
||||||
tiles_across,
|
|
||||||
tiles_down,
|
|
||||||
tile_samples,
|
|
||||||
padding_right,
|
|
||||||
padding_down: (tiles_down * tile_length) - usize::try_from(self.height)?,
|
|
||||||
row_samples: (tile_width * samples_per_pixel),
|
|
||||||
tile_strip_samples,
|
|
||||||
});
|
});
|
||||||
self.chunk_offsets = self.get_tag_u64_vec(Tag::TileOffsets)?;
|
self.chunk_offsets = self.get_tag_u64_vec(Tag::TileOffsets)?;
|
||||||
self.chunk_bytes = self.get_tag_u64_vec(Tag::TileByteCounts)?;
|
self.chunk_bytes = self.get_tag_u64_vec(Tag::TileByteCounts)?;
|
||||||
|
|
||||||
|
let tile = self.tile_attributes.as_ref().unwrap();
|
||||||
|
if self.chunk_offsets.len() != self.chunk_bytes.len()
|
||||||
|
|| self.chunk_offsets.len() != tile.tiles_down() * tile.tiles_across()
|
||||||
|
{
|
||||||
|
return Err(TiffError::FormatError(
|
||||||
|
TiffFormatError::InconsistentSizesEncountered,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(_, _, _, _) => {
|
(_, _, _, _) => {
|
||||||
return Err(TiffError::FormatError(
|
return Err(TiffError::FormatError(
|
||||||
@@ -1246,9 +1257,9 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
|
|
||||||
let tile_attrs = self.tile_attributes.as_mut().unwrap();
|
let tile_attrs = self.tile_attributes.as_mut().unwrap();
|
||||||
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
let (padding_right, padding_down) = tile_attrs.get_padding(tile);
|
||||||
let tile_samples = tile_attrs.tile_samples;
|
let tile_samples = tile_attrs.tile_samples();
|
||||||
let tile_length = tile_attrs.tile_length;
|
let tile_length = tile_attrs.tile_length;
|
||||||
let row_samples = tile_attrs.row_samples;
|
let row_samples = tile_attrs.row_samples();
|
||||||
let padding_right_samples = padding_right * self.bits_per_sample.len();
|
let padding_right_samples = padding_right * self.bits_per_sample.len();
|
||||||
|
|
||||||
self.goto_offset_u64(offset)?;
|
self.goto_offset_u64(offset)?;
|
||||||
@@ -1371,10 +1382,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// Number of tiles in image
|
/// Number of tiles in image
|
||||||
pub fn tile_count(&mut self) -> TiffResult<u32> {
|
pub fn tile_count(&mut self) -> TiffResult<u32> {
|
||||||
self.check_chunk_type(ChunkType::Tile)?;
|
self.check_chunk_type(ChunkType::Tile)?;
|
||||||
let tile_attrs = self.tile_attributes.as_ref().unwrap();
|
Ok(u32::try_from(self.chunk_offsets.len())?)
|
||||||
Ok(u32::try_from(
|
|
||||||
tile_attrs.tiles_across * tile_attrs.tiles_down,
|
|
||||||
)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_jpeg(&mut self) -> TiffResult<DecodingResult> {
|
pub fn read_jpeg(&mut self) -> TiffResult<DecodingResult> {
|
||||||
@@ -1623,11 +1631,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let width = usize::try_from(self.width)?;
|
let width = usize::try_from(self.width)?;
|
||||||
let mut result = self.result_buffer(width, usize::try_from(self.height)?)?;
|
let mut result = self.result_buffer(width, usize::try_from(self.height)?)?;
|
||||||
|
|
||||||
let tile_attrs = self.tile_attributes.as_ref().unwrap();
|
for tile in 0..self.chunk_offsets.len() {
|
||||||
let tiles_across = tile_attrs.tiles_across;
|
|
||||||
let tiles_down = tile_attrs.tiles_down;
|
|
||||||
|
|
||||||
for tile in 0..(tiles_across * tiles_down) {
|
|
||||||
let buffer_offset = self.tile_attributes.as_ref().unwrap().get_offset(tile);
|
let buffer_offset = self.tile_attributes.as_ref().unwrap().get_offset(tile);
|
||||||
self.read_tile_to_buffer(&mut result.as_buffer(buffer_offset), tile, width)?;
|
self.read_tile_to_buffer(&mut result.as_buffer(buffer_offset), tile, width)?;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user