Merge TagReader and exposed IfdReader internals

Having the value reader itself take care of the bigtiff and limit
semantics is a little cleaner, with the TagReader being responsible
for the interface of grabbing specific types of IFD values.
This commit is contained in:
A. Molzer committed 2025-07-11 15:09:31 +02:00
1 parent f021e3e599
commit e62cdfbf42
3 files changed
+38 -49

No files matched your search

+2 -13
View File
@@ -82,21 +82,10 @@ pub(crate) struct Image {
impl Image { impl Image {
pub fn from_reader<R: Read + Seek>( pub fn from_reader<R: Read + Seek>(
reader: &mut ValueReader<R>, decoder: &mut ValueReader<R>,
ifd: Directory, ifd: Directory,
) -> TiffResult<Image> { ) -> TiffResult<Image> {
let ValueReader { let mut tag_reader = TagReader { decoder, ifd: &ifd };
reader,
bigtiff,
limits,
} = reader;
let mut tag_reader = TagReader {
reader,
limits,
ifd: &ifd,
bigtiff: *bigtiff,
};
let width = tag_reader.require_tag(Tag::ImageWidth)?.into_u32()?; let width = tag_reader.require_tag(Tag::ImageWidth)?.into_u32()?;
let height = tag_reader.require_tag(Tag::ImageLength)?.into_u32()?; let height = tag_reader.require_tag(Tag::ImageLength)?.into_u32()?;
+9 -22
View File
@@ -10,7 +10,6 @@ use crate::{
UsageError, UsageError,
}; };
use half::f16; use half::f16;
use ifd::Entry;
use self::image::Image; use self::image::Image;
use self::stream::{ByteOrder, EndianReader}; use self::stream::{ByteOrder, EndianReader};
@@ -286,8 +285,7 @@ struct ValueReader<R> {
/// Reads a directory's tag values from an underlying stream. /// Reads a directory's tag values from an underlying stream.
pub struct IfdDecoder<'lt> { pub struct IfdDecoder<'lt> {
decoder: &'lt mut dyn EntryDecoder, inner: tag_reader::TagReader<'lt, dyn tag_reader::EntryDecoder + 'lt>,
ifd: &'lt Directory,
} }
fn rev_hpredict_nsamp(buf: &mut [u8], bit_depth: u8, samples: usize) { fn rev_hpredict_nsamp(buf: &mut [u8], bit_depth: u8, samples: usize) {
@@ -987,8 +985,10 @@ impl<R: Read + Seek> Decoder<R> {
/// Get the IFD decoder for our current image IFD. /// Get the IFD decoder for our current image IFD.
fn image_ifd(&mut self) -> IfdDecoder<'_> { fn image_ifd(&mut self) -> IfdDecoder<'_> {
IfdDecoder { IfdDecoder {
inner: tag_reader::TagReader {
decoder: &mut self.value_reader, decoder: &mut self.value_reader,
ifd: self.image.ifd.as_ref().unwrap(), ifd: self.image.ifd.as_ref().unwrap(),
},
} }
} }
@@ -1018,8 +1018,10 @@ impl<R: Read + Seek> Decoder<R> {
/// ``` /// ```
pub fn read_directory_tags<'ifd>(&'ifd mut self, ifd: &'ifd Directory) -> IfdDecoder<'ifd> { pub fn read_directory_tags<'ifd>(&'ifd mut self, ifd: &'ifd Directory) -> IfdDecoder<'ifd> {
IfdDecoder { IfdDecoder {
inner: tag_reader::TagReader {
decoder: &mut self.value_reader, decoder: &mut self.value_reader,
ifd, ifd,
},
} }
} }
@@ -1184,27 +1186,11 @@ impl<R: Seek + Read> ValueReader<R> {
} }
} }
trait EntryDecoder {
/// Turn an entry into a value by fetching the required bytes in the stream.
fn entry_val(&mut self, entry: &Entry) -> TiffResult<ifd::Value>;
}
impl<R: Seek + Read> EntryDecoder for ValueReader<R> {
fn entry_val(&mut self, entry: &Entry) -> TiffResult<ifd::Value> {
entry.val(&self.limits, self.bigtiff, &mut self.reader)
}
}
impl IfdDecoder<'_> { impl IfdDecoder<'_> {
/// Tries to retrieve a tag. /// Tries to retrieve a tag.
/// Return `Ok(None)` if the tag is not present. /// Return `Ok(None)` if the tag is not present.
pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> { pub fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<ifd::Value>> {
let entry = match self.ifd.get(tag) { self.inner.find_tag(tag)
None => return Ok(None),
Some(entry) => entry.clone(),
};
self.decoder.entry_val(&entry).map(Some)
} }
/// Tries to retrieve a tag and convert it to the desired unsigned type. /// Tries to retrieve a tag and convert it to the desired unsigned type.
@@ -1311,9 +1297,10 @@ impl IfdDecoder<'_> {
impl<'l> IfdDecoder<'l> { impl<'l> IfdDecoder<'l> {
/// Returns an iterator over all tags in the current image, along with their values. /// Returns an iterator over all tags in the current image, along with their values.
pub fn tag_iter(self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + 'l { pub fn tag_iter(self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + 'l {
self.ifd self.inner
.ifd
.iter() .iter()
.map(|(tag, entry)| match self.decoder.entry_val(entry) { .map(|(tag, entry)| match self.inner.decoder.entry_val(entry) {
Ok(value) => Ok((tag, value)), Ok(value) => Ok((tag, value)),
Err(err) => Err(err), Err(err) => Err(err),
}) })
+27 -14
View File
@@ -3,23 +3,35 @@ use std::io::{Read, Seek};
use crate::{tags::Tag, Directory}; use crate::{tags::Tag, Directory};
use crate::{TiffError, TiffFormatError, TiffResult}; use crate::{TiffError, TiffFormatError, TiffResult};
use super::ifd::Value; use super::ifd::{Entry, Value};
use super::stream::EndianReader; use super::ValueReader;
use super::Limits;
pub(crate) struct TagReader<'a, R: Read + Seek> { pub(crate) struct TagReader<'lt, R: EntryDecoder + ?Sized> {
pub reader: &'a mut EndianReader<R>, pub(crate) decoder: &'lt mut R,
pub ifd: &'a Directory, pub(crate) ifd: &'lt Directory,
pub limits: &'a Limits,
pub bigtiff: bool,
} }
impl<'a, R: Read + Seek> TagReader<'a, R> {
pub(crate) fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<Value>> { pub(crate) trait EntryDecoder {
Ok(match self.ifd.get(tag) { /// Turn an entry into a value by fetching the required bytes in the stream.
Some(entry) => Some(entry.clone().val(self.limits, self.bigtiff, self.reader)?), fn entry_val(&mut self, entry: &Entry) -> TiffResult<Value>;
None => None, }
})
impl<R: Seek + Read> EntryDecoder for ValueReader<R> {
fn entry_val(&mut self, entry: &Entry) -> TiffResult<Value> {
entry.val(&self.limits, self.bigtiff, &mut self.reader)
} }
}
impl<'a, R: EntryDecoder + ?Sized> TagReader<'a, R> {
pub(crate) fn find_tag(&mut self, tag: Tag) -> TiffResult<Option<Value>> {
let entry = match self.ifd.get(tag) {
None => return Ok(None),
Some(entry) => entry.clone(),
};
self.decoder.entry_val(&entry).map(Some)
}
pub(crate) fn require_tag(&mut self, tag: Tag) -> TiffResult<Value> { pub(crate) fn require_tag(&mut self, tag: Tag) -> TiffResult<Value> {
match self.find_tag(tag)? { match self.find_tag(tag)? {
Some(val) => Ok(val), Some(val) => Ok(val),
@@ -28,6 +40,7 @@ impl<'a, R: Read + Seek> TagReader<'a, R> {
)), )),
} }
} }
pub fn find_tag_uint_vec<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<Vec<T>>> { pub fn find_tag_uint_vec<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<Vec<T>>> {
self.find_tag(tag)? self.find_tag(tag)?
.map(|v| v.into_u64_vec()) .map(|v| v.into_u64_vec())