Merge pull request #370 from image-rs/restructure-buffer

Restructure decoding's Buffer
This commit is contained in:
Aurelia Molzer authored and GitHub committed 2026-03-27 19:48:46 +00:00
commit 8e315c6a00
12 files changed
+411 -393

No files matched your search

+23 -21
View File
@@ -1,4 +1,4 @@
use tiff::decoder::{BufferLayoutPreference, Decoder, DecodingBuffer, DecodingResult}; use tiff::decoder::{BufferLayoutPreference, Decoder, DecodingSampleBuffer, DecodingSampleSlice};
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let Some(image) = std::env::args_os().nth(1) else { let Some(image) = std::env::args_os().nth(1) else {
@@ -10,7 +10,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let io = std::io::BufReader::new(file); let io = std::io::BufReader::new(file);
let mut reader = Decoder::open(io)?; let mut reader = Decoder::open(io)?;
let mut data = DecodingResult::I8(vec![]); let mut data = DecodingSampleBuffer::I8(vec![]);
for i in 0u32.. { for i in 0u32.. {
let colortype = reader.colortype()?; let colortype = reader.colortype()?;
@@ -31,32 +31,32 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
fn debug_planes( fn debug_planes(
index: u32, index: u32,
data: &mut DecodingResult, data: &mut DecodingSampleBuffer,
layout: &BufferLayoutPreference, layout: &BufferLayoutPreference,
colortype: &tiff::ColorType, colortype: &tiff::ColorType,
(width, height): (u32, u32), (width, height): (u32, u32),
) { ) {
match data { match data {
DecodingResult::F16(v) => { DecodingSampleBuffer::F16(v) => {
let samples = v let samples = v
.iter() .iter()
.map(|&f| (f64::from(f) * f64::from(u16::MAX)) as u16) .map(|&f| (f64::from(f) * f64::from(u16::MAX)) as u16)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
*data = DecodingResult::U16(samples); *data = DecodingSampleBuffer::U16(samples);
} }
DecodingResult::F32(v) => { DecodingSampleBuffer::F32(v) => {
let samples = v let samples = v
.iter() .iter()
.map(|&f| (f64::from(f) * f64::from(u16::MAX)) as u16) .map(|&f| (f64::from(f) * f64::from(u16::MAX)) as u16)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
*data = DecodingResult::U16(samples); *data = DecodingSampleBuffer::U16(samples);
} }
DecodingResult::F64(v) => { DecodingSampleBuffer::F64(v) => {
let samples = v let samples = v
.iter() .iter()
.map(|&f| (f * f64::from(u16::MAX)) as u16) .map(|&f| (f * f64::from(u16::MAX)) as u16)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
*data = DecodingResult::U16(samples); *data = DecodingSampleBuffer::U16(samples);
} }
_ => {} _ => {}
} }
@@ -98,24 +98,24 @@ fn debug_planes(
// them here (e.g. represent 1-bit as `{0, 1}`) but we'd also set `maxval` accordingly and // them here (e.g. represent 1-bit as `{0, 1}`) but we'd also set `maxval` accordingly and
// this requires tupltype to be `BLACKANDWHITE` so introducing a bunch of complexity. If // this requires tupltype to be `BLACKANDWHITE` so introducing a bunch of complexity. If
// you want to do that in your real code, go ahead. // you want to do that in your real code, go ahead.
DecodingBuffer::U8(buf) => match colortype.bit_depth() { DecodingSampleSlice::U8(buf) => match colortype.bit_depth() {
8 => u64::from(u8::MAX), 8 => u64::from(u8::MAX),
4 => { 4 => {
fallback_buffer = vec![0; (swidth * sheight) as usize]; fallback_buffer = vec![0; (swidth * sheight) as usize];
expand_4bit(buf, swidth, &mut fallback_buffer); expand_4bit(buf, swidth, &mut fallback_buffer);
*data = DecodingResult::U8(fallback_buffer); *data = DecodingSampleBuffer::U8(fallback_buffer);
u64::from(u8::MAX) u64::from(u8::MAX)
} }
2 => { 2 => {
fallback_buffer = vec![0; (swidth * sheight) as usize]; fallback_buffer = vec![0; (swidth * sheight) as usize];
expand_2bit(buf, swidth, &mut fallback_buffer); expand_2bit(buf, swidth, &mut fallback_buffer);
*data = DecodingResult::U8(fallback_buffer); *data = DecodingSampleBuffer::U8(fallback_buffer);
u64::from(u8::MAX) u64::from(u8::MAX)
} }
1 => { 1 => {
fallback_buffer = vec![0; (swidth * sheight) as usize]; fallback_buffer = vec![0; (swidth * sheight) as usize];
expand_1bit(buf, swidth, &mut fallback_buffer); expand_1bit(buf, swidth, &mut fallback_buffer);
*data = DecodingResult::U8(fallback_buffer); *data = DecodingSampleBuffer::U8(fallback_buffer);
u64::from(u8::MAX) u64::from(u8::MAX)
} }
_ => { _ => {
@@ -126,28 +126,30 @@ fn debug_planes(
return; return;
} }
}, },
DecodingBuffer::U16(_) => u64::from(u16::MAX), DecodingSampleSlice::U16(_) => u64::from(u16::MAX),
DecodingBuffer::U32(_) => u64::from(u32::MAX), DecodingSampleSlice::U32(_) => u64::from(u32::MAX),
DecodingBuffer::U64(_) => u64::MAX, DecodingSampleSlice::U64(_) => u64::MAX,
// Eh, this is a good effort I guess. // Eh, this is a good effort I guess.
DecodingBuffer::I8(items) => { DecodingSampleSlice::I8(items) => {
items.iter_mut().for_each(|v| *v = 0.max(*v)); items.iter_mut().for_each(|v| *v = 0.max(*v));
u64::from(i8::MAX as u8) u64::from(i8::MAX as u8)
} }
DecodingBuffer::I16(items) => { DecodingSampleSlice::I16(items) => {
items.iter_mut().for_each(|v| *v = 0.max(*v)); items.iter_mut().for_each(|v| *v = 0.max(*v));
u64::from(i16::MAX as u16) u64::from(i16::MAX as u16)
} }
DecodingBuffer::I32(items) => { DecodingSampleSlice::I32(items) => {
items.iter_mut().for_each(|v| *v = 0.max(*v)); items.iter_mut().for_each(|v| *v = 0.max(*v));
u64::from(i32::MAX as u32) u64::from(i32::MAX as u32)
} }
DecodingBuffer::I64(items) => { DecodingSampleSlice::I64(items) => {
items.iter_mut().for_each(|v| *v = 0.max(*v)); items.iter_mut().for_each(|v| *v = 0.max(*v));
i64::MAX as u64 i64::MAX as u64
} }
// Not supported by PAM. // Not supported by PAM.
DecodingBuffer::F16(_) | DecodingBuffer::F32(_) | DecodingBuffer::F64(_) => return, DecodingSampleSlice::F16(_) | DecodingSampleSlice::F32(_) | DecodingSampleSlice::F64(_) => {
return
}
}; };
let byte_len = if layout.planes > 1 { let byte_len = if layout.planes > 1 {
+302
View File
@@ -0,0 +1,302 @@
use half::f16;
use std::alloc::{Layout, LayoutError};
use crate::{
bytecast,
decoder::{BufferLayoutPreference, Limits},
error::{TiffError, TiffResult, TiffUnsupportedError},
};
/// Result of a decoding process
#[derive(Debug)]
pub enum DecodingSampleBuffer {
/// A vector of unsigned bytes
U8(Vec<u8>),
/// A vector of unsigned words
U16(Vec<u16>),
/// A vector of 32 bit unsigned ints
U32(Vec<u32>),
/// A vector of 64 bit unsigned ints
U64(Vec<u64>),
/// A vector of 16 bit IEEE floats (held in u16)
F16(Vec<f16>),
/// A vector of 32 bit IEEE floats
F32(Vec<f32>),
/// A vector of 64 bit IEEE floats
F64(Vec<f64>),
/// A vector of 8 bit signed ints
I8(Vec<i8>),
/// A vector of 16 bit signed ints
I16(Vec<i16>),
/// A vector of 32 bit signed ints
I32(Vec<i32>),
/// A vector of 64 bit signed ints
I64(Vec<i64>),
}
impl DecodingSampleBuffer {
/// Reallocate the buffer to decode all planes of the indicated layout.
pub fn resize_to(
&mut self,
buffer: &BufferLayoutPreference,
limits: &Limits,
) -> Result<(), TiffError> {
let sample_type = buffer.sample_type.ok_or(TiffError::UnsupportedError(
TiffUnsupportedError::UnknownInterpretation,
))?;
let extent = sample_type.extent_for_bytes(buffer.complete_len);
self.resize_to_extent(extent, limits)
}
pub(crate) fn resize_to_extent(
&mut self,
extent: DecodingExtent,
limits: &Limits,
) -> Result<(), TiffError> {
// FIXME: we *can* reuse the allocation sometimes.
*self = extent.to_result_buffer(limits)?;
Ok(())
}
fn new<T: Default + Copy>(
size: usize,
limits: &Limits,
from_fn: fn(Vec<T>) -> Self,
) -> TiffResult<DecodingSampleBuffer> {
if size > limits.decoding_buffer_size / core::mem::size_of::<T>() {
Err(TiffError::LimitsExceeded)
} else {
Ok(from_fn(vec![T::default(); size]))
}
}
fn new_u8(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::U8)
}
fn new_u16(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::U16)
}
fn new_u32(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::U32)
}
fn new_u64(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::U64)
}
fn new_f32(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::F32)
}
fn new_f64(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::F64)
}
fn new_f16(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::F16)
}
fn new_i8(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::I8)
}
fn new_i16(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::I16)
}
fn new_i32(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::I32)
}
fn new_i64(size: usize, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
Self::new(size, limits, DecodingSampleBuffer::I64)
}
/// Get a view of this buffer starting from the nth _sample_ of the current type.
pub fn as_buffer(&mut self, start: usize) -> DecodingSampleSlice<'_> {
match *self {
DecodingSampleBuffer::U8(ref mut buf) => DecodingSampleSlice::U8(&mut buf[start..]),
DecodingSampleBuffer::U16(ref mut buf) => DecodingSampleSlice::U16(&mut buf[start..]),
DecodingSampleBuffer::U32(ref mut buf) => DecodingSampleSlice::U32(&mut buf[start..]),
DecodingSampleBuffer::U64(ref mut buf) => DecodingSampleSlice::U64(&mut buf[start..]),
DecodingSampleBuffer::F16(ref mut buf) => DecodingSampleSlice::F16(&mut buf[start..]),
DecodingSampleBuffer::F32(ref mut buf) => DecodingSampleSlice::F32(&mut buf[start..]),
DecodingSampleBuffer::F64(ref mut buf) => DecodingSampleSlice::F64(&mut buf[start..]),
DecodingSampleBuffer::I8(ref mut buf) => DecodingSampleSlice::I8(&mut buf[start..]),
DecodingSampleBuffer::I16(ref mut buf) => DecodingSampleSlice::I16(&mut buf[start..]),
DecodingSampleBuffer::I32(ref mut buf) => DecodingSampleSlice::I32(&mut buf[start..]),
DecodingSampleBuffer::I64(ref mut buf) => DecodingSampleSlice::I64(&mut buf[start..]),
}
}
}
// A buffer for image decoding
pub enum DecodingSampleSlice<'a> {
/// A slice of unsigned bytes
U8(&'a mut [u8]),
/// A slice of unsigned words
U16(&'a mut [u16]),
/// A slice of 32 bit unsigned ints
U32(&'a mut [u32]),
/// A slice of 64 bit unsigned ints
U64(&'a mut [u64]),
/// A slice of 16 bit IEEE floats
F16(&'a mut [f16]),
/// A slice of 32 bit IEEE floats
F32(&'a mut [f32]),
/// A slice of 64 bit IEEE floats
F64(&'a mut [f64]),
/// A slice of 8 bits signed ints
I8(&'a mut [i8]),
/// A slice of 16 bits signed ints
I16(&'a mut [i16]),
/// A slice of 32 bits signed ints
I32(&'a mut [i32]),
/// A slice of 64 bits signed ints
I64(&'a mut [i64]),
}
impl<'a> DecodingSampleSlice<'a> {
pub fn as_bytes(&self) -> &[u8] {
match self {
DecodingSampleSlice::U8(buf) => buf,
DecodingSampleSlice::I8(buf) => bytecast::i8_as_ne_bytes(buf),
DecodingSampleSlice::U16(buf) => bytecast::u16_as_ne_bytes(buf),
DecodingSampleSlice::I16(buf) => bytecast::i16_as_ne_bytes(buf),
DecodingSampleSlice::U32(buf) => bytecast::u32_as_ne_bytes(buf),
DecodingSampleSlice::I32(buf) => bytecast::i32_as_ne_bytes(buf),
DecodingSampleSlice::U64(buf) => bytecast::u64_as_ne_bytes(buf),
DecodingSampleSlice::I64(buf) => bytecast::i64_as_ne_bytes(buf),
DecodingSampleSlice::F16(buf) => bytecast::f16_as_ne_bytes(buf),
DecodingSampleSlice::F32(buf) => bytecast::f32_as_ne_bytes(buf),
DecodingSampleSlice::F64(buf) => bytecast::f64_as_ne_bytes(buf),
}
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
match self {
DecodingSampleSlice::U8(buf) => buf,
DecodingSampleSlice::I8(buf) => bytecast::i8_as_ne_mut_bytes(buf),
DecodingSampleSlice::U16(buf) => bytecast::u16_as_ne_mut_bytes(buf),
DecodingSampleSlice::I16(buf) => bytecast::i16_as_ne_mut_bytes(buf),
DecodingSampleSlice::U32(buf) => bytecast::u32_as_ne_mut_bytes(buf),
DecodingSampleSlice::I32(buf) => bytecast::i32_as_ne_mut_bytes(buf),
DecodingSampleSlice::U64(buf) => bytecast::u64_as_ne_mut_bytes(buf),
DecodingSampleSlice::I64(buf) => bytecast::i64_as_ne_mut_bytes(buf),
DecodingSampleSlice::F16(buf) => bytecast::f16_as_ne_mut_bytes(buf),
DecodingSampleSlice::F32(buf) => bytecast::f32_as_ne_mut_bytes(buf),
DecodingSampleSlice::F64(buf) => bytecast::f64_as_ne_mut_bytes(buf),
}
}
pub fn byte_len(&self) -> usize {
self.as_bytes().len()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DecodingSampleType {
U8,
U16,
U32,
U64,
F16,
F32,
F64,
I8,
I16,
I32,
I64,
}
impl DecodingSampleType {
pub(crate) fn extent_for_bytes(self, bytes: usize) -> DecodingExtent {
match self {
DecodingSampleType::U8 => DecodingExtent::U8(bytes),
DecodingSampleType::U16 => DecodingExtent::U16(bytes.div_ceil(2)),
DecodingSampleType::U32 => DecodingExtent::U32(bytes.div_ceil(4)),
DecodingSampleType::U64 => DecodingExtent::U64(bytes.div_ceil(8)),
DecodingSampleType::I8 => DecodingExtent::I8(bytes),
DecodingSampleType::I16 => DecodingExtent::I16(bytes.div_ceil(2)),
DecodingSampleType::I32 => DecodingExtent::I32(bytes.div_ceil(4)),
DecodingSampleType::I64 => DecodingExtent::I64(bytes.div_ceil(8)),
DecodingSampleType::F16 => DecodingExtent::F16(bytes.div_ceil(2)),
DecodingSampleType::F32 => DecodingExtent::F32(bytes.div_ceil(4)),
DecodingSampleType::F64 => DecodingExtent::F64(bytes.div_ceil(8)),
}
}
}
/// The count and matching discriminant for a `DecodingBuffer`.
#[derive(Clone)]
pub(crate) 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 {
pub(crate) fn to_result_buffer(&self, limits: &Limits) -> TiffResult<DecodingSampleBuffer> {
match *self {
DecodingExtent::U8(count) => DecodingSampleBuffer::new_u8(count, limits),
DecodingExtent::U16(count) => DecodingSampleBuffer::new_u16(count, limits),
DecodingExtent::U32(count) => DecodingSampleBuffer::new_u32(count, limits),
DecodingExtent::U64(count) => DecodingSampleBuffer::new_u64(count, limits),
DecodingExtent::F16(count) => DecodingSampleBuffer::new_f16(count, limits),
DecodingExtent::F32(count) => DecodingSampleBuffer::new_f32(count, limits),
DecodingExtent::F64(count) => DecodingSampleBuffer::new_f64(count, limits),
DecodingExtent::I8(count) => DecodingSampleBuffer::new_i8(count, limits),
DecodingExtent::I16(count) => DecodingSampleBuffer::new_i16(count, limits),
DecodingExtent::I32(count) => DecodingSampleBuffer::new_i32(count, limits),
DecodingExtent::I64(count) => DecodingSampleBuffer::new_i64(count, limits),
}
}
pub(crate) 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)
}
pub(crate) fn sample_type(&self) -> DecodingSampleType {
match *self {
DecodingExtent::U8(_) => DecodingSampleType::U8,
DecodingExtent::U16(_) => DecodingSampleType::U16,
DecodingExtent::U32(_) => DecodingSampleType::U32,
DecodingExtent::U64(_) => DecodingSampleType::U64,
DecodingExtent::F16(_) => DecodingSampleType::F16,
DecodingExtent::F32(_) => DecodingSampleType::F32,
DecodingExtent::F64(_) => DecodingSampleType::F64,
DecodingExtent::I8(_) => DecodingSampleType::I8,
DecodingExtent::I16(_) => DecodingSampleType::I16,
DecodingExtent::I32(_) => DecodingSampleType::I32,
DecodingExtent::I64(_) => DecodingSampleType::I64,
}
}
}
+16 -302
View File
@@ -1,4 +1,3 @@
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};
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
@@ -8,14 +7,13 @@ use crate::tags::{
ValueBuffer, ValueBuffer,
}; };
use crate::{ use crate::{
bytecast, ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, ColorType, Directory, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError,
UsageError,
}; };
use half::f16;
use self::image::Image; use self::image::Image;
use self::stream::EndianReader; use self::stream::EndianReader;
mod buffer;
mod cycles; mod cycles;
pub mod ifd; pub mod ifd;
mod image; mod image;
@@ -23,233 +21,20 @@ mod logluv;
mod stream; mod stream;
mod tag_reader; mod tag_reader;
pub use self::buffer::{DecodingSampleBuffer, DecodingSampleSlice, DecodingSampleType};
#[deprecated = "Renamed to `DecodingSampleBuffer`"]
pub type DecodingResult = DecodingSampleBuffer;
#[deprecated = "Renamed to `DecodingSampleSlice`"]
pub type DecodingBuffer<'a> = DecodingSampleSlice<'a>;
use self::buffer::DecodingExtent;
/// An index referring to a (rectangular) region of an image. /// An index referring to a (rectangular) region of an image.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TiffCodingUnit(pub u32); pub struct TiffCodingUnit(pub u32);
/// Result of a decoding process
#[derive(Debug)]
pub enum DecodingResult {
/// A vector of unsigned bytes
U8(Vec<u8>),
/// A vector of unsigned words
U16(Vec<u16>),
/// A vector of 32 bit unsigned ints
U32(Vec<u32>),
/// A vector of 64 bit unsigned ints
U64(Vec<u64>),
/// A vector of 16 bit IEEE floats (held in u16)
F16(Vec<f16>),
/// A vector of 32 bit IEEE floats
F32(Vec<f32>),
/// A vector of 64 bit IEEE floats
F64(Vec<f64>),
/// A vector of 8 bit signed ints
I8(Vec<i8>),
/// A vector of 16 bit signed ints
I16(Vec<i16>),
/// A vector of 32 bit signed ints
I32(Vec<i32>),
/// A vector of 64 bit signed ints
I64(Vec<i64>),
}
impl DecodingResult {
/// Reallocate the buffer to decode all planes of the indicated layout.
pub fn resize_to(
&mut self,
buffer: &BufferLayoutPreference,
limits: &Limits,
) -> Result<(), TiffError> {
let sample_type = buffer.sample_type.ok_or(TiffError::UnsupportedError(
TiffUnsupportedError::UnknownInterpretation,
))?;
let extent = sample_type.extent_for_bytes(buffer.complete_len);
self.resize_to_extent(extent, limits)
}
fn resize_to_extent(
&mut self,
extent: DecodingExtent,
limits: &Limits,
) -> Result<(), TiffError> {
// FIXME: we *can* reuse the allocation sometimes.
*self = extent.to_result_buffer(limits)?;
Ok(())
}
fn new<T: Default + Copy>(
size: usize,
limits: &Limits,
from_fn: fn(Vec<T>) -> Self,
) -> TiffResult<DecodingResult> {
if size > limits.decoding_buffer_size / core::mem::size_of::<T>() {
Err(TiffError::LimitsExceeded)
} else {
Ok(from_fn(vec![T::default(); size]))
}
}
fn new_u8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::U8)
}
fn new_u16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::U16)
}
fn new_u32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::U32)
}
fn new_u64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::U64)
}
fn new_f32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::F32)
}
fn new_f64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::F64)
}
fn new_f16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::F16)
}
fn new_i8(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::I8)
}
fn new_i16(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::I16)
}
fn new_i32(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::I32)
}
fn new_i64(size: usize, limits: &Limits) -> TiffResult<DecodingResult> {
Self::new(size, limits, DecodingResult::I64)
}
/// Get a view of this buffer starting from the nth _sample_ of the current type.
pub fn as_buffer(&mut self, start: usize) -> DecodingBuffer<'_> {
match *self {
DecodingResult::U8(ref mut buf) => DecodingBuffer::U8(&mut buf[start..]),
DecodingResult::U16(ref mut buf) => DecodingBuffer::U16(&mut buf[start..]),
DecodingResult::U32(ref mut buf) => DecodingBuffer::U32(&mut buf[start..]),
DecodingResult::U64(ref mut buf) => DecodingBuffer::U64(&mut buf[start..]),
DecodingResult::F16(ref mut buf) => DecodingBuffer::F16(&mut buf[start..]),
DecodingResult::F32(ref mut buf) => DecodingBuffer::F32(&mut buf[start..]),
DecodingResult::F64(ref mut buf) => DecodingBuffer::F64(&mut buf[start..]),
DecodingResult::I8(ref mut buf) => DecodingBuffer::I8(&mut buf[start..]),
DecodingResult::I16(ref mut buf) => DecodingBuffer::I16(&mut buf[start..]),
DecodingResult::I32(ref mut buf) => DecodingBuffer::I32(&mut buf[start..]),
DecodingResult::I64(ref mut buf) => DecodingBuffer::I64(&mut buf[start..]),
}
}
}
// A buffer for image decoding
pub enum DecodingBuffer<'a> {
/// A slice of unsigned bytes
U8(&'a mut [u8]),
/// A slice of unsigned words
U16(&'a mut [u16]),
/// A slice of 32 bit unsigned ints
U32(&'a mut [u32]),
/// A slice of 64 bit unsigned ints
U64(&'a mut [u64]),
/// A slice of 16 bit IEEE floats
F16(&'a mut [f16]),
/// A slice of 32 bit IEEE floats
F32(&'a mut [f32]),
/// A slice of 64 bit IEEE floats
F64(&'a mut [f64]),
/// A slice of 8 bits signed ints
I8(&'a mut [i8]),
/// A slice of 16 bits signed ints
I16(&'a mut [i16]),
/// A slice of 32 bits signed ints
I32(&'a mut [i32]),
/// A slice of 64 bits signed ints
I64(&'a mut [i64]),
}
impl<'a> DecodingBuffer<'a> {
pub fn as_bytes(&self) -> &[u8] {
match self {
DecodingBuffer::U8(buf) => buf,
DecodingBuffer::I8(buf) => bytecast::i8_as_ne_bytes(buf),
DecodingBuffer::U16(buf) => bytecast::u16_as_ne_bytes(buf),
DecodingBuffer::I16(buf) => bytecast::i16_as_ne_bytes(buf),
DecodingBuffer::U32(buf) => bytecast::u32_as_ne_bytes(buf),
DecodingBuffer::I32(buf) => bytecast::i32_as_ne_bytes(buf),
DecodingBuffer::U64(buf) => bytecast::u64_as_ne_bytes(buf),
DecodingBuffer::I64(buf) => bytecast::i64_as_ne_bytes(buf),
DecodingBuffer::F16(buf) => bytecast::f16_as_ne_bytes(buf),
DecodingBuffer::F32(buf) => bytecast::f32_as_ne_bytes(buf),
DecodingBuffer::F64(buf) => bytecast::f64_as_ne_bytes(buf),
}
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
match self {
DecodingBuffer::U8(buf) => buf,
DecodingBuffer::I8(buf) => bytecast::i8_as_ne_mut_bytes(buf),
DecodingBuffer::U16(buf) => bytecast::u16_as_ne_mut_bytes(buf),
DecodingBuffer::I16(buf) => bytecast::i16_as_ne_mut_bytes(buf),
DecodingBuffer::U32(buf) => bytecast::u32_as_ne_mut_bytes(buf),
DecodingBuffer::I32(buf) => bytecast::i32_as_ne_mut_bytes(buf),
DecodingBuffer::U64(buf) => bytecast::u64_as_ne_mut_bytes(buf),
DecodingBuffer::I64(buf) => bytecast::i64_as_ne_mut_bytes(buf),
DecodingBuffer::F16(buf) => bytecast::f16_as_ne_mut_bytes(buf),
DecodingBuffer::F32(buf) => bytecast::f32_as_ne_mut_bytes(buf),
DecodingBuffer::F64(buf) => bytecast::f64_as_ne_mut_bytes(buf),
}
}
pub fn byte_len(&self) -> usize {
self.as_bytes().len()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DecodingSampleType {
U8,
U16,
U32,
U64,
F16,
F32,
F64,
I8,
I16,
I32,
I64,
}
impl DecodingSampleType {
fn extent_for_bytes(self, bytes: usize) -> DecodingExtent {
match self {
DecodingSampleType::U8 => DecodingExtent::U8(bytes),
DecodingSampleType::U16 => DecodingExtent::U16(bytes.div_ceil(2)),
DecodingSampleType::U32 => DecodingExtent::U32(bytes.div_ceil(4)),
DecodingSampleType::U64 => DecodingExtent::U64(bytes.div_ceil(8)),
DecodingSampleType::I8 => DecodingExtent::I8(bytes),
DecodingSampleType::I16 => DecodingExtent::I16(bytes.div_ceil(2)),
DecodingSampleType::I32 => DecodingExtent::I32(bytes.div_ceil(4)),
DecodingSampleType::I64 => DecodingExtent::I64(bytes.div_ceil(8)),
DecodingSampleType::F16 => DecodingExtent::F16(bytes.div_ceil(2)),
DecodingSampleType::F32 => DecodingExtent::F32(bytes.div_ceil(4)),
DecodingSampleType::F64 => DecodingExtent::F64(bytes.div_ceil(8)),
}
}
}
/// Information on the byte buffer that should be supplied to the decoder. /// Information on the byte buffer that should be supplied to the decoder.
/// ///
/// This is relevant for [`Decoder::read_image_bytes`] and [`Decoder::read_chunk_bytes`] where the /// This is relevant for [`Decoder::read_image_bytes`] and [`Decoder::read_chunk_bytes`] where the
@@ -383,77 +168,6 @@ impl image::ReadoutLayout {
} }
} }
/// 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)
}
fn sample_type(&self) -> DecodingSampleType {
match *self {
DecodingExtent::U8(_) => DecodingSampleType::U8,
DecodingExtent::U16(_) => DecodingSampleType::U16,
DecodingExtent::U32(_) => DecodingSampleType::U32,
DecodingExtent::U64(_) => DecodingSampleType::U64,
DecodingExtent::F16(_) => DecodingSampleType::F16,
DecodingExtent::F32(_) => DecodingSampleType::F32,
DecodingExtent::F64(_) => DecodingSampleType::F64,
DecodingExtent::I8(_) => DecodingSampleType::I8,
DecodingExtent::I16(_) => DecodingSampleType::I16,
DecodingExtent::I32(_) => DecodingSampleType::I32,
DecodingExtent::I64(_) => DecodingSampleType::I64,
}
}
}
#[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 {
@@ -1400,7 +1114,7 @@ impl<R: Read + Seek> Decoder<R> {
/// 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.
/// ///
/// Note that for planar images each chunk contains only one sample of the underlying data. /// Note that for planar images each chunk contains only one sample of the underlying data.
pub fn read_chunk(&mut self, chunk_index: u32) -> TiffResult<DecodingResult> { pub fn read_chunk(&mut self, chunk_index: u32) -> TiffResult<DecodingSampleBuffer> {
let (width, height) = self.image.chunk_data_dimensions(chunk_index)?; let (width, height) = self.image.chunk_data_dimensions(chunk_index)?;
let readout = self.image.readout_for_size(width, height)?; let readout = self.image.readout_for_size(width, height)?;
@@ -1441,7 +1155,7 @@ impl<R: Read + Seek> Decoder<R> {
/// Note that for planar images each chunk contains only one sample of the underlying data. /// Note that for planar images each chunk contains only one sample of the underlying data.
pub fn read_chunk_to_buffer( pub fn read_chunk_to_buffer(
&mut self, &mut self,
buffer: &mut DecodingResult, buffer: &mut DecodingSampleBuffer,
chunk_index: u32, chunk_index: u32,
output_width: usize, output_width: usize,
) -> TiffResult<()> { ) -> TiffResult<()> {
@@ -1564,7 +1278,7 @@ impl<R: Read + Seek> Decoder<R> {
/// calls. This old method will likely keep its bugged planar behavior until it is fully /// calls. This old method will likely keep its bugged planar behavior until it is fully
/// replaced, to ensure that existing code will not run into unexpectedly large allocations /// replaced, to ensure that existing code will not run into unexpectedly large allocations
/// that will error on limits instead. /// that will error on limits instead.
pub fn read_image(&mut self) -> TiffResult<DecodingResult> { pub fn read_image(&mut self) -> TiffResult<DecodingSampleBuffer> {
let readout = self.image.readout_for_image()?; let readout = self.image.readout_for_image()?;
let mut result = readout let mut result = readout
@@ -1625,7 +1339,7 @@ impl<R: Read + Seek> Decoder<R> {
/// ``` /// ```
pub fn read_image_to_buffer( pub fn read_image_to_buffer(
&mut self, &mut self,
result: &mut DecodingResult, result: &mut DecodingSampleBuffer,
) -> TiffResult<BufferLayoutPreference> { ) -> TiffResult<BufferLayoutPreference> {
let readout = self.image.readout_for_image()?; let readout = self.image.readout_for_image()?;
let planes = readout.to_plane_layout()?; let planes = readout.to_plane_layout()?;
+2 -2
View File
@@ -221,7 +221,7 @@ fn encoder_on_short_writes() {
}; };
let imgdata = vec![42u8; 100 * 100]; let imgdata = vec![42u8; 100 * 100];
let mut data = crate::decoder::DecodingResult::U8(vec![]); let mut data = crate::decoder::DecodingSampleBuffer::U8(vec![]);
for comp in [ for comp in [
super::Compression::Uncompressed, super::Compression::Uncompressed,
@@ -247,7 +247,7 @@ fn encoder_on_short_writes() {
let _layout = tiff_reader.read_image_to_buffer(&mut data).unwrap(); let _layout = tiff_reader.read_image_to_buffer(&mut data).unwrap();
assert!( assert!(
matches!(&data, crate::decoder::DecodingResult::U8(v) if *v == imgdata), matches!(&data, crate::decoder::DecodingSampleBuffer::U8(v) if *v == imgdata),
"{data:?} @ {}", "{data:?} @ {}",
data.as_buffer(0).byte_len() data.as_buffer(0).byte_len()
); );
+6 -6
View File
@@ -1,6 +1,6 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{Decoder, DecodingResult}; use tiff::decoder::{Decoder, DecodingSampleBuffer};
use tiff::ColorType; use tiff::ColorType;
use std::fs::File; use std::fs::File;
@@ -28,7 +28,7 @@ fn test_white_ieee_fp16() {
ColorType::Gray(16) ColorType::Gray(16)
); );
if let DecodingResult::F16(img) = decoder.read_image().unwrap() { if let DecodingSampleBuffer::F16(img) = decoder.read_image().unwrap() {
for p in img { for p in img {
assert!(p == half::f16::from_f32_const(1.0)); assert!(p == half::f16::from_f32_const(1.0));
} }
@@ -58,7 +58,7 @@ fn test_one_black_pixel_ieee_fp16() {
ColorType::Gray(16) ColorType::Gray(16)
); );
if let DecodingResult::F16(img) = decoder.read_image().unwrap() { if let DecodingSampleBuffer::F16(img) = decoder.read_image().unwrap() {
for (i, p) in img.iter().enumerate() { for (i, p) in img.iter().enumerate() {
if i == 0 { if i == 0 {
assert!(p < &half::f16::from_f32_const(0.001)); assert!(p < &half::f16::from_f32_const(0.001));
@@ -92,7 +92,7 @@ fn test_pattern_horizontal_differencing_ieee_fp16() {
ColorType::Gray(16) ColorType::Gray(16)
); );
if let DecodingResult::F16(img) = decoder.read_image().unwrap() { if let DecodingSampleBuffer::F16(img) = decoder.read_image().unwrap() {
// 0, 2, 5, 8, 12, 16, 255 are black // 0, 2, 5, 8, 12, 16, 255 are black
let black = [0, 2, 5, 8, 12, 16, 255]; let black = [0, 2, 5, 8, 12, 16, 255];
for (i, p) in img.iter().enumerate() { for (i, p) in img.iter().enumerate() {
@@ -128,7 +128,7 @@ fn test_pattern_predictor_ieee_fp16() {
ColorType::Gray(16) ColorType::Gray(16)
); );
if let DecodingResult::F16(img) = decoder.read_image().unwrap() { if let DecodingSampleBuffer::F16(img) = decoder.read_image().unwrap() {
// 0, 2, 5, 8, 12, 16, 255 are black // 0, 2, 5, 8, 12, 16, 255 are black
let black = [0, 2, 5, 8, 12, 16, 255]; let black = [0, 2, 5, 8, 12, 16, 255];
for (i, p) in img.iter().enumerate() { for (i, p) in img.iter().enumerate() {
@@ -199,7 +199,7 @@ fn test_predictor_ieee_fp16() {
ColorType::Gray(16) ColorType::Gray(16)
); );
if let DecodingResult::F16(img) = decoder.read_image().unwrap() { if let DecodingSampleBuffer::F16(img) = decoder.read_image().unwrap() {
for (exp, found) in std::iter::zip(pnm_values.iter(), img.iter()) { for (exp, found) in std::iter::zip(pnm_values.iter(), img.iter()) {
assert!((exp - found.to_f32()).abs() < 0.0001); assert!((exp - found.to_f32()).abs() < 0.0001);
} }
+3 -3
View File
@@ -1,6 +1,6 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{Decoder, DecodingResult}; use tiff::decoder::{Decoder, DecodingSampleBuffer};
use tiff::tags::Tag; use tiff::tags::Tag;
use tiff::ColorType; use tiff::ColorType;
@@ -56,7 +56,7 @@ fn test_geo_tiff() {
.expect("Cannot get pixel scale"), .expect("Cannot get pixel scale"),
vec![60.0, 60.0, 0.0] vec![60.0, 60.0, 0.0]
); );
let DecodingResult::I16(data) = decoder.read_image().unwrap() else { let DecodingSampleBuffer::I16(data) = decoder.read_image().unwrap() else {
panic!("Cannot read band data") panic!("Cannot read band data")
}; };
assert_eq!(data.len(), 500); assert_eq!(data.len(), 500);
@@ -67,7 +67,7 @@ fn test_geo_tiff() {
#[test] #[test]
fn test_webp_tiff() { fn test_webp_tiff() {
let filenames = ["usda_naip_256_webp_z3.tif"]; let filenames = ["usda_naip_256_webp_z3.tif"];
let mut buffer = DecodingResult::U8(vec![]); let mut buffer = DecodingSampleBuffer::U8(vec![]);
for filename in filenames.iter() { for filename in filenames.iter() {
let path = PathBuf::from(TEST_IMAGE_DIR).join(filename); let path = PathBuf::from(TEST_IMAGE_DIR).join(filename);
+20 -20
View File
@@ -1,6 +1,6 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{ifd, Decoder, DecodingResult}; use tiff::decoder::{ifd, Decoder, DecodingSampleBuffer};
use tiff::tags::{ByteOrder, Type}; use tiff::tags::{ByteOrder, Type};
use tiff::ColorType; use tiff::ColorType;
@@ -23,7 +23,7 @@ macro_rules! test_image_sum {
let img_res = decoder.read_image().unwrap(); let img_res = decoder.read_image().unwrap();
match img_res { match img_res {
DecodingResult::$buffer(res) => { DecodingSampleBuffer::$buffer(res) => {
let sum: $sum_ty = res.into_iter().map(<$sum_ty>::from).sum(); let sum: $sum_ty = res.into_iter().map(<$sum_ty>::from).sum();
assert_eq!(sum, expected_sum); assert_eq!(sum, expected_sum);
} }
@@ -88,17 +88,17 @@ fn compute_tiff_hash<R: Read + Seek>(reader: R) -> u32 {
// Hash decoded data: TIFF type tag (u16 repr) + LE sample bytes. // Hash decoded data: TIFF type tag (u16 repr) + LE sample bytes.
// Map each variant to the corresponding TIFF Type for byte-order normalization. // Map each variant to the corresponding TIFF Type for byte-order normalization.
let sample_type = match &result { let sample_type = match &result {
DecodingResult::U8(_) => Type::BYTE, DecodingSampleBuffer::U8(_) => Type::BYTE,
DecodingResult::I8(_) => Type::SBYTE, DecodingSampleBuffer::I8(_) => Type::SBYTE,
DecodingResult::U16(_) => Type::SHORT, DecodingSampleBuffer::U16(_) => Type::SHORT,
DecodingResult::I16(_) => Type::SSHORT, DecodingSampleBuffer::I16(_) => Type::SSHORT,
DecodingResult::U32(_) => Type::LONG, DecodingSampleBuffer::U32(_) => Type::LONG,
DecodingResult::I32(_) => Type::SLONG, DecodingSampleBuffer::I32(_) => Type::SLONG,
DecodingResult::F32(_) => Type::FLOAT, DecodingSampleBuffer::F32(_) => Type::FLOAT,
DecodingResult::U64(_) => Type::LONG8, DecodingSampleBuffer::U64(_) => Type::LONG8,
DecodingResult::I64(_) => Type::SLONG8, DecodingSampleBuffer::I64(_) => Type::SLONG8,
DecodingResult::F64(_) => Type::DOUBLE, DecodingSampleBuffer::F64(_) => Type::DOUBLE,
DecodingResult::F16(_) => Type::SHORT, // f16 is 2 bytes like SHORT DecodingSampleBuffer::F16(_) => Type::SHORT, // f16 is 2 bytes like SHORT
}; };
hasher.update(&sample_type.to_u16().to_le_bytes()); hasher.update(&sample_type.to_u16().to_le_bytes());
@@ -431,7 +431,7 @@ fn test_decode_data() {
decoder.next_image().expect("Cannot read image IFD"); decoder.next_image().expect("Cannot read image IFD");
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(8));
assert_eq!(decoder.dimensions().unwrap(), (100, 100)); assert_eq!(decoder.dimensions().unwrap(), (100, 100));
if let DecodingResult::U8(img_res) = decoder.read_image().unwrap() { if let DecodingSampleBuffer::U8(img_res) = decoder.read_image().unwrap() {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} else { } else {
panic!("Wrong data type"); panic!("Wrong data type");
@@ -511,7 +511,7 @@ fn test_inner_access() {
let raw_sum: u64 = buf.into_iter().map(<u64>::from).sum(); let raw_sum: u64 = buf.into_iter().map(<u64>::from).sum();
match decoder.read_chunk(0).unwrap() { match decoder.read_chunk(0).unwrap() {
DecodingResult::U8(chunk) => { DecodingSampleBuffer::U8(chunk) => {
let sum: u64 = chunk.into_iter().map(<u64>::from).sum(); let sum: u64 = chunk.into_iter().map(<u64>::from).sum();
assert_eq!(sum, raw_sum); assert_eq!(sum, raw_sum);
} }
@@ -570,7 +570,7 @@ fn test_tiled_incremental() {
for tile in 0..tiles { for tile in 0..tiles {
match decoder.read_chunk(tile).unwrap() { match decoder.read_chunk(tile).unwrap() {
DecodingResult::U8(res) => { DecodingSampleBuffer::U8(res) => {
let sum: u64 = res.into_iter().map(<u64>::from).sum(); let sum: u64 = res.into_iter().map(<u64>::from).sum();
assert_eq!(sum, sums[tile as usize]); assert_eq!(sum, sums[tile as usize]);
} }
@@ -604,21 +604,21 @@ fn test_read_planar_bands() {
// 1st band (red) // 1st band (red)
match decoder.read_chunk(0).unwrap() { match decoder.read_chunk(0).unwrap() {
DecodingResult::U8(chunk) => { DecodingSampleBuffer::U8(chunk) => {
assert_eq!(chunk[0], 73); assert_eq!(chunk[0], 73);
} }
_ => panic!("Wrong bit depth"), _ => panic!("Wrong bit depth"),
} }
// 2nd band (green) // 2nd band (green)
match decoder.read_chunk(chunks / 3).unwrap() { match decoder.read_chunk(chunks / 3).unwrap() {
DecodingResult::U8(chunk) => { DecodingSampleBuffer::U8(chunk) => {
assert_eq!(chunk[0], 51); assert_eq!(chunk[0], 51);
} }
_ => panic!("Wrong bit depth"), _ => panic!("Wrong bit depth"),
} }
// 3rd band (blue) // 3rd band (blue)
match decoder.read_chunk(chunks / 3 * 2).unwrap() { match decoder.read_chunk(chunks / 3 * 2).unwrap() {
DecodingResult::U8(chunk) => { DecodingSampleBuffer::U8(chunk) => {
assert_eq!(chunk[0], 30); assert_eq!(chunk[0], 30);
} }
_ => panic!("Wrong bit depth"), _ => panic!("Wrong bit depth"),
@@ -994,7 +994,7 @@ fn test_decode_huge_g4() {
.read_image() .read_image()
.expect("failed to decode huge G4 image"); .expect("failed to decode huge G4 image");
if let tiff::decoder::DecodingResult::U8(data) = result { if let tiff::decoder::DecodingSampleBuffer::U8(data) = result {
assert_eq!(data.len(), (width as usize * height as usize)); assert_eq!(data.len(), (width as usize * height as usize));
} else { } else {
panic!("Unexpected decoding result type"); panic!("Unexpected decoding result type");
+14 -14
View File
@@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::{fs::File, path}; use std::{fs::File, path};
use tiff::decoder::{Decoder, DecodingResult}; use tiff::decoder::{Decoder, DecodingSampleBuffer};
use tiff::tags::{ByteOrder, Type}; use tiff::tags::{ByteOrder, Type};
use tiff::ColorType; use tiff::ColorType;
@@ -252,19 +252,19 @@ fn main() {
} }
/// Map DecodingResult variant to a TIFF Type for byte-order normalization. /// Map DecodingResult variant to a TIFF Type for byte-order normalization.
fn sample_type_of(result: &DecodingResult) -> Type { fn sample_type_of(result: &DecodingSampleBuffer) -> Type {
match result { match result {
DecodingResult::U8(_) => Type::BYTE, DecodingSampleBuffer::U8(_) => Type::BYTE,
DecodingResult::I8(_) => Type::SBYTE, DecodingSampleBuffer::I8(_) => Type::SBYTE,
DecodingResult::U16(_) => Type::SHORT, DecodingSampleBuffer::U16(_) => Type::SHORT,
DecodingResult::I16(_) => Type::SSHORT, DecodingSampleBuffer::I16(_) => Type::SSHORT,
DecodingResult::U32(_) => Type::LONG, DecodingSampleBuffer::U32(_) => Type::LONG,
DecodingResult::I32(_) => Type::SLONG, DecodingSampleBuffer::I32(_) => Type::SLONG,
DecodingResult::F32(_) => Type::FLOAT, DecodingSampleBuffer::F32(_) => Type::FLOAT,
DecodingResult::U64(_) => Type::LONG8, DecodingSampleBuffer::U64(_) => Type::LONG8,
DecodingResult::I64(_) => Type::SLONG8, DecodingSampleBuffer::I64(_) => Type::SLONG8,
DecodingResult::F64(_) => Type::DOUBLE, DecodingSampleBuffer::F64(_) => Type::DOUBLE,
DecodingResult::F16(_) => Type::SHORT, // f16 is 2 bytes like SHORT DecodingSampleBuffer::F16(_) => Type::SHORT, // f16 is 2 bytes like SHORT
} }
} }
@@ -299,7 +299,7 @@ fn compute_hash(path: &std::path::Path) -> Result<u32, tiff::TiffError> {
let img_file = File::open(path)?; let img_file = File::open(path)?;
let mut decoder = Decoder::open(img_file)?; let mut decoder = Decoder::open(img_file)?;
let mut hasher = crc32fast::Hasher::new(); let mut hasher = crc32fast::Hasher::new();
let mut buffer = DecodingResult::U8(vec![]); let mut buffer = DecodingSampleBuffer::U8(vec![]);
let mut page = 0u32; let mut page = 0u32;
while decoder.more_images() { while decoder.more_images() {
+2 -2
View File
@@ -1,4 +1,4 @@
use tiff::decoder::{Decoder, DecodingResult, Limits, TiffCodingUnit}; use tiff::decoder::{Decoder, DecodingSampleBuffer, Limits, TiffCodingUnit};
use std::fs::File; use std::fs::File;
use std::path::PathBuf; use std::path::PathBuf;
@@ -84,7 +84,7 @@ fn read_planes_by_limits() {
let io = std::io::BufReader::new(file); let io = std::io::BufReader::new(file);
let mut limits = Limits::default(); let mut limits = Limits::default();
let mut buffer = DecodingResult::U8(vec![]); let mut buffer = DecodingSampleBuffer::U8(vec![]);
// Make room for 1 plane. // Make room for 1 plane.
let mut tif = Decoder::open(io).unwrap(); let mut tif = Decoder::open(io).unwrap();
+16 -16
View File
@@ -1,6 +1,6 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{ifd, Decoder, DecodingResult}; use tiff::decoder::{ifd, Decoder, DecodingSampleBuffer};
use tiff::encoder::{colortype, Ifd, Ifd8, Predictor, SRational, TiffEncoder}; use tiff::encoder::{colortype, Ifd, Ifd8, Predictor, SRational, TiffEncoder};
use tiff::tags::Tag; use tiff::tags::Tag;
use tiff::ColorType; use tiff::ColorType;
@@ -84,9 +84,9 @@ fn encode_decode() {
ifd::Value::Ascii("Image-tiff".into()) ifd::Value::Ascii("Image-tiff".into())
); );
let mut buffer = tiff::decoder::DecodingResult::U8(vec![]); let mut buffer = tiff::decoder::DecodingSampleBuffer::U8(vec![]);
let _layout = decoder.read_image_to_buffer(&mut buffer).unwrap(); let _layout = decoder.read_image_to_buffer(&mut buffer).unwrap();
if let tiff::decoder::DecodingResult::U8(img_res) = buffer { if let tiff::decoder::DecodingSampleBuffer::U8(img_res) = buffer {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} else { } else {
panic!("Wrong data type"); panic!("Wrong data type");
@@ -168,9 +168,9 @@ fn encode_decode_big() {
decoder.get_tag(Tag::Artist).unwrap(), decoder.get_tag(Tag::Artist).unwrap(),
ifd::Value::Ascii("Image-tiff".into()) ifd::Value::Ascii("Image-tiff".into())
); );
let mut buffer = tiff::decoder::DecodingResult::U8(vec![]); let mut buffer = tiff::decoder::DecodingSampleBuffer::U8(vec![]);
let _layout = decoder.read_image_to_buffer(&mut buffer).unwrap(); let _layout = decoder.read_image_to_buffer(&mut buffer).unwrap();
if let DecodingResult::U8(img_res) = buffer { if let DecodingSampleBuffer::U8(img_res) = buffer {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);
} else { } else {
panic!("Wrong data type"); panic!("Wrong data type");
@@ -258,11 +258,11 @@ macro_rules! test_roundtrip {
assert_eq!(decoder.colortype().unwrap(), expected_type); assert_eq!(decoder.colortype().unwrap(), expected_type);
let mut buffer = tiff::decoder::DecodingResult::U8(vec![]); let mut buffer = tiff::decoder::DecodingSampleBuffer::U8(vec![]);
decoder.read_image_to_buffer(&mut buffer).unwrap(); decoder.read_image_to_buffer(&mut buffer).unwrap();
let image_data = match buffer { let image_data = match buffer {
DecodingResult::$buffer(res) => res, DecodingSampleBuffer::$buffer(res) => res,
_ => panic!("Wrong data type"), _ => panic!("Wrong data type"),
}; };
@@ -275,11 +275,11 @@ macro_rules! test_roundtrip {
} }
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
{ {
let mut buffer = tiff::decoder::DecodingResult::U8(vec![]); let mut buffer = tiff::decoder::DecodingSampleBuffer::U8(vec![]);
let mut decoder = Decoder::open(&mut file).unwrap(); let mut decoder = Decoder::open(&mut file).unwrap();
decoder.next_image().unwrap(); decoder.next_image().unwrap();
decoder.read_image_to_buffer(&mut buffer).unwrap(); decoder.read_image_to_buffer(&mut buffer).unwrap();
if let DecodingResult::$buffer(img_res) = buffer { if let DecodingSampleBuffer::$buffer(img_res) = buffer {
assert_eq!(*image_data, img_res); assert_eq!(*image_data, img_res);
} else { } else {
panic!("Wrong data type"); panic!("Wrong data type");
@@ -418,9 +418,9 @@ fn test_gray_f32_floating_point_predictor() {
decoder.next_image().unwrap(); decoder.next_image().unwrap();
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(32)); assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(32));
let mut buffer = DecodingResult::F32(vec![]); let mut buffer = DecodingSampleBuffer::F32(vec![]);
decoder.read_image_to_buffer(&mut buffer).unwrap(); decoder.read_image_to_buffer(&mut buffer).unwrap();
if let DecodingResult::F32(img_res) = buffer { if let DecodingSampleBuffer::F32(img_res) = buffer {
assert_eq!(image_data.len(), img_res.len()); assert_eq!(image_data.len(), img_res.len());
for (orig, decoded) in image_data.iter().zip(img_res.iter()) { for (orig, decoded) in image_data.iter().zip(img_res.iter()) {
assert_eq!( assert_eq!(
@@ -465,9 +465,9 @@ fn test_rgb_f32_floating_point_predictor() {
decoder.next_image().unwrap(); decoder.next_image().unwrap();
assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(32)); assert_eq!(decoder.colortype().unwrap(), ColorType::RGB(32));
let mut buffer = DecodingResult::F32(vec![]); let mut buffer = DecodingSampleBuffer::F32(vec![]);
decoder.read_image_to_buffer(&mut buffer).unwrap(); decoder.read_image_to_buffer(&mut buffer).unwrap();
if let DecodingResult::F32(img_res) = buffer { if let DecodingSampleBuffer::F32(img_res) = buffer {
assert_eq!(image_data.len(), img_res.len()); assert_eq!(image_data.len(), img_res.len());
for (i, (orig, decoded)) in image_data.iter().zip(img_res.iter()).enumerate() { for (i, (orig, decoded)) in image_data.iter().zip(img_res.iter()).enumerate() {
assert_eq!( assert_eq!(
@@ -509,9 +509,9 @@ fn test_gray_f64_floating_point_predictor() {
decoder.next_image().unwrap(); decoder.next_image().unwrap();
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(64)); assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(64));
let mut buffer = DecodingResult::F64(vec![]); let mut buffer = DecodingSampleBuffer::F64(vec![]);
decoder.read_image_to_buffer(&mut buffer).unwrap(); decoder.read_image_to_buffer(&mut buffer).unwrap();
if let DecodingResult::F64(img_res) = buffer { if let DecodingSampleBuffer::F64(img_res) = buffer {
assert_eq!(image_data.len(), img_res.len()); assert_eq!(image_data.len(), img_res.len());
for (orig, decoded) in image_data.iter().zip(img_res.iter()) { for (orig, decoded) in image_data.iter().zip(img_res.iter()) {
assert_eq!( assert_eq!(
@@ -782,7 +782,7 @@ fn test_rows_per_strip() {
for i in 0..50 { for i in 0..50 {
let img2 = [i; 2 * 100]; let img2 = [i; 2 * 100];
match decoder.read_chunk(i as u32).unwrap() { match decoder.read_chunk(i as u32).unwrap() {
DecodingResult::U8(data) => assert_eq!(&img2[..], &data[..]), DecodingSampleBuffer::U8(data) => assert_eq!(&img2[..], &data[..]),
other => panic!("Incorrect strip type {other:?}"), other => panic!("Incorrect strip type {other:?}"),
} }
} }
+3 -3
View File
@@ -2,7 +2,7 @@ extern crate tiff;
use std::io::{Cursor, Seek, Write}; use std::io::{Cursor, Seek, Write};
use tiff::{ use tiff::{
decoder::{Decoder, DecodingResult}, decoder::{Decoder, DecodingSampleBuffer},
encoder::{ encoder::{
colortype::{self, ColorType}, colortype::{self, ColorType},
Compression, TiffEncoder, TiffValue, Compression, TiffEncoder, TiffValue,
@@ -115,7 +115,7 @@ fn encode_decode_with_compression(compression: Compression) {
// Check the RGB image // Check the RGB image
assert_eq!( assert_eq!(
match decoder.read_image() { match decoder.read_image() {
Ok(DecodingResult::U16(image_data)) => image_data, Ok(DecodingSampleBuffer::U16(image_data)) => image_data,
unexpected => panic!("Descoding RGB failed: {unexpected:?}"), unexpected => panic!("Descoding RGB failed: {unexpected:?}"),
}, },
image_rgb.reference_data() image_rgb.reference_data()
@@ -125,7 +125,7 @@ fn encode_decode_with_compression(compression: Compression) {
decoder.next_image().unwrap(); decoder.next_image().unwrap();
assert_eq!( assert_eq!(
match decoder.read_image() { match decoder.read_image() {
Ok(DecodingResult::U8(image_data)) => image_data, Ok(DecodingSampleBuffer::U8(image_data)) => image_data,
unexpected => panic!("Decoding grayscale failed: {unexpected:?}"), unexpected => panic!("Decoding grayscale failed: {unexpected:?}"),
}, },
image_grayscale.reference_data() image_grayscale.reference_data()
+4 -4
View File
@@ -1,6 +1,6 @@
extern crate tiff; extern crate tiff;
use tiff::decoder::{Decoder, DecodingResult}; use tiff::decoder::{Decoder, DecodingSampleBuffer};
use tiff::encoder::{colortype, Predictor, TiffEncoder}; use tiff::encoder::{colortype, Predictor, TiffEncoder};
use tiff::ColorType; use tiff::ColorType;
@@ -23,7 +23,7 @@ macro_rules! test_predict {
decoder.next_image().unwrap(); decoder.next_image().unwrap();
assert_eq!(decoder.colortype().unwrap(), expected_type); assert_eq!(decoder.colortype().unwrap(), expected_type);
let image_data = match decoder.read_image().unwrap() { let image_data = match decoder.read_image().unwrap() {
DecodingResult::$buffer(res) => res, DecodingSampleBuffer::$buffer(res) => res,
_ => panic!("Wrong data type"), _ => panic!("Wrong data type"),
}; };
@@ -130,7 +130,7 @@ macro_rules! test_predict_roundtrip {
assert_eq!(decoder.colortype().unwrap(), expected_type); assert_eq!(decoder.colortype().unwrap(), expected_type);
let image_data = match decoder.read_image().unwrap() { let image_data = match decoder.read_image().unwrap() {
DecodingResult::$buffer(res) => res, DecodingSampleBuffer::$buffer(res) => res,
_ => panic!("Wrong data type"), _ => panic!("Wrong data type"),
}; };
@@ -147,7 +147,7 @@ macro_rules! test_predict_roundtrip {
{ {
let mut decoder = Decoder::open(&mut file).unwrap(); let mut decoder = Decoder::open(&mut file).unwrap();
decoder.next_image().unwrap(); decoder.next_image().unwrap();
if let DecodingResult::$buffer(img_res) = if let DecodingSampleBuffer::$buffer(img_res) =
decoder.read_image().expect("Decoding image failed") decoder.read_image().expect("Decoding image failed")
{ {
assert_eq!(image_data, img_res); assert_eq!(image_data, img_res);