1+ use std:: sync:: Arc ;
2+
13use async_tiff:: reader:: { AsyncFileReader , ObjectReader , PrefetchReader } ;
24use async_tiff:: TIFF ;
5+ use pyo3:: exceptions:: PyIndexError ;
36use pyo3:: prelude:: * ;
47use pyo3:: types:: PyType ;
58use pyo3_async_runtimes:: tokio:: future_into_py;
69use pyo3_object_store:: PyObjectStore ;
710
11+ use crate :: tile:: PyTile ;
812use crate :: PyImageFileDirectory ;
913
1014#[ pyclass( name = "TIFF" , frozen) ]
11- pub ( crate ) struct PyTIFF ( TIFF ) ;
15+ pub ( crate ) struct PyTIFF {
16+ tiff : TIFF ,
17+ reader : Arc < dyn AsyncFileReader > ,
18+ }
1219
1320#[ pymethods]
1421impl PyTIFF {
@@ -22,6 +29,7 @@ impl PyTIFF {
2229 prefetch : Option < u64 > ,
2330 ) -> PyResult < Bound < ' py , PyAny > > {
2431 let reader = ObjectReader :: new ( store. into_inner ( ) , path. into ( ) ) ;
32+ let object_reader = reader. clone ( ) ;
2533
2634 let cog_reader = future_into_py ( py, async move {
2735 let reader: Box < dyn AsyncFileReader > = if let Some ( prefetch) = prefetch {
@@ -33,14 +41,62 @@ impl PyTIFF {
3341 } else {
3442 Box :: new ( reader)
3543 } ;
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+ } )
3748 } ) ?;
3849 Ok ( cog_reader)
3950 }
4051
4152 #[ getter]
4253 fn ifds ( & self ) -> Vec < PyImageFileDirectory > {
43- let ifds = self . 0 . ifds ( ) ;
54+ let ifds = self . tiff . ifds ( ) ;
4455 ifds. as_ref ( ) . iter ( ) . map ( |ifd| ifd. clone ( ) . into ( ) ) . collect ( )
4556 }
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+ }
46102}
0 commit comments