Add Decoder::read_image_bytes, borrowed output
This commit is contained in:
1 parent
cc75d051af
commit
c746653269
2 files changed
+120
-27
No files matched your search
+117
-27
@@ -1,3 +1,4 @@
|
|||||||
|
use std::alloc::{Layout, LayoutError};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::io::{self, Read, Seek};
|
use std::io::{self, Read, Seek};
|
||||||
|
|
||||||
@@ -197,6 +198,61 @@ impl<'a> DecodingBuffer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The count and matching discriminant for a `DecodingBuffer`.
|
||||||
|
#[derive(Clone)]
|
||||||
|
enum DecodingExtent {
|
||||||
|
U8(usize),
|
||||||
|
U16(usize),
|
||||||
|
U32(usize),
|
||||||
|
U64(usize),
|
||||||
|
F16(usize),
|
||||||
|
F32(usize),
|
||||||
|
F64(usize),
|
||||||
|
I8(usize),
|
||||||
|
I16(usize),
|
||||||
|
I32(usize),
|
||||||
|
I64(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DecodingExtent {
|
||||||
|
fn to_result_buffer(&self, limits: &Limits) -> TiffResult<DecodingResult> {
|
||||||
|
match *self {
|
||||||
|
DecodingExtent::U8(count) => DecodingResult::new_u8(count, limits),
|
||||||
|
DecodingExtent::U16(count) => DecodingResult::new_u16(count, limits),
|
||||||
|
DecodingExtent::U32(count) => DecodingResult::new_u32(count, limits),
|
||||||
|
DecodingExtent::U64(count) => DecodingResult::new_u64(count, limits),
|
||||||
|
DecodingExtent::F16(count) => DecodingResult::new_f16(count, limits),
|
||||||
|
DecodingExtent::F32(count) => DecodingResult::new_f32(count, limits),
|
||||||
|
DecodingExtent::F64(count) => DecodingResult::new_f64(count, limits),
|
||||||
|
DecodingExtent::I8(count) => DecodingResult::new_i8(count, limits),
|
||||||
|
DecodingExtent::I16(count) => DecodingResult::new_i16(count, limits),
|
||||||
|
DecodingExtent::I32(count) => DecodingResult::new_i32(count, limits),
|
||||||
|
DecodingExtent::I64(count) => DecodingResult::new_i64(count, limits),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn preferred_layout(self) -> TiffResult<Layout> {
|
||||||
|
fn overflow(_: LayoutError) -> TiffError {
|
||||||
|
TiffError::LimitsExceeded
|
||||||
|
}
|
||||||
|
|
||||||
|
match self {
|
||||||
|
DecodingExtent::U8(count) => Layout::array::<u8>(count),
|
||||||
|
DecodingExtent::U16(count) => Layout::array::<u16>(count),
|
||||||
|
DecodingExtent::U32(count) => Layout::array::<u32>(count),
|
||||||
|
DecodingExtent::U64(count) => Layout::array::<u64>(count),
|
||||||
|
DecodingExtent::F16(count) => Layout::array::<f16>(count),
|
||||||
|
DecodingExtent::F32(count) => Layout::array::<f32>(count),
|
||||||
|
DecodingExtent::F64(count) => Layout::array::<f64>(count),
|
||||||
|
DecodingExtent::I8(count) => Layout::array::<i8>(count),
|
||||||
|
DecodingExtent::I16(count) => Layout::array::<i16>(count),
|
||||||
|
DecodingExtent::I32(count) => Layout::array::<i32>(count),
|
||||||
|
DecodingExtent::I64(count) => Layout::array::<i64>(count),
|
||||||
|
}
|
||||||
|
.map_err(overflow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
/// Chunk type of the internal representation
|
/// Chunk type of the internal representation
|
||||||
pub enum ChunkType {
|
pub enum ChunkType {
|
||||||
@@ -856,6 +912,11 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn result_buffer(&self, width: usize, height: usize) -> TiffResult<DecodingResult> {
|
fn result_buffer(&self, width: usize, height: usize) -> TiffResult<DecodingResult> {
|
||||||
|
self.result_extent(width, height)?
|
||||||
|
.to_result_buffer(&self.value_reader.limits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn result_extent(&self, width: usize, height: usize) -> TiffResult<DecodingExtent> {
|
||||||
let bits_per_sample = self.image().bits_per_sample;
|
let bits_per_sample = self.image().bits_per_sample;
|
||||||
|
|
||||||
let row_samples = if bits_per_sample >= 8 {
|
let row_samples = if bits_per_sample >= 8 {
|
||||||
@@ -872,37 +933,44 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
.ok_or(TiffError::LimitsExceeded)?;
|
.ok_or(TiffError::LimitsExceeded)?;
|
||||||
|
|
||||||
let max_sample_bits = self.image().bits_per_sample;
|
let max_sample_bits = self.image().bits_per_sample;
|
||||||
let limits = &self.value_reader.limits;
|
|
||||||
|
|
||||||
match self.image().sample_format {
|
Ok(match self.image().sample_format {
|
||||||
SampleFormat::Uint => match max_sample_bits {
|
SampleFormat::Uint => match max_sample_bits {
|
||||||
n if n <= 8 => DecodingResult::new_u8(buffer_size, limits),
|
n if n <= 8 => DecodingExtent::U8(buffer_size),
|
||||||
n if n <= 16 => DecodingResult::new_u16(buffer_size, limits),
|
n if n <= 16 => DecodingExtent::U16(buffer_size),
|
||||||
n if n <= 32 => DecodingResult::new_u32(buffer_size, limits),
|
n if n <= 32 => DecodingExtent::U32(buffer_size),
|
||||||
n if n <= 64 => DecodingResult::new_u64(buffer_size, limits),
|
n if n <= 64 => DecodingExtent::U64(buffer_size),
|
||||||
n => Err(TiffError::UnsupportedError(
|
n => {
|
||||||
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
return Err(TiffError::UnsupportedError(
|
||||||
)),
|
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
||||||
|
))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SampleFormat::IEEEFP => match max_sample_bits {
|
SampleFormat::IEEEFP => match max_sample_bits {
|
||||||
16 => DecodingResult::new_f16(buffer_size, limits),
|
16 => DecodingExtent::F16(buffer_size),
|
||||||
32 => DecodingResult::new_f32(buffer_size, limits),
|
32 => DecodingExtent::F32(buffer_size),
|
||||||
64 => DecodingResult::new_f64(buffer_size, limits),
|
64 => DecodingExtent::F64(buffer_size),
|
||||||
n => Err(TiffError::UnsupportedError(
|
n => {
|
||||||
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
return Err(TiffError::UnsupportedError(
|
||||||
)),
|
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
||||||
|
))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
SampleFormat::Int => match max_sample_bits {
|
SampleFormat::Int => match max_sample_bits {
|
||||||
n if n <= 8 => DecodingResult::new_i8(buffer_size, limits),
|
n if n <= 8 => DecodingExtent::I8(buffer_size),
|
||||||
n if n <= 16 => DecodingResult::new_i16(buffer_size, limits),
|
n if n <= 16 => DecodingExtent::I16(buffer_size),
|
||||||
n if n <= 32 => DecodingResult::new_i32(buffer_size, limits),
|
n if n <= 32 => DecodingExtent::I32(buffer_size),
|
||||||
n if n <= 64 => DecodingResult::new_i64(buffer_size, limits),
|
n if n <= 64 => DecodingExtent::I64(buffer_size),
|
||||||
n => Err(TiffError::UnsupportedError(
|
n => {
|
||||||
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
return Err(TiffError::UnsupportedError(
|
||||||
)),
|
TiffUnsupportedError::UnsupportedBitsPerChannel(n),
|
||||||
|
))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
format => Err(TiffUnsupportedError::UnsupportedSampleFormat(vec![format]).into()),
|
format => {
|
||||||
}
|
return Err(TiffUnsupportedError::UnsupportedSampleFormat(vec![format]).into())
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the specified chunk (at index `chunk_index`) and return the binary data as a Vector.
|
/// Read the specified chunk (at index `chunk_index`) and return the binary data as a Vector.
|
||||||
@@ -934,9 +1002,31 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
|
pub fn read_image(&mut self) -> TiffResult<DecodingResult> {
|
||||||
let width = self.image().width;
|
let width = self.image().width;
|
||||||
let height = self.image().height;
|
let height = self.image().height;
|
||||||
|
|
||||||
let mut result = self.result_buffer(width as usize, height as usize)?;
|
let mut result = self.result_buffer(width as usize, height as usize)?;
|
||||||
|
self.read_image_bytes(result.as_buffer(0).as_bytes_mut())?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_image_bytes(&mut self, buffer: &mut [u8]) -> TiffResult<()> {
|
||||||
|
let width = self.image().width;
|
||||||
|
let height = self.image().height;
|
||||||
|
|
||||||
|
let extent = self.result_extent(width as usize, height as usize)?;
|
||||||
|
let needed_bytes = extent.preferred_layout()?.size();
|
||||||
|
|
||||||
|
if buffer.len() < needed_bytes {
|
||||||
|
return Err(TiffError::UsageError(
|
||||||
|
UsageError::InsufficientOutputBufferSize {
|
||||||
|
needed: needed_bytes,
|
||||||
|
provided: buffer.len(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if width == 0 || height == 0 {
|
if width == 0 || height == 0 {
|
||||||
return Ok(result);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk_dimensions = self.image().chunk_dimensions()?;
|
let chunk_dimensions = self.image().chunk_dimensions()?;
|
||||||
@@ -989,13 +1079,13 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
y * output_row_stride * chunk_dimensions.1 as usize + x * chunk_row_bytes;
|
y * output_row_stride * chunk_dimensions.1 as usize + x * chunk_row_bytes;
|
||||||
self.image.expand_chunk(
|
self.image.expand_chunk(
|
||||||
&mut self.value_reader,
|
&mut self.value_reader,
|
||||||
&mut result.as_buffer(0).as_bytes_mut()[buffer_offset..],
|
&mut buffer[buffer_offset..],
|
||||||
output_row_stride,
|
output_row_stride,
|
||||||
chunk as u32,
|
chunk as u32,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the IFD decoder for our current image IFD.
|
/// Get the IFD decoder for our current image IFD.
|
||||||
|
|||||||
@@ -184,6 +184,9 @@ quick_error! {
|
|||||||
PredictorUnavailable {
|
PredictorUnavailable {
|
||||||
display("the requested predictor is not available")
|
display("the requested predictor is not available")
|
||||||
}
|
}
|
||||||
|
InsufficientOutputBufferSize { needed: usize, provided: usize } {
|
||||||
|
display("the borrowed output buffer is not large enough for the decoded data, needed {needed} but have {provided}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user