Encode values immediately
This currently avoids buffering the collection, but not buffering them individually where we still format it into a byte vector. The main drive here is making the DirectoryEncoder less dependent on the values. That is, it should be concerned with the Entry representation of values only. A few decoders expect all values to strictly follow the image directory and the data layout of such files should be controllable by the user. This could be achieved by encoding dummy entries which are later corrected once the actual item is known by seeking back and writing the directory anew. By no longer assuming values to be available on finishing a directory we also prepare an interface that encodes an existing directory.
This commit is contained in:
1 parent
525bb2b9b1
commit
f6e2aeffe5
2 files changed
+13
-15
No files matched your search
+11
-13
@@ -2,7 +2,6 @@ pub use tiff_value::*;
|
||||
|
||||
use std::{
|
||||
cmp,
|
||||
collections::BTreeMap,
|
||||
io::{self, Seek, Write},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
@@ -220,9 +219,9 @@ pub struct DirectoryEncoder<'a, W: 'a + Write + Seek, K: TiffKind> {
|
||||
chained_ifd_pos: Option<NonZeroU64>,
|
||||
/// An output to write the `next` field offset on completion.
|
||||
write_chain: Option<&'a mut NonZeroU64>,
|
||||
kind: PhantomData<K>,
|
||||
// We use BTreeMap to make sure tags are written in correct order
|
||||
directory: Directory,
|
||||
ifd: BTreeMap<u16, DirectoryEntry<K::OffsetType>>,
|
||||
dropped: bool,
|
||||
}
|
||||
|
||||
@@ -235,43 +234,42 @@ impl<'a, W: 'a + Write + Seek, K: TiffKind> DirectoryEncoder<'a, W, K> {
|
||||
chain_into: Option<&'a mut NonZeroU64>,
|
||||
) -> TiffResult<Self> {
|
||||
writer.pad_word_boundary()?; // TODO: Do we need to adjust this for BigTiff?
|
||||
Ok(DirectoryEncoder {
|
||||
Ok(Self {
|
||||
writer,
|
||||
chained_ifd_pos,
|
||||
write_chain: chain_into,
|
||||
kind: PhantomData,
|
||||
directory: Directory::empty(),
|
||||
ifd: BTreeMap::new(),
|
||||
dropped: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Write a single ifd tag.
|
||||
pub fn write_tag<T: TiffValue>(&mut self, tag: Tag, value: T) -> TiffResult<()> {
|
||||
// Encodes the value if necessary. In the current bytes all integers are taken as native
|
||||
// endian and thus transparent but this keeps the interface generic.
|
||||
let mut bytes = Vec::with_capacity(value.bytes());
|
||||
{
|
||||
let mut writer = TiffWriter::new(&mut bytes);
|
||||
value.write(&mut writer)?;
|
||||
}
|
||||
|
||||
self.ifd.insert(
|
||||
tag.to_u16(),
|
||||
DirectoryEntry {
|
||||
let entry = Self::write_value(
|
||||
&mut self.writer,
|
||||
&DirectoryEntry {
|
||||
data_type: <T>::FIELD_TYPE,
|
||||
count: value.count().try_into()?,
|
||||
data: bytes,
|
||||
},
|
||||
);
|
||||
)?;
|
||||
|
||||
self.directory.extend([(tag, entry)]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_directory(&mut self) -> TiffResult<u64> {
|
||||
// Start by turning all buffered unwritten values into entries.
|
||||
for (&tag, value) in &self.ifd {
|
||||
let entry = Self::write_value(&mut self.writer, value)?;
|
||||
self.directory.extend([(Tag::Unknown(tag), entry)]);
|
||||
}
|
||||
|
||||
let offset = self.writer.offset();
|
||||
K::write_entry_count(self.writer, self.directory.len())?;
|
||||
|
||||
|
||||
Reference in new issue
Block a user