1
+ use std:: sync:: Arc ;
2
+
1
3
use async_tiff:: reader:: { AsyncFileReader , ObjectReader , PrefetchReader } ;
2
4
use async_tiff:: TIFF ;
5
+ use pyo3:: exceptions:: PyIndexError ;
3
6
use pyo3:: prelude:: * ;
4
7
use pyo3:: types:: PyType ;
5
8
use pyo3_async_runtimes:: tokio:: future_into_py;
6
9
use pyo3_object_store:: PyObjectStore ;
7
10
11
+ use crate :: tile:: PyTile ;
8
12
use crate :: PyImageFileDirectory ;
9
13
10
14
#[ pyclass( name = "TIFF" , frozen) ]
11
- pub ( crate ) struct PyTIFF ( TIFF ) ;
15
+ pub ( crate ) struct PyTIFF {
16
+ tiff : TIFF ,
17
+ reader : Arc < dyn AsyncFileReader > ,
18
+ }
12
19
13
20
#[ pymethods]
14
21
impl PyTIFF {
@@ -22,6 +29,7 @@ impl PyTIFF {
22
29
prefetch : Option < u64 > ,
23
30
) -> PyResult < Bound < ' py , PyAny > > {
24
31
let reader = ObjectReader :: new ( store. into_inner ( ) , path. into ( ) ) ;
32
+ let object_reader = reader. clone ( ) ;
25
33
26
34
let cog_reader = future_into_py ( py, async move {
27
35
let reader: Box < dyn AsyncFileReader > = if let Some ( prefetch) = prefetch {
@@ -33,14 +41,62 @@ impl PyTIFF {
33
41
} else {
34
42
Box :: new ( reader)
35
43
} ;
36
- Ok ( PyTIFF ( TIFF :: try_open ( reader) . await . unwrap ( ) ) )
44
+ Ok ( PyTIFF {
45
+ tiff : TIFF :: try_open ( reader) . await . unwrap ( ) ,
46
+ reader : Arc :: new ( object_reader) ,
47
+ } )
37
48
} ) ?;
38
49
Ok ( cog_reader)
39
50
}
40
51
41
52
#[ getter]
42
53
fn ifds ( & self ) -> Vec < PyImageFileDirectory > {
43
- let ifds = self . 0 . ifds ( ) ;
54
+ let ifds = self . tiff . ifds ( ) ;
44
55
ifds. as_ref ( ) . iter ( ) . map ( |ifd| ifd. clone ( ) . into ( ) ) . collect ( )
45
56
}
57
+
58
+ fn fetch_tile < ' py > (
59
+ & ' py self ,
60
+ py : Python < ' py > ,
61
+ x : usize ,
62
+ y : usize ,
63
+ z : usize ,
64
+ ) -> PyResult < Bound < ' py , PyAny > > {
65
+ let reader = self . reader . clone ( ) ;
66
+ let ifd = self
67
+ . tiff
68
+ . ifds ( )
69
+ . as_ref ( )
70
+ . get ( z)
71
+ . ok_or_else ( || PyIndexError :: new_err ( format ! ( "No IFD found for z={}" , z) ) ) ?
72
+ // TODO: avoid this clone; add Arc to underlying rust code?
73
+ . clone ( ) ;
74
+ future_into_py ( py, async move {
75
+ let tile = ifd. fetch_tile ( x, y, reader. as_ref ( ) ) . await . unwrap ( ) ;
76
+ Ok ( PyTile :: new ( tile) )
77
+ } )
78
+ }
79
+
80
+ fn fetch_tiles < ' py > (
81
+ & ' py self ,
82
+ py : Python < ' py > ,
83
+ x : Vec < usize > ,
84
+ y : Vec < usize > ,
85
+ z : usize ,
86
+ ) -> PyResult < Bound < ' py , PyAny > > {
87
+ let reader = self . reader . clone ( ) ;
88
+ let ifd = self
89
+ . tiff
90
+ . ifds ( )
91
+ . as_ref ( )
92
+ . get ( z)
93
+ . ok_or_else ( || PyIndexError :: new_err ( format ! ( "No IFD found for z={}" , z) ) ) ?
94
+ // TODO: avoid this clone; add Arc to underlying rust code?
95
+ . clone ( ) ;
96
+ future_into_py ( py, async move {
97
+ let tiles = ifd. fetch_tiles ( & x, & y, reader. as_ref ( ) ) . await . unwrap ( ) ;
98
+ let py_tiles = tiles. into_iter ( ) . map ( PyTile :: new) . collect :: < Vec < _ > > ( ) ;
99
+ Ok ( py_tiles)
100
+ } )
101
+ }
46
102
}
0 commit comments