@@ -46,7 +46,13 @@ class DeepZoomGenerator:
46
46
openslide .PROPERTY_NAME_BOUNDS_HEIGHT ,
47
47
)
48
48
49
- def __init__ (self , osr , tile_size = 254 , overlap = 1 , limit_bounds = False ):
49
+ def __init__ (
50
+ self ,
51
+ osr : openslide .AbstractSlide ,
52
+ tile_size : int = 254 ,
53
+ overlap : int = 1 ,
54
+ limit_bounds : bool = False ,
55
+ ):
50
56
"""Create a DeepZoomGenerator wrapping an OpenSlide object.
51
57
52
58
osr: a slide object.
@@ -101,7 +107,7 @@ def __init__(self, osr, tile_size=254, overlap=1, limit_bounds=False):
101
107
self ._z_dimensions = tuple (reversed (z_dimensions ))
102
108
103
109
# Tile
104
- def tiles (z_lim ) :
110
+ def tiles (z_lim : int ) -> int :
105
111
return int (math .ceil (z_lim / self ._z_t_downsample ))
106
112
107
113
self ._t_dimensions = tuple (
@@ -112,7 +118,8 @@ def tiles(z_lim):
112
118
self ._dz_levels = len (self ._z_dimensions )
113
119
114
120
# Total downsamples for each Deep Zoom level
115
- l0_z_downsamples = tuple (
121
+ # mypy infers this as a tuple[Any, ...] due to the ** operator
122
+ l0_z_downsamples : tuple [int , ...] = tuple (
116
123
2 ** (self ._dz_levels - dz_level - 1 ) for dz_level in range (self ._dz_levels )
117
124
)
118
125
@@ -134,7 +141,7 @@ def tiles(z_lim):
134
141
openslide .PROPERTY_NAME_BACKGROUND_COLOR , 'ffffff'
135
142
)
136
143
137
- def __repr__ (self ):
144
+ def __repr__ (self ) -> str :
138
145
return '{}({!r}, tile_size={!r}, overlap={!r}, limit_bounds={!r})' .format (
139
146
self .__class__ .__name__ ,
140
147
self ._osr ,
@@ -144,26 +151,26 @@ def __repr__(self):
144
151
)
145
152
146
153
@property
147
- def level_count (self ):
154
+ def level_count (self ) -> int :
148
155
"""The number of Deep Zoom levels in the image."""
149
156
return self ._dz_levels
150
157
151
158
@property
152
- def level_tiles (self ):
159
+ def level_tiles (self ) -> tuple [ tuple [ int , int ], ...] :
153
160
"""A list of (tiles_x, tiles_y) tuples for each Deep Zoom level."""
154
161
return self ._t_dimensions
155
162
156
163
@property
157
- def level_dimensions (self ):
164
+ def level_dimensions (self ) -> tuple [ tuple [ int , ...], ...] :
158
165
"""A list of (pixels_x, pixels_y) tuples for each Deep Zoom level."""
159
166
return self ._z_dimensions
160
167
161
168
@property
162
- def tile_count (self ):
169
+ def tile_count (self ) -> int :
163
170
"""The total number of Deep Zoom tiles in the image."""
164
171
return sum (t_cols * t_rows for t_cols , t_rows in self ._t_dimensions )
165
172
166
- def get_tile (self , level , address ) :
173
+ def get_tile (self , level : int , address : tuple [ int , int ]) -> Image . Image :
167
174
"""Return an RGB PIL.Image for a tile.
168
175
169
176
level: the Deep Zoom level.
@@ -191,7 +198,9 @@ def get_tile(self, level, address):
191
198
192
199
return tile
193
200
194
- def _get_tile_info (self , dz_level , t_location ):
201
+ def _get_tile_info (
202
+ self , dz_level : int , t_location : tuple [int , int ]
203
+ ) -> tuple [tuple [tuple [int , int ], int , tuple [int , int ]], tuple [int , int ]]:
195
204
# Check parameters
196
205
if dz_level < 0 or dz_level >= self ._dz_levels :
197
206
raise ValueError ("Invalid level" )
@@ -210,42 +219,62 @@ def _get_tile_info(self, dz_level, t_location):
210
219
)
211
220
212
221
# Get final size of the tile
213
- z_size = tuple (
214
- min (self . _z_t_downsample , z_lim - self . _z_t_downsample * t ) + z_tl + z_br
215
- for t , z_lim , z_tl , z_br in zip (
216
- t_location , self ._z_dimensions [dz_level ], z_overlap_tl , z_overlap_br
222
+ z_size = (
223
+ min (
224
+ self . _z_t_downsample ,
225
+ self ._z_dimensions [dz_level ][ 0 ] - self . _z_t_downsample * t_location [ 0 ],
217
226
)
227
+ + z_overlap_tl [0 ]
228
+ + z_overlap_br [0 ],
229
+ min (
230
+ self ._z_t_downsample ,
231
+ self ._z_dimensions [dz_level ][1 ] - self ._z_t_downsample * t_location [1 ],
232
+ )
233
+ + z_overlap_tl [1 ]
234
+ + z_overlap_br [1 ],
218
235
)
219
236
220
237
# Obtain the region coordinates
221
- z_location = [ self ._z_from_t (t ) for t in t_location ]
222
- l_location = [
223
- self ._l_from_z (dz_level , z - z_tl )
224
- for z , z_tl in zip ( z_location , z_overlap_tl )
225
- ]
238
+ z_location = ( self ._z_from_t (t_location [ 0 ]), self . _z_from_t ( t_location [ 1 ]))
239
+ l_location = (
240
+ self ._l_from_z (dz_level , z_location [ 0 ] - z_overlap_tl [ 0 ]),
241
+ self . _l_from_z ( dz_level , z_location [ 1 ] - z_overlap_tl [ 1 ]),
242
+ )
226
243
# Round location down and size up, and add offset of active area
227
- l0_location = tuple (
228
- int (self ._l0_from_l (slide_level , l ) + l0_off )
229
- for l , l0_off in zip ( l_location , self ._l0_offset )
244
+ l0_location = (
245
+ int (self ._l0_from_l (slide_level , l_location [ 0 ] ) + self . _l0_offset [ 0 ]),
246
+ int ( self . _l0_from_l ( slide_level , l_location [ 1 ]) + self ._l0_offset [ 1 ]),
230
247
)
231
- l_size = tuple (
232
- int (min (math .ceil (self ._l_from_z (dz_level , dz )), l_lim - math .ceil (l )))
233
- for l , dz , l_lim in zip (l_location , z_size , self ._l_dimensions [slide_level ])
248
+ l_size = (
249
+ int (
250
+ min (
251
+ math .ceil (self ._l_from_z (dz_level , z_size [0 ])),
252
+ self ._l_dimensions [slide_level ][0 ] - math .ceil (l_location [0 ]),
253
+ )
254
+ ),
255
+ int (
256
+ min (
257
+ math .ceil (self ._l_from_z (dz_level , z_size [1 ])),
258
+ self ._l_dimensions [slide_level ][1 ] - math .ceil (l_location [1 ]),
259
+ )
260
+ ),
234
261
)
235
262
236
263
# Return read_region() parameters plus tile size for final scaling
237
264
return ((l0_location , slide_level , l_size ), z_size )
238
265
239
- def _l0_from_l (self , slide_level , l ) :
266
+ def _l0_from_l (self , slide_level : int , l : float ) -> float :
240
267
return self ._l0_l_downsamples [slide_level ] * l
241
268
242
- def _l_from_z (self , dz_level , z ) :
269
+ def _l_from_z (self , dz_level : int , z : int ) -> float :
243
270
return self ._l_z_downsamples [dz_level ] * z
244
271
245
- def _z_from_t (self , t ) :
272
+ def _z_from_t (self , t : int ) -> int :
246
273
return self ._z_t_downsample * t
247
274
248
- def get_tile_coordinates (self , level , address ):
275
+ def get_tile_coordinates (
276
+ self , level : int , address : tuple [int , int ]
277
+ ) -> tuple [tuple [int , int ], int , tuple [int , int ]]:
249
278
"""Return the OpenSlide.read_region() arguments for the specified tile.
250
279
251
280
Most users should call get_tile() rather than calling
@@ -256,15 +285,17 @@ def get_tile_coordinates(self, level, address):
256
285
tuple."""
257
286
return self ._get_tile_info (level , address )[0 ]
258
287
259
- def get_tile_dimensions (self , level , address ):
288
+ def get_tile_dimensions (
289
+ self , level : int , address : tuple [int , int ]
290
+ ) -> tuple [int , int ]:
260
291
"""Return a (pixels_x, pixels_y) tuple for the specified tile.
261
292
262
293
level: the Deep Zoom level.
263
294
address: the address of the tile within the level as a (col, row)
264
295
tuple."""
265
296
return self ._get_tile_info (level , address )[1 ]
266
297
267
- def get_dzi (self , format ) :
298
+ def get_dzi (self , format : str ) -> str :
268
299
"""Return a string containing the XML metadata for the .dzi file.
269
300
270
301
format: the format of the individual tiles ('png' or 'jpeg')"""
0 commit comments