Skip to content

Commit a7c6a7d

Browse files
committed
feat:tag_registry added tag registry core functionality
1 parent 418dbb3 commit a7c6a7d

File tree

7 files changed

+49
-16
lines changed

7 files changed

+49
-16
lines changed

python/src/tiff.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl PyTIFF {
3737
.map_err(|err| PyFileNotFoundError::new_err(err.to_string()))?;
3838
let mut metadata_reader = TiffMetadataReader::try_open(&metadata_fetch).await.unwrap();
3939
let ifds = metadata_reader
40-
.read_all_ifds(&metadata_fetch)
40+
.read_all_ifds(&metadata_fetch, Default::default())
4141
.await
4242
.unwrap();
4343
let tiff = TIFF::new(ifds);

src/cog.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ mod test {
4444
.await
4545
.unwrap();
4646
let ifds = metadata_reader
47-
.read_all_ifds(&prefetch_reader)
47+
.read_all_ifds(&prefetch_reader, Default::default())
4848
.await
4949
.unwrap();
5050
let tiff = TIFF::new(ifds);

src/ifd.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashMap;
1+
use std::collections::{HashMap, HashSet};
22
use std::fmt::Debug;
33
use std::ops::Range;
44
use std::sync::Arc;
@@ -20,15 +20,18 @@ use crate::tile::Tile;
2020
const DOCUMENT_NAME: u16 = 269;
2121

2222
/// Trait to implement for custom tags, such as Geo, EXIF, OME, etc
23-
pub trait ExtraTags: ExtraTagsCloneArc + std::any::Any + Debug {
23+
/// your type should also implement `Clone`
24+
// Send + Sync are required for Python, where `dyn ExtraTags` needs `Send` and `Sync`
25+
pub trait ExtraTags: ExtraTagsCloneArc + std::any::Any + Debug + Send + Sync {
2426
/// a list of tags this entry processes
2527
/// e.g. for Geo this would be [34735, 34736, 34737]
2628
fn tags(&self) -> &'static [Tag];
2729
/// process a single tag
2830
fn process_tag(&mut self, tag: u16, value: Value) -> AsyncTiffResult<()>;
2931
}
3032

31-
//
33+
// we need to do a little dance to do an object-safe deep clone
34+
// https://stackoverflow.com/a/30353928/14681457
3235
pub trait ExtraTagsCloneArc {
3336
fn clone_arc(&self) -> Arc<dyn ExtraTags>;
3437
}
@@ -46,6 +49,11 @@ where
4649
pub struct ExtraTagsRegistry(HashMap<Tag, Arc<dyn ExtraTags>>);
4750

4851
impl ExtraTagsRegistry {
52+
/// Create a new, empty `ExtraTagsRegistry`
53+
pub fn new() -> Self{
54+
Self(HashMap::new())
55+
}
56+
/// Register an ExtraTags so their tags are parsed and stored in the ifd's `extra_tags``
4957
pub fn register(&mut self, tags: Arc<dyn ExtraTags>) -> AsyncTiffResult<()> {
5058
// check for duplicates
5159
for tag in tags.tags() {
@@ -59,6 +67,32 @@ impl ExtraTagsRegistry {
5967
}
6068
Ok(())
6169
}
70+
71+
/// deep clone so we have different registries per IFD
72+
pub(crate) fn deep_clone(&self) -> Self {
73+
let mut new_registry = ExtraTagsRegistry::new();
74+
75+
76+
// we need to do some magic, because we can have multiple tags pointing to the same arc
77+
let mut seen = HashSet::new();
78+
for extra_tags in self.0.values() {
79+
// only add if this is the first encountered reference to this arc
80+
// (using thin pointer equality: https://stackoverflow.com/a/67114787/14681457 ; https://github.com/rust-lang/rust/issues/46139#issuecomment-346971153)
81+
if seen.insert(Arc::as_ptr(extra_tags) as *const ()) {
82+
if let Err(e) = new_registry.register(extra_tags.clone_arc()) {
83+
panic!("{e}");
84+
}
85+
}
86+
}
87+
88+
new_registry
89+
}
90+
}
91+
92+
impl Default for ExtraTagsRegistry {
93+
fn default() -> Self {
94+
Self::new() // add e.g. geo tags later
95+
}
6296
}
6397

6498
/// An ImageFileDirectory representing Image content

src/metadata/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
//!
4141
//! // Read all IFDs out of the source.
4242
//! let ifds = metadata_reader
43-
//! .read_all_ifds(&prefetch_reader)
43+
//! .read_all_ifds(&prefetch_reader, Default::default())
4444
//! .await
4545
//! .unwrap();
4646
//! # })

src/metadata/reader.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,13 @@ impl TiffMetadataReader {
111111
pub async fn read_next_ifd<F: MetadataFetch>(
112112
&mut self,
113113
fetch: &F,
114+
extra_tags_registry: ExtraTagsRegistry,
114115
) -> AsyncTiffResult<Option<ImageFileDirectory>> {
115116
if let Some(ifd_start) = self.next_ifd_offset {
116117
let ifd_reader =
117118
ImageFileDirectoryReader::open(fetch, ifd_start, self.bigtiff, self.endianness)
118119
.await?;
119-
let ifd = ifd_reader.read(fetch).await?;
120+
let ifd = ifd_reader.read(fetch, extra_tags_registry).await?;
120121
let next_ifd_offset = ifd_reader.finish(fetch).await?;
121122
self.next_ifd_offset = next_ifd_offset;
122123
Ok(Some(ifd))
@@ -129,9 +130,11 @@ impl TiffMetadataReader {
129130
pub async fn read_all_ifds<F: MetadataFetch>(
130131
&mut self,
131132
fetch: &F,
133+
extra_tags_registry: ExtraTagsRegistry,
132134
) -> AsyncTiffResult<Vec<ImageFileDirectory>> {
133135
let mut ifds = vec![];
134-
while let Some(ifd) = self.read_next_ifd(fetch).await? {
136+
// deep clone the extra_tags_registry so we can have different values
137+
while let Some(ifd) = self.read_next_ifd(fetch, extra_tags_registry.deep_clone()).await? {
135138
ifds.push(ifd);
136139
}
137140
Ok(ifds)
@@ -158,8 +161,6 @@ pub struct ImageFileDirectoryReader {
158161
ifd_entry_byte_size: u64,
159162
/// The number of bytes that the value for the number of tags takes up.
160163
tag_count_byte_size: u64,
161-
/// Registry for parsing extra tags
162-
extra_tags_registry: ExtraTagsRegistry,
163164
}
164165

165166
impl ImageFileDirectoryReader {
@@ -169,7 +170,6 @@ impl ImageFileDirectoryReader {
169170
ifd_start_offset: u64,
170171
bigtiff: bool,
171172
endianness: Endianness,
172-
extra_tags_registry: ExtraTagsRegistry,
173173
) -> AsyncTiffResult<Self> {
174174
let mut cursor = MetadataCursor::new_with_offset(fetch, endianness, ifd_start_offset);
175175

@@ -198,7 +198,6 @@ impl ImageFileDirectoryReader {
198198
tag_count,
199199
tag_count_byte_size,
200200
ifd_start_offset,
201-
extra_tags_registry,
202201
})
203202
}
204203

@@ -225,13 +224,13 @@ impl ImageFileDirectoryReader {
225224
///
226225
/// Keep in mind that you'll still need to call [`finish`][Self::finish] to get the byte offset
227226
/// of the next IFD.
228-
pub async fn read<F: MetadataFetch>(&self, fetch: &F) -> AsyncTiffResult<ImageFileDirectory> {
227+
pub async fn read<F: MetadataFetch>(&self, fetch: &F, extra_tags_registry: ExtraTagsRegistry) -> AsyncTiffResult<ImageFileDirectory> {
229228
let mut tags = HashMap::with_capacity(self.tag_count as usize);
230229
for tag_idx in 0..self.tag_count {
231230
let (tag, value) = self.read_tag(fetch, tag_idx).await?;
232231
tags.insert(tag, value);
233232
}
234-
ImageFileDirectory::from_tags(tags, self.endianness, self.extra_tags_registry)
233+
ImageFileDirectory::from_tags(tags, self.endianness, extra_tags_registry)
235234
}
236235

237236
/// Finish this reader, reading the byte offset of the next IFD

tests/image_tiff/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ pub(crate) async fn open_tiff(filename: &str) -> TIFF {
1414
let reader = Arc::new(ObjectReader::new(store.clone(), path.as_str().into()))
1515
as Arc<dyn AsyncFileReader>;
1616
let mut metadata_reader = TiffMetadataReader::try_open(&reader).await.unwrap();
17-
let ifds = metadata_reader.read_all_ifds(&reader).await.unwrap();
17+
let ifds = metadata_reader.read_all_ifds(&reader, Default::default()).await.unwrap();
1818
TIFF::new(ifds)
1919
}

tests/util/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub(crate) async fn open_remote_tiff(url: &str) -> TIFF {
1717
.await
1818
.unwrap();
1919
let ifds = metadata_reader
20-
.read_all_ifds(&prefetch_reader)
20+
.read_all_ifds(&prefetch_reader, Default::default())
2121
.await
2222
.unwrap();
2323
TIFF::new(ifds)

0 commit comments

Comments
 (0)