Skip to content

Commit 5a3b113

Browse files
committed
Rewrite _to_buffer variants
We previously handed it a wrapper that was supposedly type-safe but really internally cast the buffer to bytes. That was rather pointless as the `_bytes` method could always be used instead. We replace the semantics by a utility which allocates an appropriate buffer with the internal limits, wrapping the exact sequence identified previously in the example as a pattern.
1 parent 5150e91 commit 5a3b113

File tree

2 files changed

+66
-29
lines changed

2 files changed

+66
-29
lines changed

examples/decode.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
1111
let mut reader = Decoder::new(io)?;
1212

1313
let mut data = DecodingResult::I8(vec![]);
14-
let limits = tiff::decoder::Limits::unlimited();
1514

1615
for i in 0u32.. {
17-
let layout = reader.image_buffer_layout()?;
1816
let colortype = reader.colortype()?;
1917
let dimensions = reader.dimensions()?;
20-
21-
data.resize_to(&layout, &limits)?;
22-
reader.read_image_bytes(data.as_buffer(0).as_bytes_mut())?;
18+
let layout = reader.read_image_to_buffer(&mut data)?;
2319

2420
debug_planes(i, &mut data, &layout, &colortype, dimensions);
2521

src/decoder/mod.rs

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,20 @@ impl DecodingResult {
6060
buffer: &BufferLayoutPreference,
6161
limits: &Limits,
6262
) -> Result<(), TiffError> {
63-
let extent = DecodingExtent::U8(buffer.complete_len);
63+
let sample_type = buffer.sample_type.ok_or(TiffError::UnsupportedError(
64+
TiffUnsupportedError::UnknownInterpretation,
65+
))?;
66+
67+
let extent = sample_type.extent_for_bytes(buffer.complete_len);
68+
self.resize_to_extent(extent, limits)
69+
}
70+
71+
fn resize_to_extent(
72+
&mut self,
73+
extent: DecodingExtent,
74+
limits: &Limits,
75+
) -> Result<(), TiffError> {
76+
// FIXME: we *can* reuse the allocation sometimes.
6477
*self = extent.to_result_buffer(limits)?;
6578
Ok(())
6679
}
@@ -1144,22 +1157,6 @@ impl<R: Read + Seek> Decoder<R> {
11441157
Ok(u32::try_from(self.image().chunk_offsets.len())?)
11451158
}
11461159

1147-
pub fn read_chunk_to_buffer(
1148-
&mut self,
1149-
mut buffer: DecodingBuffer,
1150-
chunk_index: u32,
1151-
output_width: usize,
1152-
) -> TiffResult<()> {
1153-
let (width, height) = self.image().chunk_data_dimensions(chunk_index)?;
1154-
1155-
let mut layout = self.image().readout_for_size(width, height)?;
1156-
layout.set_row_stride(output_width)?;
1157-
1158-
self.read_chunk_to_bytes(buffer.as_bytes_mut(), chunk_index, &layout)?;
1159-
1160-
Ok(())
1161-
}
1162-
11631160
fn read_chunk_to_bytes(
11641161
&mut self,
11651162
buffer: &mut [u8],
@@ -1276,6 +1273,32 @@ impl<R: Read + Seek> Decoder<R> {
12761273
Ok(())
12771274
}
12781275

1276+
/// Read the specified chunk (at index `chunk_index`) into a provide buffer.
1277+
///
1278+
/// It will re-allocate the buffer into the correct type and size, within the decoder's
1279+
/// configured limits, and then pass it to the underlying method. This is essentially a
1280+
/// type-safe wrapper around the raw [`Self::read_chunk_to_bytes`] method.
1281+
///
1282+
/// Note that for planar images each chunk contains only one sample of the underlying data.
1283+
pub fn read_chunk_to_buffer(
1284+
&mut self,
1285+
buffer: &mut DecodingResult,
1286+
chunk_index: u32,
1287+
output_width: usize,
1288+
) -> TiffResult<()> {
1289+
let (width, height) = self.image().chunk_data_dimensions(chunk_index)?;
1290+
1291+
let mut layout = self.image().readout_for_size(width, height)?;
1292+
layout.set_row_stride(output_width)?;
1293+
1294+
let extent = layout.result_extent_for_planes(0..1)?;
1295+
buffer.resize_to_extent(extent, &self.value_reader.limits)?;
1296+
1297+
self.read_chunk_to_bytes(buffer.as_buffer(0).as_bytes_mut(), chunk_index, &layout)?;
1298+
1299+
Ok(())
1300+
}
1301+
12791302
/// Read chunks corresponding to several planes of a region of pixels.
12801303
///
12811304
/// For non planar images this is equivalent to [`Self::read_chunk_bytes`] as there is only one
@@ -1388,29 +1411,47 @@ impl<R: Read + Seek> Decoder<R> {
13881411

13891412
/// Decodes the entire image into a provided buffer.
13901413
///
1391-
/// Returns a [`TiffError::UsageError`] if the chunk is smaller than the size indicated with a
1392-
/// call to [`Self::image_buffer_layout`]. Note that the alignment may be arbitrary, but an
1393-
/// alignment smaller than the preferred alignment may perform worse.
1414+
/// It will re-allocate the buffer into the correct type and size, within the decoder's
1415+
/// configured limits, and then pass it to the underlying method. This is essentially a
1416+
/// type-safe wrapper around the raw [`Self::read_image_bytes`] method.
13941417
///
13951418
/// # Examples
13961419
///
13971420
/// ```
13981421
/// use tiff::decoder::{Decoder, DecodingResult, Limits};
13991422
///
14001423
/// let mut result = DecodingResult::I8(vec![]);
1401-
/// let limits = Limits::unlimited();
14021424
///
14031425
/// let mut reader = /* */
14041426
/// # Decoder::new(std::io::Cursor::new(include_bytes!(concat!(
14051427
/// # env!("CARGO_MANIFEST_DIR"), "/tests/images/tiled-gray-i1.tif"
14061428
/// # )))).unwrap();
14071429
///
1408-
/// let layout = reader.image_buffer_layout()?;
1409-
/// result.resize_to(&layout, &limits)?;
1410-
/// reader.read_image_bytes(result.as_buffer(0).as_bytes_mut())?;
1430+
/// reader.read_image_to_buffer(&mut result)?;
14111431
///
14121432
/// # Ok::<_, tiff::TiffError>(())
14131433
/// ```
1434+
pub fn read_image_to_buffer(
1435+
&mut self,
1436+
result: &mut DecodingResult,
1437+
) -> TiffResult<BufferLayoutPreference> {
1438+
let readout = self.image().readout_for_image()?;
1439+
1440+
let planes = readout.to_plane_layout()?;
1441+
let layout = BufferLayoutPreference::from_planes(&planes);
1442+
1443+
let extent = readout.result_extent_for_planes(0..1)?;
1444+
result.resize_to_extent(extent, &self.value_reader.limits)?;
1445+
self.read_image_bytes(result.as_buffer(0).as_bytes_mut())?;
1446+
1447+
Ok(layout)
1448+
}
1449+
1450+
/// Decodes the entire image into a provided buffer.
1451+
///
1452+
/// Returns a [`TiffError::UsageError`] if the chunk is smaller than the size indicated with a
1453+
/// call to [`Self::image_buffer_layout`]. Note that the alignment may be arbitrary, but an
1454+
/// alignment smaller than the preferred alignment may perform worse.
14141455
///
14151456
/// # Error
14161457
///

0 commit comments

Comments
 (0)