Skip to content

Commit 3ac58b4

Browse files
committed
added doc example for exif, exif sample tiff and some sad error handling in ifd::from_tags
1 parent 06ebb91 commit 3ac58b4

File tree

3 files changed

+78
-4
lines changed

3 files changed

+78
-4
lines changed

src/ifd.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,11 +269,17 @@ impl ImageFileDirectory {
269269
Tag::Unknown(DOCUMENT_NAME) => document_name = Some(value.into_string()?),
270270
t => {
271271
if extra_tags_registry.contains(&t) {
272-
extra_tags_registry[&t].process_tag(t, value);
272+
extra_tags_registry[&t].process_tag(t, value).map_err(|e| {
273+
if let AsyncTiffError::InternalTIFFError(err) = e {
274+
err
275+
} else {
276+
// TODO fix error handling. This is bad
277+
TiffError::IntSizeError
278+
}
279+
})?;
273280
} else {
274281
other_tags.insert(tag, value);
275282
}
276-
277283
}
278284
};
279285
Ok::<_, TiffError>(())
@@ -645,6 +651,11 @@ impl ImageFileDirectory {
645651
self.model_tiepoint.as_deref()
646652
}
647653

654+
/// the registry holding extra tags
655+
pub fn extra_tags(&self) -> &ExtraTagsRegistry {
656+
&self.extra_tags
657+
}
658+
648659
/// Tags for which the tiff crate doesn't have a hard-coded enum variant.
649660
pub fn other_tags(&self) -> &HashMap<Tag, Value> {
650661
&self.other_tags

src/metadata/extra_tags.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,81 @@ use std::sync::Arc;
99

1010
/// Trait to implement for custom tags, such as Geo, EXIF, OME, etc
1111
/// your type should also implement `Clone`
12+
///
13+
/// ```
14+
/// # use std::sync::{LazyLock, OnceLock, Arc};
15+
/// # use std::env::current_dir;
16+
/// # use async_tiff::tiff::{Value, tags::Tag};
17+
/// # use async_tiff::error::AsyncTiffResult;
18+
/// # use async_tiff::reader::{ObjectReader, AsyncFileReader};
19+
/// use async_tiff::metadata::{ExtraTags, ExtraTagsRegistry, TiffMetadataReader};
20+
/// # use object_store::local::LocalFileSystem;
21+
/// // see https://www.media.mit.edu/pia/Research/deepview/exif.html#ExifTags
22+
/// // or exif spec: https://www.cipa.jp/std/documents/download_e.html?DC-008-Translation-2023-E
23+
/// // / all tags processed by your extension
24+
/// pub static EXIF_TAGS: LazyLock<Vec<Tag>> = LazyLock::new(|| vec![
25+
/// Tag::Unknown(34665), // Exif IFD pointer
26+
/// Tag::Unknown(34853), // GPS IFD pointer
27+
/// Tag::Unknown(40965), // Interoperability IFD pointer
28+
/// ]);
29+
///
30+
/// // / the struct that stores the data (using interior mutability)
31+
/// #[derive(Debug, Clone, Default)]
32+
/// pub struct ExifTags {
33+
/// pub exif: OnceLock<u32>,
34+
/// pub gps: OnceLock<u32>,
35+
/// pub interop: OnceLock<u32>,
36+
/// }
37+
///
38+
/// impl ExtraTags for ExifTags {
39+
/// fn tags(&self) -> &'static [Tag] {
40+
/// &EXIF_TAGS
41+
/// }
42+
///
43+
/// fn process_tag(&self, tag:Tag, value: Value) -> AsyncTiffResult<()> {
44+
/// match tag {
45+
/// Tag::Unknown(34665) => self.exif.set(value.into_u32()?).unwrap(),
46+
/// Tag::Unknown(34853) => self.gps.set(value.into_u32()?).unwrap(),
47+
/// Tag::Unknown(40965) => self.interop.set(value.into_u32()?).unwrap(),
48+
/// _ => {}
49+
/// }
50+
/// Ok(())
51+
/// }
52+
/// }
53+
///
54+
/// #[tokio::main]
55+
/// async fn main() {
56+
/// let mut registry = ExtraTagsRegistry::new();
57+
/// registry.register(Arc::new(ExifTags::default()));
58+
/// # let store = Arc::new(LocalFileSystem::new_with_prefix(current_dir().unwrap()).unwrap());
59+
/// # let path = "tests/sample-exif.tiff";
60+
/// let reader = Arc::new(ObjectReader::new(store.clone(), path.into())) as Arc<dyn AsyncFileReader>;
61+
/// let mut metadata_reader = TiffMetadataReader::try_open(&reader).await.unwrap();
62+
/// let ifd = metadata_reader.read_next_ifd(&reader, registry).await.unwrap().unwrap();
63+
/// // access by any of our registered tags
64+
/// let exif = ifd.extra_tags()[&EXIF_TAGS[0]].clone().as_any_arc().downcast::<ExifTags>().unwrap();
65+
/// assert!(exif.exif.get().is_some());
66+
/// assert!(exif.gps.get().is_some());
67+
/// // our image doesn't have interop info
68+
/// assert!(exif.interop.get().is_none());
69+
/// }
70+
/// ```
1271
// Send + Sync are required for Python, where `dyn ExtraTags` needs `Send` and `Sync`
1372
pub trait ExtraTags: ExtraTagsBlankets + Any + Debug + Send + Sync {
1473
/// a list of tags this entry processes
74+
///
1575
/// e.g. for Geo this would be [34735, 34736, 34737]
1676
fn tags(&self) -> &'static [Tag];
1777
/// process a single tag, using internal mutability if needed
1878
fn process_tag(&self, tag: Tag, value: Value) -> AsyncTiffResult<()>;
1979
}
2080

2181
// we need to do a little dance to do an object-safe deep clone
22-
// https://stackoverflow.com/a/30353928/14681457
23-
// also object-safe type conversions for downcasting
82+
// https://stackoverflow.com/a/30353928/14681457 also object-safe type
83+
// conversions for downcasting.
84+
//
85+
// This works since blanket implementations are done on concrete types and only
86+
// their signatures (function pointer) will end up in the vtable
2487
pub trait ExtraTagsBlankets {
2588
fn clone_arc(&self) -> Arc<dyn ExtraTags>;
2689
fn as_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;

tests/sample-exif.tiff

257 KB
Binary file not shown.

0 commit comments

Comments
 (0)