Skip to content

Commit fc0bd83

Browse files
sammaxwellxyzbgilbert
authored andcommitted
type the deepzoom generator
Signed-off-by: Sam Maxwell <[email protected]>
1 parent ab61d01 commit fc0bd83

File tree

1 file changed

+62
-31
lines changed

1 file changed

+62
-31
lines changed

openslide/deepzoom.py

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ class DeepZoomGenerator:
4646
openslide.PROPERTY_NAME_BOUNDS_HEIGHT,
4747
)
4848

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+
):
5056
"""Create a DeepZoomGenerator wrapping an OpenSlide object.
5157
5258
osr: a slide object.
@@ -101,7 +107,7 @@ def __init__(self, osr, tile_size=254, overlap=1, limit_bounds=False):
101107
self._z_dimensions = tuple(reversed(z_dimensions))
102108

103109
# Tile
104-
def tiles(z_lim):
110+
def tiles(z_lim: int) -> int:
105111
return int(math.ceil(z_lim / self._z_t_downsample))
106112

107113
self._t_dimensions = tuple(
@@ -112,7 +118,8 @@ def tiles(z_lim):
112118
self._dz_levels = len(self._z_dimensions)
113119

114120
# 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(
116123
2 ** (self._dz_levels - dz_level - 1) for dz_level in range(self._dz_levels)
117124
)
118125

@@ -134,7 +141,7 @@ def tiles(z_lim):
134141
openslide.PROPERTY_NAME_BACKGROUND_COLOR, 'ffffff'
135142
)
136143

137-
def __repr__(self):
144+
def __repr__(self) -> str:
138145
return '{}({!r}, tile_size={!r}, overlap={!r}, limit_bounds={!r})'.format(
139146
self.__class__.__name__,
140147
self._osr,
@@ -144,26 +151,26 @@ def __repr__(self):
144151
)
145152

146153
@property
147-
def level_count(self):
154+
def level_count(self) -> int:
148155
"""The number of Deep Zoom levels in the image."""
149156
return self._dz_levels
150157

151158
@property
152-
def level_tiles(self):
159+
def level_tiles(self) -> tuple[tuple[int, int], ...]:
153160
"""A list of (tiles_x, tiles_y) tuples for each Deep Zoom level."""
154161
return self._t_dimensions
155162

156163
@property
157-
def level_dimensions(self):
164+
def level_dimensions(self) -> tuple[tuple[int, ...], ...]:
158165
"""A list of (pixels_x, pixels_y) tuples for each Deep Zoom level."""
159166
return self._z_dimensions
160167

161168
@property
162-
def tile_count(self):
169+
def tile_count(self) -> int:
163170
"""The total number of Deep Zoom tiles in the image."""
164171
return sum(t_cols * t_rows for t_cols, t_rows in self._t_dimensions)
165172

166-
def get_tile(self, level, address):
173+
def get_tile(self, level: int, address: tuple[int, int]) -> Image.Image:
167174
"""Return an RGB PIL.Image for a tile.
168175
169176
level: the Deep Zoom level.
@@ -191,7 +198,9 @@ def get_tile(self, level, address):
191198

192199
return tile
193200

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]]:
195204
# Check parameters
196205
if dz_level < 0 or dz_level >= self._dz_levels:
197206
raise ValueError("Invalid level")
@@ -210,42 +219,62 @@ def _get_tile_info(self, dz_level, t_location):
210219
)
211220

212221
# 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],
217226
)
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],
218235
)
219236

220237
# 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+
)
226243
# 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]),
230247
)
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+
),
234261
)
235262

236263
# Return read_region() parameters plus tile size for final scaling
237264
return ((l0_location, slide_level, l_size), z_size)
238265

239-
def _l0_from_l(self, slide_level, l):
266+
def _l0_from_l(self, slide_level: int, l: float) -> float:
240267
return self._l0_l_downsamples[slide_level] * l
241268

242-
def _l_from_z(self, dz_level, z):
269+
def _l_from_z(self, dz_level: int, z: int) -> float:
243270
return self._l_z_downsamples[dz_level] * z
244271

245-
def _z_from_t(self, t):
272+
def _z_from_t(self, t: int) -> int:
246273
return self._z_t_downsample * t
247274

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]]:
249278
"""Return the OpenSlide.read_region() arguments for the specified tile.
250279
251280
Most users should call get_tile() rather than calling
@@ -256,15 +285,17 @@ def get_tile_coordinates(self, level, address):
256285
tuple."""
257286
return self._get_tile_info(level, address)[0]
258287

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]:
260291
"""Return a (pixels_x, pixels_y) tuple for the specified tile.
261292
262293
level: the Deep Zoom level.
263294
address: the address of the tile within the level as a (col, row)
264295
tuple."""
265296
return self._get_tile_info(level, address)[1]
266297

267-
def get_dzi(self, format):
298+
def get_dzi(self, format: str) -> str:
268299
"""Return a string containing the XML metadata for the .dzi file.
269300
270301
format: the format of the individual tiles ('png' or 'jpeg')"""

0 commit comments

Comments
 (0)