@@ -18,18 +18,18 @@ Main `rio_tiler.io` Abstract Base Class.
18
18
19
19
- ** bounds** : Dataset's bounding box. Not in the ` __init__ ` method.
20
20
- ** crs** : dataset's crs. Not in the ` __init__ ` method.
21
- - ** geographic_crs** : CRS to use as geographic coordinate system. Defaults to WGS84. Not in the ` __init__ ` method.
21
+ - ** transform** : dataset's Affine transform. Not in the ` __init__ ` method.
22
+ - ** height** : dataset's height. Not in the ` __init__ ` method.
23
+ - ** width** : dataset's width. Not in the ` __init__ ` method.
24
+
22
25
23
26
!!! important
24
27
BaseClass Arguments outside the ` __init__ ` method and without default value ** HAVE TO** be set in the ` __attrs_post_init__ ` step.
25
28
26
29
#### Methods
27
30
28
- - ** tile_exists** : Check if a given tile (for the input TMS) intersect the dataset bounds.
29
-
30
- ##### Properties
31
-
32
- - ** geographic_bounds** : dataset's bounds in WGS84 crs (calculated from ` self.bounds ` and ` self.crs ` ).
31
+ - ** tile_exists(tile_x: int, tile_y: int, tile_z: int)** : Check if a given tile (for the input TMS) intersect the dataset bounds.
32
+ - ** get_geographic_bounds(crs: rasterio.crs.CRS)** : dataset's bounds in Geographic CRS (calculated from ` self.bounds ` and ` self.crs ` ).
33
33
34
34
##### Abstract Methods
35
35
@@ -64,6 +64,8 @@ from rio_tiler.io.base import MultiBaseReader
64
64
from rio_tiler.io import Reader, BaseReader
65
65
from rio_tiler.constants import WEB_MERCATOR_TMS
66
66
from rio_tiler.models import Info
67
+ from rio_tiler.types import AssetInfo
68
+ from rio_tiler.errors import InvalidAssetName
67
69
68
70
@attr.s
69
71
class AssetFileReader (MultiBaseReader ):
@@ -86,19 +88,26 @@ class AssetFileReader(MultiBaseReader):
86
88
self .assets = sorted (
87
89
[p.stem.split(" _" )[1 ] for p in pathlib.Path(self .input).glob(f " * { self .prefix} *.tif " )]
88
90
)
89
- with self .reader(self ._get_asset_url (self .assets[0 ])) as cog:
91
+ with self .reader(self ._get_asset_info (self .assets[0 ])[ " url " ] ) as cog:
90
92
self .bounds = cog.bounds
91
93
self .crs = cog.crs
92
-
94
+ self .transform = cog.transform
95
+ self .height = cog.height
96
+ self .width = cog.width
93
97
if self .minzoom is None :
94
98
self .minzoom = cog.minzoom
95
99
96
100
if self .maxzoom is None :
97
101
self .maxzoom = cog.maxzoom
98
102
99
- def _get_asset_url (self , band : str ) -> str :
103
+ def _get_asset_info (self , asset : str ) -> AssetInfo :
100
104
""" Validate band's name and return band's url."""
101
- return os.path.join(self .input, f " { self .prefix}{ band} .tif " )
105
+ if asset not in self .assets:
106
+ raise InvalidAssetName(
107
+ f " ' { asset} ' is not valid, should be one of { self .assets} "
108
+ )
109
+
110
+ return AssetInfo(url = os.path.join(self .input, f " { self .prefix}{ asset} .tif " ))
102
111
103
112
# we have a directoty with "scene_b1.tif", "scene_b2.tif"
104
113
with AssetFileReader(input = " my_dir/" , prefix = " scene_" ) as cr:
@@ -114,14 +123,44 @@ with AssetFileReader(input="my_dir/", prefix="scene_") as cr:
114
123
assert isinstance (info[" band1" ], Info)
115
124
print (info[" band1" ].model_dump_json(exclude_none = True ))
116
125
>> > {
117
- ' bounds' : [- 11.979244865430259 , 24.296321392464325 , - 10.874546803397614 , 25.304623891542263 ],
118
- ' minzoom' : 7 ,
119
- ' maxzoom' : 9 ,
120
- ' band_metadata' : [(' b1' , {})],
121
- ' band_descriptions' : [(' b1' , ' ' )],
122
- ' dtype' : ' uint16' ,
123
- ' nodata_type' : ' Nodata' ,
124
- ' colorinterp' : [' gray' ]
126
+ " bounds" : [
127
+ 199980 ,
128
+ 2690220 ,
129
+ 309780 ,
130
+ 2800020
131
+ ],
132
+ " crs" : " http://www.opengis.net/def/crs/EPSG/0/32629" ,
133
+ " band_metadata" : [
134
+ [
135
+ " b1" ,
136
+ {}
137
+ ]
138
+ ],
139
+ " band_descriptions" : [
140
+ [
141
+ " b1" ,
142
+ " "
143
+ ]
144
+ ],
145
+ " dtype" : " uint16" ,
146
+ " nodata_type" : " Nodata" ,
147
+ " colorinterp" : [
148
+ " gray"
149
+ ],
150
+ " scales" : [
151
+ 1
152
+ ],
153
+ " offsets" : [
154
+ 0
155
+ ],
156
+ " driver" : " GTiff" ,
157
+ " count" : 1 ,
158
+ " width" : 549 ,
159
+ " height" : 549 ,
160
+ " overviews" : [
161
+ 2
162
+ ],
163
+ " nodata_value" : 0
125
164
}
126
165
img = cr.tile(238 , 218 , 9 , assets = (" band1" , " band2" ))
127
166
@@ -176,7 +215,9 @@ class BandFileReader(MultiBandReader):
176
215
with self .reader(self ._get_band_url(self .bands[0 ])) as cog:
177
216
self .bounds = cog.bounds
178
217
self .crs = cog.crs
179
-
218
+ self .transform = cog.transform
219
+ self .height = cog.height
220
+ self .width = cog.width
180
221
if self .minzoom is None :
181
222
self .minzoom = cog.minzoom
182
223
@@ -195,14 +236,39 @@ with BandFileReader(input="my_dir/", prefix="scene_") as cr:
195
236
196
237
print (cr.info(bands = (" band1" , " band2" )).model_dump_json(exclude_none = True ))
197
238
>> > {
198
- ' bounds' : [- 11.979244865430259 , 24.296321392464325 , - 10.874546803397614 , 25.304623891542263 ],
199
- ' minzoom' : 7 ,
200
- ' maxzoom' : 9 ,
201
- ' band_metadata' : [(' band1' , {}), (' band2' , {})],
202
- ' band_descriptions' : [(' band1' , ' ' ), (' band2' , ' ' )],
203
- ' dtype' : ' uint16' ,
204
- ' nodata_type' : ' Nodata' ,
205
- ' colorinterp' : [' gray' , ' gray' ]
239
+ " bounds" : [
240
+ 199980 ,
241
+ 2690220 ,
242
+ 309780 ,
243
+ 2800020
244
+ ],
245
+ " crs" : " http://www.opengis.net/def/crs/EPSG/0/32629" ,
246
+ " band_metadata" : [
247
+ [
248
+ " band1" ,
249
+ {}
250
+ ],
251
+ [
252
+ " band2" ,
253
+ {}
254
+ ]
255
+ ],
256
+ " band_descriptions" : [
257
+ [
258
+ " band1" ,
259
+ " "
260
+ ],
261
+ [
262
+ " band2" ,
263
+ " "
264
+ ]
265
+ ],
266
+ " dtype" : " uint16" ,
267
+ " nodata_type" : " Nodata" ,
268
+ " colorinterp" : [
269
+ " gray" ,
270
+ " gray"
271
+ ]
206
272
}
207
273
208
274
img = cr.tile(238 , 218 , 9 , bands = (" band1" , " band2" ))
@@ -278,7 +344,7 @@ In this `CustomSTACReader`, we are using a custom path `schema` in form of `{ite
278
344
279
345
280
346
``` python
281
- from typing import Any, Dict
347
+ from typing import Any, Dict, List
282
348
283
349
import attr
284
350
import rasterio
@@ -297,14 +363,23 @@ class SimpleReader(BaseReader):
297
363
# We force tms to be outside the class __init__
298
364
tms: TileMatrixSet = attr.ib(init = False , default = WEB_MERCATOR_TMS )
299
365
300
- # We overwrite the abstract base class attribute definition and set default
301
- minzoom: int = attr.ib(init = False , default = WEB_MERCATOR_TMS .minzoom)
302
- maxzoom: int = attr.ib(init = False , default = WEB_MERCATOR_TMS .maxzoom)
303
-
304
366
def __attrs_post_init__ (self ):
305
367
# Set bounds and crs variable
306
368
self .bounds = self .input.bounds
307
369
self .crs = self .input.crs
370
+ self .transform = self .input.transform
371
+ self .height = self .input.height
372
+ self .width = self .input.width
373
+
374
+ @ property
375
+ def minzoom (self ):
376
+ """ Return dataset minzoom."""
377
+ return self ._minzoom
378
+
379
+ @ property
380
+ def maxzoom (self ):
381
+ """ Return dataset maxzoom."""
382
+ return self ._maxzoom
308
383
309
384
# implement all mandatory methods
310
385
def info (self ) -> Info:
@@ -333,7 +408,7 @@ class SimpleReader(BaseReader):
333
408
334
409
tile_bounds = self .tms.xy_bounds(Tile(x = tile_x, y = tile_y, z = tile_z))
335
410
336
- data, mask = reader.part(
411
+ return reader.part(
337
412
self .input,
338
413
tile_bounds,
339
414
width = 256 ,
@@ -342,9 +417,7 @@ class SimpleReader(BaseReader):
342
417
dst_crs = tms.rasterio_crs,
343
418
** kwargs,
344
419
)
345
- return ImageData(
346
- data, mask, bounds = tile_bounds, crs = tms.rasterio_crs
347
- )
420
+
348
421
349
422
with rasterio.open(" file.tif" ) as src:
350
423
with SimpleReader(src) as cog:
0 commit comments