Compare commits

...
Author SHA1 Message Date
Andreas Molzer 51ec671e3a Add checkpoint, storing an IFD offset of a tiff 2020-12-08 21:01:21 +01:00
+53 -1
View File
@@ -198,6 +198,7 @@ where
bigtiff: bool, bigtiff: bool,
limits: Limits, limits: Limits,
next_ifd: Option<u64>, next_ifd: Option<u64>,
current_ifd: Option<u64>,
ifd: Option<Directory>, ifd: Option<Directory>,
width: u32, width: u32,
height: u32, height: u32,
@@ -209,6 +210,11 @@ where
strip_decoder: Option<StripDecodeState>, strip_decoder: Option<StripDecodeState>,
} }
/// Stores state necessary to seek back (or forward) to particular part of the tiff.
pub struct Checkpoint {
offset: u64,
}
trait Wrapping { trait Wrapping {
fn wrapping_add(&self, other: Self) -> Self; fn wrapping_add(&self, other: Self) -> Self;
} }
@@ -313,6 +319,7 @@ impl<R: Read + Seek> Decoder<R> {
bigtiff: false, bigtiff: false,
limits: Default::default(), limits: Default::default(),
next_ifd: None, next_ifd: None,
current_ifd: None,
ifd: None, ifd: None,
width: 0, width: 0,
height: 0, height: 0,
@@ -585,6 +592,44 @@ impl<R: Read + Seek> Decoder<R> {
self.reader.seek(io::SeekFrom::Start(offset)).map(|_| ()) self.reader.seek(io::SeekFrom::Start(offset)).map(|_| ())
} }
/// Retrieve a checkpoint that allows seeking before the TIFF header.
///
/// This is a special checkpoint where the caller should call `init` after restoring the
/// checkpoint and no ifd is being read.
pub fn checkpoint_init(&self) -> Checkpoint {
Checkpoint { offset: Checkpoint::INITIAL_OFFSET }
}
/// Retrieve a `Checkpoint` that can be used to seek to the current image directory.
pub fn checkpoint(&self) -> Checkpoint {
match self.current_ifd {
None => self.checkpoint_init(),
Some(offset) => Checkpoint { offset },
}
}
/// Get the next image directory as a checkpoint.
///
/// This allows jumping forward to the next image directory later, without needing to pay the
/// additional cost of parsing it right away.
pub fn checkpoint_next(&self) -> Option<Checkpoint> {
match self.next_ifd {
None => None,
Some(offset) => Some(Checkpoint { offset })
}
}
/// Restore the state of a previous checkpoint.
pub fn restore(&mut self, checkpoint: &Checkpoint) -> TiffResult<()> {
if checkpoint.offset == Checkpoint::INITIAL_OFFSET {
self.goto_offset_u64(0)?;
Ok(())
} else {
self.next_ifd = Some(checkpoint.offset);
self.next_image()
}
}
/// Reads a IFD entry. /// Reads a IFD entry.
// An IFD entry has four fields: // An IFD entry has four fields:
// //
@@ -620,7 +665,10 @@ impl<R: Read + Seek> Decoder<R> {
TiffFormatError::ImageFileDirectoryNotFound, TiffFormatError::ImageFileDirectoryNotFound,
)) ))
} }
Some(offset) => self.goto_offset_u64(offset)?, Some(offset) => {
self.goto_offset_u64(offset)?;
self.current_ifd = Some(offset);
}
} }
let num_tags = if self.bigtiff { let num_tags = if self.bigtiff {
self.read_long8()? self.read_long8()?
@@ -1117,3 +1165,7 @@ impl<R: Read + Seek> Decoder<R> {
Ok(result) Ok(result)
} }
} }
impl Checkpoint {
const INITIAL_OFFSET: u64 = 0;
}