From e62cdfbf421b492f0c203b28415d90a88e5ba325 Mon Sep 17 00:00:00 2001 From: "A. Molzer" <5550310+197g@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:03:40 +0200 Subject: [PATCH] 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. --- src/decoder/image.rs | 15 ++------------ src/decoder/mod.rs | 39 +++++++++++++------------------------ src/decoder/tag_reader.rs | 41 ++++++++++++++++++++++++++------------- 3 files changed, 42 insertions(+), 53 deletions(-) diff --git a/src/decoder/image.rs b/src/decoder/image.rs index cebfaf1..49510a3 100644 --- a/src/decoder/image.rs +++ b/src/decoder/image.rs @@ -82,21 +82,10 @@ pub(crate) struct Image { impl Image { pub fn from_reader( - reader: &mut ValueReader, + decoder: &mut ValueReader, ifd: Directory, ) -> TiffResult { - let ValueReader { - reader, - bigtiff, - limits, - } = reader; - - let mut tag_reader = TagReader { - reader, - limits, - ifd: &ifd, - bigtiff: *bigtiff, - }; + let mut tag_reader = TagReader { decoder, ifd: &ifd }; let width = tag_reader.require_tag(Tag::ImageWidth)?.into_u32()?; let height = tag_reader.require_tag(Tag::ImageLength)?.into_u32()?; diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index 1e8e535..ed2fdd2 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -10,7 +10,6 @@ use crate::{ UsageError, }; use half::f16; -use ifd::Entry; use self::image::Image; use self::stream::{ByteOrder, EndianReader}; @@ -286,8 +285,7 @@ struct ValueReader { /// Reads a directory's tag values from an underlying stream. pub struct IfdDecoder<'lt> { - decoder: &'lt mut dyn EntryDecoder, - ifd: &'lt Directory, + inner: tag_reader::TagReader<'lt, dyn tag_reader::EntryDecoder + 'lt>, } fn rev_hpredict_nsamp(buf: &mut [u8], bit_depth: u8, samples: usize) { @@ -987,8 +985,10 @@ impl Decoder { /// Get the IFD decoder for our current image IFD. fn image_ifd(&mut self) -> IfdDecoder<'_> { IfdDecoder { - decoder: &mut self.value_reader, - ifd: self.image.ifd.as_ref().unwrap(), + inner: tag_reader::TagReader { + decoder: &mut self.value_reader, + ifd: self.image.ifd.as_ref().unwrap(), + }, } } @@ -1018,8 +1018,10 @@ impl Decoder { /// ``` pub fn read_directory_tags<'ifd>(&'ifd mut self, ifd: &'ifd Directory) -> IfdDecoder<'ifd> { IfdDecoder { - decoder: &mut self.value_reader, - ifd, + inner: tag_reader::TagReader { + decoder: &mut self.value_reader, + ifd, + }, } } @@ -1184,27 +1186,11 @@ impl ValueReader { } } -trait EntryDecoder { - /// Turn an entry into a value by fetching the required bytes in the stream. - fn entry_val(&mut self, entry: &Entry) -> TiffResult; -} - -impl EntryDecoder for ValueReader { - fn entry_val(&mut self, entry: &Entry) -> TiffResult { - entry.val(&self.limits, self.bigtiff, &mut self.reader) - } -} - impl IfdDecoder<'_> { /// Tries to retrieve a tag. /// Return `Ok(None)` if the tag is not present. pub fn find_tag(&mut self, tag: Tag) -> TiffResult> { - let entry = match self.ifd.get(tag) { - None => return Ok(None), - Some(entry) => entry.clone(), - }; - - self.decoder.entry_val(&entry).map(Some) + self.inner.find_tag(tag) } /// Tries to retrieve a tag and convert it to the desired unsigned type. @@ -1311,9 +1297,10 @@ impl IfdDecoder<'_> { impl<'l> IfdDecoder<'l> { /// Returns an iterator over all tags in the current image, along with their values. pub fn tag_iter(self) -> impl Iterator> + 'l { - self.ifd + self.inner + .ifd .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)), Err(err) => Err(err), }) diff --git a/src/decoder/tag_reader.rs b/src/decoder/tag_reader.rs index c6d340f..99bba57 100644 --- a/src/decoder/tag_reader.rs +++ b/src/decoder/tag_reader.rs @@ -3,23 +3,35 @@ use std::io::{Read, Seek}; use crate::{tags::Tag, Directory}; use crate::{TiffError, TiffFormatError, TiffResult}; -use super::ifd::Value; -use super::stream::EndianReader; -use super::Limits; +use super::ifd::{Entry, Value}; +use super::ValueReader; -pub(crate) struct TagReader<'a, R: Read + Seek> { - pub reader: &'a mut EndianReader, - pub ifd: &'a Directory, - pub limits: &'a Limits, - pub bigtiff: bool, +pub(crate) struct TagReader<'lt, R: EntryDecoder + ?Sized> { + pub(crate) decoder: &'lt mut R, + pub(crate) ifd: &'lt Directory, } -impl<'a, R: Read + Seek> TagReader<'a, R> { - pub(crate) fn find_tag(&mut self, tag: Tag) -> TiffResult> { - Ok(match self.ifd.get(tag) { - Some(entry) => Some(entry.clone().val(self.limits, self.bigtiff, self.reader)?), - None => None, - }) + +pub(crate) trait EntryDecoder { + /// Turn an entry into a value by fetching the required bytes in the stream. + fn entry_val(&mut self, entry: &Entry) -> TiffResult; +} + +impl EntryDecoder for ValueReader { + fn entry_val(&mut self, entry: &Entry) -> TiffResult { + 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> { + 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 { match self.find_tag(tag)? { Some(val) => Ok(val), @@ -28,6 +40,7 @@ impl<'a, R: Read + Seek> TagReader<'a, R> { )), } } + pub fn find_tag_uint_vec>(&mut self, tag: Tag) -> TiffResult>> { self.find_tag(tag)? .map(|v| v.into_u64_vec())