Build Directory FromIterator

This enables a test for the encoder's DirectoryOffset but it seems to
fit nicely with the current design, too.
This commit is contained in:
A. Molzer committed 2025-11-12 01:21:53 +01:00
1 parent 73f066c09d
commit eb6275547d
4 files changed
+75 -3

No files matched your search

+4
View File
@@ -1,3 +1,7 @@
# Version 0.10.4 (unreleased)
- `Directory` now implements `FromIterator<(Tag, Value)>`.
# Version 0.10.3 # Version 0.10.3
New features: New features:
+8
View File
@@ -332,6 +332,12 @@ impl Value {
} }
} }
/// A combination of type, count, and offset.
///
/// In a TIFF the data offset portion of an entry is used for inline data in case the length of the
/// encoded value does not exceed the size of the offset field. Since the size of the offset field
/// depends on the file kind (4 bytes for standard TIFF, 8 bytes for BigTIFF) the interpretation of
/// this struct is only complete in combination with file metadata.
#[derive(Clone)] #[derive(Clone)]
pub struct Entry { pub struct Entry {
type_: Type, type_: Type,
@@ -349,12 +355,14 @@ impl ::std::fmt::Debug for Entry {
} }
impl Entry { impl Entry {
/// Create a new entry fit to be added to a standard TIFF IFD.
pub fn new(type_: Type, count: u32, offset: [u8; 4]) -> Entry { pub fn new(type_: Type, count: u32, offset: [u8; 4]) -> Entry {
let mut entry_off = [0u8; 8]; let mut entry_off = [0u8; 8];
entry_off[..4].copy_from_slice(&offset); entry_off[..4].copy_from_slice(&offset);
Entry::new_u64(type_, count.into(), entry_off) Entry::new_u64(type_, count.into(), entry_off)
} }
/// Create a new entry with data for a Big TIFF IFD.
pub fn new_u64(type_: Type, count: u64, offset: [u8; 8]) -> Entry { pub fn new_u64(type_: Type, count: u64, offset: [u8; 8]) -> Entry {
Entry { Entry {
type_, type_,
+8
View File
@@ -140,6 +140,14 @@ impl fmt::Debug for Directory {
} }
} }
impl core::iter::FromIterator<(Tag, Entry)> for Directory {
fn from_iter<T: IntoIterator<Item = (Tag, Entry)>>(iter: T) -> Self {
let mut dir = Directory::empty();
dir.extend(iter);
dir
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Directory; use super::Directory;
+55 -3
View File
@@ -821,17 +821,39 @@ impl<K: TiffKind> DirectoryOffset<K> {
/// - the extent of the directory would overflow the file length. This returns a /// - the extent of the directory would overflow the file length. This returns a
/// [`TiffError::UsageError`]. /// [`TiffError::UsageError`].
/// ///
/// The library does *not* validate the contents or offset in any way, it just performs the
/// necessary math assuming the data is an accurate representation of existing content.
///
/// # Examples /// # Examples
/// ///
/// If you have any custom way of writing a directory to a file that can not go through the
/// usual [`TiffEncoder::extra_directory`] then you can reconstruct the offset information as
/// long as you provide all the necessary data to the library. You can then use it as a parent
/// directory, i.e. have the library overwrite its `next` field.
///
/// ``` /// ```
/// use tiff::{
/// encoder::{TiffEncoder, DirectoryOffset},
/// Directory,
/// tags::IfdPointer,
/// };
///
/// # let mut file = std::io::Cursor::new(Vec::new()); /// # let mut file = std::io::Cursor::new(Vec::new());
/// let mut tiff = TiffEncoder::new(&mut file)?; /// let mut tiff = TiffEncoder::new(&mut file)?;
/// ///
/// // … write custom data with /// // … some custom data writes, assume we know where a directory was written
/// # fn reconstruction_of_your_directory() -> Directory { Directory::from_iter([]) }
/// let known_offset = IfdPointer(1024);
/// let known_contents: Directory = reconstruction_of_your_directory();
/// ///
/// let also_dir = DirectoryOffset::new(&known_)?; /// let reconstructed = DirectoryOffset::new(known_offset, &known_contents)?;
/// ///
/// # Ok::<_, crate::error::TiffError>(()) /// // Now we can use it as if the directory was written by the `TiffEncoder` itself.
/// let mut chain = tiff.extra_directory()?;
/// chain.set_parent(&reconstructed);
/// chain.finish_with_offsets()?;
///
/// # Ok::<_, tiff::TiffError>(())
/// ``` /// ```
pub fn new(pointer: IfdPointer, dir: &Directory) -> TiffResult<Self> { pub fn new(pointer: IfdPointer, dir: &Directory) -> TiffResult<Self> {
let offset = K::convert_offset(pointer.0)?; let offset = K::convert_offset(pointer.0)?;
@@ -921,3 +943,33 @@ impl TiffKind for TiffKindBig {
slice slice
} }
} }
#[test]
fn directory_offset_new_equivalent_to_writing() {
type K = TiffKindStandard;
let dir = Directory::from_iter(vec![
(
Tag::ImageWidth,
Entry::new(Type::LONG, 1, 100u32.to_ne_bytes()),
),
(
Tag::ImageLength,
Entry::new(Type::LONG, 1, 200u32.to_ne_bytes()),
),
]);
let data = std::io::Cursor::new(vec![]);
let mut file = TiffEncoder::new(data).unwrap();
let mut as_dir_encoder = file.extra_directory().unwrap();
as_dir_encoder.extend_from(&dir);
let dir_extent = as_dir_encoder.finish_with_offsets().unwrap();
// Check we can recreate the extent had we written ourselves.
let synth = DirectoryOffset::<K>::new(dir_extent.pointer, &dir).unwrap();
assert_eq!(synth.pointer, dir_extent.pointer);
assert_eq!(synth.offset, dir_extent.offset);
assert_eq!(synth.ifd_chain, dir_extent.ifd_chain);
}