Expose interacting with secondary IFDs
This commit is contained in:
1 parent
f33c7be21c
commit
f5ab3b363b
2 files changed
+69
-1
No files matched your search
+31
-1
@@ -6,7 +6,7 @@ use std::mem;
|
|||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use super::stream::{ByteOrder, EndianReader};
|
use super::stream::{ByteOrder, EndianReader};
|
||||||
use crate::tags::{Tag, Type};
|
use crate::tags::{IfdPointer, Tag, Type};
|
||||||
use crate::{TiffError, TiffFormatError, TiffResult};
|
use crate::{TiffError, TiffFormatError, TiffResult};
|
||||||
|
|
||||||
use self::Value::{
|
use self::Value::{
|
||||||
@@ -130,6 +130,25 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Turn this value into an `IfdPointer`.
|
||||||
|
///
|
||||||
|
/// Notice that this does not take an argument, a 64-bit IFD is always allowed. If the
|
||||||
|
/// difference is crucial and you do not want to be permissive you're expected to filter this
|
||||||
|
/// out before.
|
||||||
|
///
|
||||||
|
/// For compatibility the smaller sized tags should always be allowed i.e. you might use a
|
||||||
|
/// non-bigtiff's directory and its tag types and move it straight to a bigtiff. For instance
|
||||||
|
/// the SubIFD tag is defined as `LONG or IFD`:
|
||||||
|
///
|
||||||
|
/// <https://web.archive.org/web/20181105221012/https://www.awaresystems.be/imaging/tiff/tifftags/subifds.html>
|
||||||
|
pub fn into_ifd_pointer(self) -> TiffResult<IfdPointer> {
|
||||||
|
match self {
|
||||||
|
Unsigned(val) | Ifd(val) => Ok(IfdPointer(val.into())),
|
||||||
|
IfdBig(val) => Ok(IfdPointer(val)),
|
||||||
|
_ => Err(TiffError::FormatError(TiffFormatError::InvalidTypeForTag)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn into_string(self) -> TiffResult<String> {
|
pub fn into_string(self) -> TiffResult<String> {
|
||||||
match self {
|
match self {
|
||||||
Ascii(val) => Ok(val),
|
Ascii(val) => Ok(val),
|
||||||
@@ -300,6 +319,17 @@ impl Value {
|
|||||||
_ => Err(TiffError::FormatError(TiffFormatError::InvalidTypeForTag)),
|
_ => Err(TiffError::FormatError(TiffFormatError::InvalidTypeForTag)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_ifd_vec(self) -> TiffResult<Vec<IfdPointer>> {
|
||||||
|
let vec = match self {
|
||||||
|
Unsigned(val) | Ifd(val) => return Ok(vec![IfdPointer(val.into())]),
|
||||||
|
IfdBig(val) => return Ok(vec![IfdPointer(val)]),
|
||||||
|
List(vec) => vec,
|
||||||
|
_ => return Err(TiffError::FormatError(TiffFormatError::InvalidTypeForTag)),
|
||||||
|
};
|
||||||
|
|
||||||
|
vec.into_iter().map(Self::into_ifd_pointer).collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@@ -765,6 +765,13 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
self.value_reader.reader.goto_offset(offset)
|
self.value_reader.reader.goto_offset(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read a directory from a known offset.
|
||||||
|
///
|
||||||
|
/// This may always modify the position of the reader.
|
||||||
|
pub fn read_directory(&mut self, ptr: IfdPointer) -> TiffResult<Directory> {
|
||||||
|
self.value_reader.read_directory(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
fn check_chunk_type(&self, expected: ChunkType) -> TiffResult<()> {
|
fn check_chunk_type(&self, expected: ChunkType) -> TiffResult<()> {
|
||||||
if expected != self.image().chunk_type {
|
if expected != self.image().chunk_type {
|
||||||
return Err(TiffError::UsageError(UsageError::InvalidChunkType(
|
return Err(TiffError::UsageError(UsageError::InvalidChunkType(
|
||||||
@@ -985,6 +992,37 @@ impl<R: Read + Seek> Decoder<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prepare reading tag values for some externally given directory.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// This method may be used to read the values of tags in directories that have been previously
|
||||||
|
/// read with [`Decoder::read_directory`].
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// use tiff::decoder::Decoder;
|
||||||
|
/// use tiff::tags::Tag;
|
||||||
|
///
|
||||||
|
/// # use std::io::Cursor;
|
||||||
|
/// # let mut data = Cursor::new(vec![0]);
|
||||||
|
/// let mut decoder = Decoder::new(&mut data).unwrap();
|
||||||
|
/// let sub_ifds = decoder.get_tag(Tag::SubIfd)?.into_ifd_vec()?;
|
||||||
|
///
|
||||||
|
/// for ifd in sub_ifds {
|
||||||
|
/// let subdir = decoder.read_directory(ifd)?;
|
||||||
|
/// let subfile = decoder.with_ifd(&subdir).find_tag(Tag::SubfileType)?;
|
||||||
|
/// // todo: handle the subfiles, e.g. thumbnails
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # Ok::<_, tiff::TiffError>(())
|
||||||
|
/// ```
|
||||||
|
pub fn with_ifd<'ifd>(&'ifd mut self, ifd: &'ifd Directory) -> IfdDecoder<'ifd> {
|
||||||
|
IfdDecoder {
|
||||||
|
decoder: &mut self.value_reader,
|
||||||
|
ifd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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>> {
|
||||||
|
|||||||
Reference in new issue
Block a user