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:
1 parent
73f066c09d
commit
eb6275547d
4 files changed
+75
-3
No files matched your search
@@ -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:
|
||||||
|
|||||||
@@ -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_,
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user