Expand PreferredLayout for planar information
This commit is contained in:
1 parent
61b3027f38
commit
f9eaf9632a
3 files changed
+62
-7
No files matched your search
+16
-1
@@ -45,6 +45,8 @@ pub(crate) struct PlaneLayout {
|
|||||||
pub plane_stride: usize,
|
pub plane_stride: usize,
|
||||||
/// Buffer offset from one plane of output to the next.
|
/// Buffer offset from one plane of output to the next.
|
||||||
pub plane_offsets: Vec<usize>,
|
pub plane_offsets: Vec<usize>,
|
||||||
|
/// Total number of bytes for all planes in given order.
|
||||||
|
pub total_bytes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileAttributes {
|
impl TileAttributes {
|
||||||
@@ -655,11 +657,23 @@ impl Image {
|
|||||||
.ok_or(TiffError::LimitsExceeded)?
|
.ok_or(TiffError::LimitsExceeded)?
|
||||||
.try_into()?;
|
.try_into()?;
|
||||||
|
|
||||||
let plane_offsets = (0..=usize::MAX)
|
// Using the standard range iterator as checked_add on steroids.
|
||||||
|
let mut offset = 0..=usize::MAX;
|
||||||
|
|
||||||
|
let plane_offsets = offset
|
||||||
|
.by_ref()
|
||||||
|
// Note: for supporting subsampling, adjust as required.
|
||||||
.step_by(plane_stride)
|
.step_by(plane_stride)
|
||||||
.take(usize::from(color.num_samples() / samples))
|
.take(usize::from(color.num_samples() / samples))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
// Get the past-the-end of the last plane.
|
||||||
|
//
|
||||||
|
// This also verifies the `take` above was not short.
|
||||||
|
let Some(total_bytes) = offset.nth(plane_stride) else {
|
||||||
|
return Err(TiffError::LimitsExceeded);
|
||||||
|
};
|
||||||
|
|
||||||
let chunks_across: usize = ((width - 1) / chunk_dimensions.0 + 1).try_into()?;
|
let chunks_across: usize = ((width - 1) / chunk_dimensions.0 + 1).try_into()?;
|
||||||
|
|
||||||
// We would not get an offset in byte units, sorry, no bit interleaving.
|
// We would not get an offset in byte units, sorry, no bit interleaving.
|
||||||
@@ -679,6 +693,7 @@ impl Image {
|
|||||||
chunk_row_stride,
|
chunk_row_stride,
|
||||||
plane_stride,
|
plane_stride,
|
||||||
plane_offsets,
|
plane_offsets,
|
||||||
|
total_bytes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+44
-5
@@ -205,6 +205,7 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
/// caller provided buffer must fit the expectations of the decoder to be filled with data from the
|
/// caller provided buffer must fit the expectations of the decoder to be filled with data from the
|
||||||
/// current image.
|
/// current image.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct BufferLayoutPreference {
|
pub struct BufferLayoutPreference {
|
||||||
/// Minimum byte size of the buffer to read image data.
|
/// Minimum byte size of the buffer to read image data.
|
||||||
pub len: usize,
|
pub len: usize,
|
||||||
@@ -214,6 +215,8 @@ pub struct BufferLayoutPreference {
|
|||||||
pub planes: usize,
|
pub planes: usize,
|
||||||
/// Number of bytes used to represent one plane.
|
/// Number of bytes used to represent one plane.
|
||||||
pub plane_stride: Option<NonZeroUsize>,
|
pub plane_stride: Option<NonZeroUsize>,
|
||||||
|
/// Number of bytes of data when reading all planes.
|
||||||
|
pub complete_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The count and matching discriminant for a `DecodingBuffer`.
|
/// The count and matching discriminant for a `DecodingBuffer`.
|
||||||
@@ -992,16 +995,47 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let output_row_stride = (output_width as u64)
|
let output_row_stride = (output_width as u64)
|
||||||
.saturating_mul(self.image.samples_per_out_texel(color) as u64)
|
.saturating_mul(self.image.samples_per_out_texel(color) as u64)
|
||||||
.saturating_mul(self.image.bits_per_sample as u64)
|
.saturating_mul(self.image.bits_per_sample as u64)
|
||||||
.div_ceil(8);
|
.div_ceil(8)
|
||||||
|
.try_into()?;
|
||||||
|
|
||||||
self.read_chunk_to_bytes(buffer.as_bytes_mut(), chunk_index, output_row_stride)
|
self.read_chunk_to_bytes(buffer.as_bytes_mut(), chunk_index, output_row_stride)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read all planes from a specific tile.
|
||||||
|
///
|
||||||
|
/// This behaves in one of two ways depending on the planar configuration of the image:
|
||||||
|
/// 1. For chunky images, this reads the specified chunk index as if by
|
||||||
|
/// [`Self::read_chunk_bytes`].
|
||||||
|
/// 2. For planar images, this reads the chunks of each complete plane to appropriate offsets
|
||||||
|
/// in the output buffer. The size of the buffer determines the number of planes being read.
|
||||||
|
/// The `chunk_index` determines the index of the first plane being read.
|
||||||
|
pub fn read_plane_bytes(&mut self, chunk_index: u32, buffer: &mut [u8]) -> TiffResult<()> {
|
||||||
|
let layout = self.image().preferred_output_layout()?;
|
||||||
|
|
||||||
|
let plane_offsets = [0usize];
|
||||||
|
let used_plane_offsets = 1;
|
||||||
|
let plane_chunks = 0u32;
|
||||||
|
|
||||||
|
for (idx, &plane_offset) in plane_offsets[..used_plane_offsets].iter().enumerate() {
|
||||||
|
let chunk_index = chunk_index + idx as u32 * plane_chunks;
|
||||||
|
|
||||||
|
self.read_chunk_to_bytes(
|
||||||
|
&mut buffer[plane_offset..],
|
||||||
|
chunk_index,
|
||||||
|
layout.output_row_stride,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_chunk_to_bytes(
|
fn read_chunk_to_bytes(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &mut [u8],
|
buffer: &mut [u8],
|
||||||
chunk_index: u32,
|
chunk_index: u32,
|
||||||
output_row_stride: u64,
|
output_row_stride: usize,
|
||||||
) -> TiffResult<()> {
|
) -> TiffResult<()> {
|
||||||
let offset = self.image.chunk_file_range(chunk_index)?.0;
|
let offset = self.image.chunk_file_range(chunk_index)?.0;
|
||||||
self.goto_offset_u64(offset)?;
|
self.goto_offset_u64(offset)?;
|
||||||
@@ -1009,7 +1043,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.image.expand_chunk(
|
self.image.expand_chunk(
|
||||||
&mut self.value_reader,
|
&mut self.value_reader,
|
||||||
buffer,
|
buffer,
|
||||||
output_row_stride.try_into()?,
|
output_row_stride,
|
||||||
chunk_index,
|
chunk_index,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -1121,6 +1155,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
row_stride,
|
row_stride,
|
||||||
planes: 1,
|
planes: 1,
|
||||||
plane_stride,
|
plane_stride,
|
||||||
|
complete_len: layout.size(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,7 +1194,8 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
let output_row_stride = u64::from(data_dims.0)
|
let output_row_stride = u64::from(data_dims.0)
|
||||||
.saturating_mul(self.image.samples_per_pixel() as u64)
|
.saturating_mul(self.image.samples_per_pixel() as u64)
|
||||||
.saturating_mul(self.image.bits_per_sample as u64)
|
.saturating_mul(self.image.bits_per_sample as u64)
|
||||||
.div_ceil(8);
|
.div_ceil(8)
|
||||||
|
.try_into()?;
|
||||||
|
|
||||||
self.read_chunk_to_bytes(buffer, chunk_index, output_row_stride)?;
|
self.read_chunk_to_bytes(buffer, chunk_index, output_row_stride)?;
|
||||||
|
|
||||||
@@ -1201,6 +1237,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
row_stride: core::num::NonZeroUsize::new(layout.output_row_stride),
|
row_stride: core::num::NonZeroUsize::new(layout.output_row_stride),
|
||||||
planes: layout.plane_offsets.len(),
|
planes: layout.plane_offsets.len(),
|
||||||
plane_stride: core::num::NonZeroUsize::new(layout.plane_stride),
|
plane_stride: core::num::NonZeroUsize::new(layout.plane_stride),
|
||||||
|
complete_len: layout.total_bytes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1239,6 +1276,8 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
chunks_across,
|
chunks_across,
|
||||||
plane_stride,
|
plane_stride,
|
||||||
plane_offsets,
|
plane_offsets,
|
||||||
|
// We assume that is correct, so really it can be ignored.
|
||||||
|
total_bytes: _,
|
||||||
} = self.image().preferred_output_layout()?;
|
} = self.image().preferred_output_layout()?;
|
||||||
|
|
||||||
// Find how many planes fit into the output buffer.
|
// Find how many planes fit into the output buffer.
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ fn read_all_planes() {
|
|||||||
assert_eq!(layout.planes, 3);
|
assert_eq!(layout.planes, 3);
|
||||||
let plane_stride = layout.plane_stride.map_or(0, |x| x.get());
|
let plane_stride = layout.plane_stride.map_or(0, |x| x.get());
|
||||||
|
|
||||||
let mut buffer = vec![0u8; layout.planes * plane_stride];
|
eprintln!("{:?}", layout);
|
||||||
|
let mut buffer = vec![0u8; layout.complete_len];
|
||||||
tif.read_image_bytes(&mut buffer).unwrap();
|
tif.read_image_bytes(&mut buffer).unwrap();
|
||||||
|
|
||||||
// Mainly you can see: these are different and non-zero. Otherwise these magic constants just
|
// Mainly you can see: these are different and non-zero. Otherwise these magic constants just
|
||||||
|
|||||||
Reference in new issue
Block a user