-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for iterating over all tags #255
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,25 @@ | ||
use std::collections::{HashMap, HashSet}; | ||
use std::io::{self, Read, Seek}; | ||
|
||
use crate::{ | ||
bytecast, ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError, | ||
}; | ||
use either::Either; | ||
|
||
use self::ifd::Directory; | ||
use self::image::Image; | ||
use crate::decoder::tag_iter::TagIter; | ||
use crate::tags::{ | ||
CompressionMethod, PhotometricInterpretation, PlanarConfiguration, Predictor, SampleFormat, | ||
Tag, Type, | ||
}; | ||
use crate::{ | ||
bytecast, ColorType, TiffError, TiffFormatError, TiffResult, TiffUnsupportedError, UsageError, | ||
}; | ||
|
||
use self::ifd::Directory; | ||
use self::image::Image; | ||
use self::stream::{ByteOrder, EndianReader, SmartReader}; | ||
|
||
pub mod ifd; | ||
mod image; | ||
mod stream; | ||
mod tag_iter; | ||
mod tag_reader; | ||
|
||
/// Result of a decoding process | ||
|
@@ -895,6 +898,18 @@ impl<R: Read + Seek> Decoder<R> { | |
self.get_tag(tag)?.into_string() | ||
} | ||
|
||
pub fn tag_iter(&mut self) -> impl Iterator<Item = TiffResult<(Tag, ifd::Value)>> + '_ { | ||
match self.image().ifd.as_ref() { | ||
None => Either::Left(std::iter::empty()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know when this case happens? Wondering if we should return None or an error rather than an empty iterator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no idea, honestly. I think from a developer perspective, it is more convenient to have an empty iterator instead of having to deal with an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I went through the existing code. It should be impossible for |
||
Some(ifd) => Either::Right(TagIter::new( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than constructing a TagIter here, I think we could directly return: ifd.clone().into_iter().map(...) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried but failed to make the borrow checker happy with this approach. Happy to change it if you can provide a working solution. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was able to get it to work with: self.image.ifd.as_ref().unwrap().iter().map(|(tag, entry)| {
entry
.val(&self.limits, self.bigtiff, &mut self.reader)
.map(|value| (*tag, value))
}) (You have to directly access the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, cool, thx! I incorporated your changes and pushed the branch. |
||
ifd.clone(), | ||
&self.limits, | ||
self.bigtiff, | ||
&mut self.reader, | ||
)), | ||
} | ||
} | ||
|
||
fn check_chunk_type(&self, expected: ChunkType) -> TiffResult<()> { | ||
if expected != self.image().chunk_type { | ||
return Err(TiffError::UsageError(UsageError::InvalidChunkType( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use std::collections::hash_map::IntoIter; | ||
use std::io::{Read, Seek}; | ||
|
||
use crate::decoder::ifd::{Directory, Value}; | ||
use crate::decoder::stream::SmartReader; | ||
use crate::decoder::{ifd, Limits}; | ||
use crate::tags::Tag; | ||
use crate::TiffResult; | ||
|
||
pub(crate) struct TagIter<'a, R> | ||
where | ||
R: Read + Seek, | ||
{ | ||
iter: IntoIter<Tag, ifd::Entry>, | ||
limits: &'a Limits, | ||
bigtiff: bool, | ||
reader: &'a mut SmartReader<R>, | ||
} | ||
|
||
impl<'a, R> TagIter<'a, R> | ||
where | ||
R: Read + Seek, | ||
{ | ||
pub fn new( | ||
directory: Directory, | ||
limits: &'a Limits, | ||
bigtiff: bool, | ||
reader: &'a mut SmartReader<R>, | ||
) -> Self { | ||
Self { | ||
iter: directory.into_iter(), | ||
limits, | ||
bigtiff, | ||
reader, | ||
} | ||
} | ||
} | ||
|
||
impl<'a, R> Iterator for TagIter<'a, R> | ||
where | ||
R: Read + Seek, | ||
{ | ||
type Item = TiffResult<(Tag, Value)>; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
self.iter.next().map(|(tag, entry)| { | ||
entry | ||
.val(self.limits, self.bigtiff, self.reader) | ||
.map(|value| (tag, value)) | ||
}) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also add a short doc comment explaining what this method does? Something like "Returns an iterator over all tags in the current image"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!