Track non-image Directory sequence in Reader
A bit nasty, since we are storing the current Directory within the Image instead of a separate attribute so we can not have one without the other directly. Instead we prioritize with another attribute.
This commit is contained in:
1 parent
f993cfb940
commit
ab0ce47230
4 files changed
+60
-20
No files matched your search
+14
-2
@@ -86,7 +86,19 @@ impl Image {
|
|||||||
decoder: &mut ValueReader<R>,
|
decoder: &mut ValueReader<R>,
|
||||||
ifd: Directory,
|
ifd: Directory,
|
||||||
) -> TiffResult<Image> {
|
) -> TiffResult<Image> {
|
||||||
let mut tag_reader = TagReader { decoder, ifd: &ifd };
|
let img = Self::from_ref(decoder, &ifd)?;
|
||||||
|
|
||||||
|
Ok(Image {
|
||||||
|
ifd: Some(ifd),
|
||||||
|
..img
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_ref<R: Read + Seek>(
|
||||||
|
decoder: &mut ValueReader<R>,
|
||||||
|
ifd: &Directory,
|
||||||
|
) -> TiffResult<Image> {
|
||||||
|
let mut tag_reader = TagReader { decoder, ifd };
|
||||||
|
|
||||||
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()?;
|
||||||
@@ -288,7 +300,7 @@ impl Image {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Image {
|
Ok(Image {
|
||||||
ifd: Some(ifd),
|
ifd: None,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
bits_per_sample: bits_per_sample[0],
|
bits_per_sample: bits_per_sample[0],
|
||||||
|
|||||||
+44
-13
@@ -349,6 +349,10 @@ where
|
|||||||
ifd_offsets: Vec<IfdPointer>,
|
ifd_offsets: Vec<IfdPointer>,
|
||||||
/// Map from the ifd into the `ifd_offsets` ordered list.
|
/// Map from the ifd into the `ifd_offsets` ordered list.
|
||||||
seen_ifds: cycles::IfdCycles,
|
seen_ifds: cycles::IfdCycles,
|
||||||
|
/// The directory, if we have not yet read it as an image.
|
||||||
|
/// This is prioritized _over_ the image. Hence it must _not_ be set if we are currently
|
||||||
|
/// reading a true image IFD that is instead stored in the `image` attribute.
|
||||||
|
non_image_ifd: Option<Directory>,
|
||||||
image: Image,
|
image: Image,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,6 +628,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
chunk_offsets: Vec::new(),
|
chunk_offsets: Vec::new(),
|
||||||
chunk_bytes: Vec::new(),
|
chunk_bytes: Vec::new(),
|
||||||
},
|
},
|
||||||
|
non_image_ifd: None,
|
||||||
};
|
};
|
||||||
decoder.next_image()?;
|
decoder.next_image()?;
|
||||||
Ok(decoder)
|
Ok(decoder)
|
||||||
@@ -654,6 +659,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// Loads the IFD at the specified index in the list, if one exists
|
/// Loads the IFD at the specified index in the list, if one exists
|
||||||
pub fn seek_to_image(&mut self, ifd_index: usize) -> TiffResult<()> {
|
pub fn seek_to_image(&mut self, ifd_index: usize) -> TiffResult<()> {
|
||||||
let ifd = self.seek_to_directory(ifd_index)?;
|
let ifd = self.seek_to_directory(ifd_index)?;
|
||||||
|
self.non_image_ifd = None;
|
||||||
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -699,6 +705,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// recovered by calling [`Self::restart_at_image`] with a valid offset and a successful seek.
|
/// recovered by calling [`Self::restart_at_image`] with a valid offset and a successful seek.
|
||||||
pub fn restart_at_image(&mut self, offset: IfdPointer) -> TiffResult<()> {
|
pub fn restart_at_image(&mut self, offset: IfdPointer) -> TiffResult<()> {
|
||||||
let ifd = self.restart_at_offset(offset)?;
|
let ifd = self.restart_at_offset(offset)?;
|
||||||
|
self.non_image_ifd = None;
|
||||||
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -709,8 +716,10 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// interpret the directory in the sequence as an image. Instead, it may be used to read a
|
/// interpret the directory in the sequence as an image. Instead, it may be used to read a
|
||||||
/// sequence of auxiliary IFDs that are not necessarily images. For instance, a directory
|
/// sequence of auxiliary IFDs that are not necessarily images. For instance, a directory
|
||||||
/// referred to in the SubIfd tag may be a thumbnail
|
/// referred to in the SubIfd tag may be a thumbnail
|
||||||
pub fn restart_at_directory(&mut self, offset: IfdPointer) -> TiffResult<Directory> {
|
pub fn restart_at_directory(&mut self, offset: IfdPointer) -> TiffResult<()> {
|
||||||
self.restart_at_offset(offset)
|
let ifd = self.restart_at_offset(offset)?;
|
||||||
|
self.non_image_ifd = Some(ifd);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restart_at_offset(&mut self, offset: IfdPointer) -> TiffResult<Directory> {
|
fn restart_at_offset(&mut self, offset: IfdPointer) -> TiffResult<Directory> {
|
||||||
@@ -726,6 +735,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
fn next_ifd(&mut self) -> TiffResult<Directory> {
|
fn next_ifd(&mut self) -> TiffResult<Directory> {
|
||||||
let Some(next_ifd) = self.next_ifd.take() else {
|
let Some(next_ifd) = self.next_ifd.take() else {
|
||||||
self.current_ifd = None;
|
self.current_ifd = None;
|
||||||
|
self.non_image_ifd = None;
|
||||||
|
|
||||||
return Err(TiffError::FormatError(
|
return Err(TiffError::FormatError(
|
||||||
TiffFormatError::ImageFileDirectoryNotFound,
|
TiffFormatError::ImageFileDirectoryNotFound,
|
||||||
@@ -753,6 +763,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// To determine whether there are more images call `TIFFDecoder::more_images` instead.
|
/// To determine whether there are more images call `TIFFDecoder::more_images` instead.
|
||||||
pub fn next_image(&mut self) -> TiffResult<()> {
|
pub fn next_image(&mut self) -> TiffResult<()> {
|
||||||
let ifd = self.next_ifd()?;
|
let ifd = self.next_ifd()?;
|
||||||
|
self.non_image_ifd = None;
|
||||||
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -761,8 +772,10 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
///
|
///
|
||||||
/// If there is no further image in the TIFF file a format error is returned. To determine
|
/// If there is no further image in the TIFF file a format error is returned. To determine
|
||||||
/// whether there are more images call `TIFFDecoder::more_directories` instead.
|
/// whether there are more images call `TIFFDecoder::more_directories` instead.
|
||||||
pub fn next_directory(&mut self) -> TiffResult<Directory> {
|
pub fn next_directory(&mut self) -> TiffResult<()> {
|
||||||
self.next_ifd()
|
let ifd = self.next_ifd()?;
|
||||||
|
self.non_image_ifd = Some(ifd);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interpret the current directory as an image.
|
/// Interpret the current directory as an image.
|
||||||
@@ -775,8 +788,15 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
TiffFormatError::ImageFileDirectoryNotFound,
|
TiffFormatError::ImageFileDirectoryNotFound,
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let ifd = self.read_directory(current_ifd)?;
|
if let Some(ifd) = &self.non_image_ifd {
|
||||||
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
self.image = Image::from_ref(&mut self.value_reader, ifd)?;
|
||||||
|
// Definitely sets an IFD but this works without unwraps.
|
||||||
|
self.image.ifd = self.non_image_ifd.take();
|
||||||
|
} else {
|
||||||
|
// Probably re-reading an image but that's fine.
|
||||||
|
let ifd = self.read_directory(current_ifd)?;
|
||||||
|
self.image = Image::from_reader(&mut self.value_reader, ifd)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1283,11 +1303,22 @@ 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 current_directory_ifd(&mut self) -> IfdDecoder<'_> {
|
||||||
|
// Special fallback. We do not want to error handle not having read a current directory, in
|
||||||
|
// particular as the behavior having a directory without tags will produce these errors
|
||||||
|
// anyways (most likely). Note that an empty directory is invalid in a TIFF.
|
||||||
|
static NO_IFD: Directory = Directory::empty();
|
||||||
|
|
||||||
|
let ifd = self
|
||||||
|
.non_image_ifd
|
||||||
|
.as_ref()
|
||||||
|
.or(self.image.ifd.as_ref())
|
||||||
|
.unwrap_or(&NO_IFD);
|
||||||
|
|
||||||
IfdDecoder {
|
IfdDecoder {
|
||||||
inner: tag_reader::TagReader {
|
inner: tag_reader::TagReader {
|
||||||
decoder: &mut self.value_reader,
|
decoder: &mut self.value_reader,
|
||||||
ifd: self.image.ifd.as_ref().unwrap(),
|
ifd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1328,25 +1359,25 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
/// Tries to retrieve a tag from the current image directory.
|
/// Tries to retrieve a tag from the current image directory.
|
||||||
/// 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>> {
|
||||||
self.image_ifd().find_tag(tag)
|
self.current_directory_ifd().find_tag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to retrieve a tag in the current image directory and convert it to the desired
|
/// Tries to retrieve a tag in the current image directory and convert it to the desired
|
||||||
/// unsigned type.
|
/// unsigned type.
|
||||||
pub fn find_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<T>> {
|
pub fn find_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<Option<T>> {
|
||||||
self.image_ifd().find_tag_unsigned(tag)
|
self.current_directory_ifd().find_tag_unsigned(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to retrieve a tag from the current image directory and convert it to the desired
|
/// Tries to retrieve a tag from the current image directory and convert it to the desired
|
||||||
/// unsigned type. Returns an error if the tag is not present.
|
/// unsigned type. Returns an error if the tag is not present.
|
||||||
pub fn get_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<T> {
|
pub fn get_tag_unsigned<T: TryFrom<u64>>(&mut self, tag: Tag) -> TiffResult<T> {
|
||||||
self.image_ifd().get_tag_unsigned(tag)
|
self.current_directory_ifd().get_tag_unsigned(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to retrieve a tag from the current image directory.
|
/// Tries to retrieve a tag from the current image directory.
|
||||||
/// Returns an error if the tag is not present
|
/// Returns an error if the tag is not present
|
||||||
pub fn get_tag(&mut self, tag: Tag) -> TiffResult<ifd::Value> {
|
pub fn get_tag(&mut self, tag: Tag) -> TiffResult<ifd::Value> {
|
||||||
self.image_ifd().get_tag(tag)
|
self.current_directory_ifd().get_tag(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult<u32> {
|
pub fn get_tag_u32(&mut self, tag: Tag) -> TiffResult<u32> {
|
||||||
@@ -1401,7 +1432,7 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn tag_iter(&mut self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + '_ {
|
pub fn tag_iter(&mut self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + '_ {
|
||||||
self.image_ifd().tag_iter()
|
self.current_directory_ifd().tag_iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ pub struct Directory {
|
|||||||
impl Directory {
|
impl Directory {
|
||||||
/// Create a directory in an initial state without entries. Note that an empty directory can
|
/// Create a directory in an initial state without entries. Note that an empty directory can
|
||||||
/// not be encoded in a file, it must contain at least one entry.
|
/// not be encoded in a file, it must contain at least one entry.
|
||||||
pub fn empty() -> Self {
|
pub const fn empty() -> Self {
|
||||||
Directory {
|
Directory {
|
||||||
entries: BTreeMap::new(),
|
entries: BTreeMap::new(),
|
||||||
next_ifd: None,
|
next_ifd: None,
|
||||||
|
|||||||
+1
-4
@@ -123,10 +123,7 @@ fn decode_subifds() {
|
|||||||
loop {
|
loop {
|
||||||
len += 1;
|
len += 1;
|
||||||
|
|
||||||
let position = decoder.ifd_pointer().unwrap();
|
if let Ok(subifd) = decoder.get_tag(Tag::SubIfd) {
|
||||||
let ifd = decoder.read_directory(position).unwrap();
|
|
||||||
|
|
||||||
if let Ok(subifd) = decoder.read_directory_tags(&ifd).get_tag(Tag::SubIfd) {
|
|
||||||
let prelen = subifds.len();
|
let prelen = subifds.len();
|
||||||
subifds.extend(subifd.into_ifd_vec().expect("Failed to decode SubIfd tag"));
|
subifds.extend(subifd.into_ifd_vec().expect("Failed to decode SubIfd tag"));
|
||||||
eprintln!("New roots: {:?}", &subifds[prelen..]);
|
eprintln!("New roots: {:?}", &subifds[prelen..]);
|
||||||
|
|||||||
Reference in new issue
Block a user