large-image-source-openslide 1.30.3.dev35__py3-none-any.whl → 1.33.6a165__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- large_image_source_openslide/__init__.py +55 -6
- large_image_source_openslide/girder_source.py +2 -2
- {large_image_source_openslide-1.30.3.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/METADATA +20 -8
- large_image_source_openslide-1.33.6a165.dist-info/RECORD +8 -0
- {large_image_source_openslide-1.30.3.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/WHEEL +1 -1
- large_image_source_openslide-1.30.3.dev35.dist-info/RECORD +0 -8
- {large_image_source_openslide-1.30.3.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/entry_points.txt +0 -0
- {large_image_source_openslide-1.30.3.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info/licenses}/LICENSE +0 -0
- {large_image_source_openslide-1.30.3.dev35.dist-info → large_image_source_openslide-1.33.6a165.dist-info}/top_level.txt +0 -0
|
@@ -20,6 +20,7 @@ import os
|
|
|
20
20
|
from importlib.metadata import PackageNotFoundError
|
|
21
21
|
from importlib.metadata import version as _importlib_version
|
|
22
22
|
|
|
23
|
+
import numpy as np
|
|
23
24
|
import openslide
|
|
24
25
|
import PIL
|
|
25
26
|
import tifftools
|
|
@@ -47,12 +48,13 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
47
48
|
extensions = {
|
|
48
49
|
None: SourcePriority.MEDIUM,
|
|
49
50
|
'bif': SourcePriority.LOW, # Ventana
|
|
50
|
-
'
|
|
51
|
+
'czi': SourcePriority.PREFERRED,
|
|
52
|
+
'dcm': SourcePriority.MEDIUM, # DICOM
|
|
51
53
|
'ini': SourcePriority.LOW, # Part of mrxs
|
|
52
54
|
'mrxs': SourcePriority.PREFERRED, # MIRAX
|
|
53
55
|
'ndpi': SourcePriority.PREFERRED, # Hamamatsu
|
|
54
56
|
'scn': SourcePriority.LOW, # Leica
|
|
55
|
-
'svs': SourcePriority.
|
|
57
|
+
'svs': SourcePriority.HIGH,
|
|
56
58
|
'svslide': SourcePriority.PREFERRED,
|
|
57
59
|
'tif': SourcePriority.MEDIUM,
|
|
58
60
|
'tiff': SourcePriority.MEDIUM,
|
|
@@ -61,6 +63,8 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
61
63
|
}
|
|
62
64
|
mimeTypes = {
|
|
63
65
|
None: SourcePriority.FALLBACK,
|
|
66
|
+
'image/czi': SourcePriority.PREFERRED,
|
|
67
|
+
'application/dicom': SourcePriority.MEDIUM,
|
|
64
68
|
'image/mirax': SourcePriority.PREFERRED, # MIRAX
|
|
65
69
|
'image/tiff': SourcePriority.MEDIUM,
|
|
66
70
|
'image/x-tiff': SourcePriority.MEDIUM,
|
|
@@ -94,6 +98,13 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
94
98
|
tifftools.Tag.ICCProfile.value]['data']]
|
|
95
99
|
except Exception:
|
|
96
100
|
pass
|
|
101
|
+
if hasattr(self, '_tiffinfo'):
|
|
102
|
+
for ifd in self._tiffinfo['ifds']:
|
|
103
|
+
if (tifftools.Tag.NDPI_FOCAL_PLANE.value in ifd['tags'] and
|
|
104
|
+
ifd['tags'][tifftools.Tag.NDPI_FOCAL_PLANE.value]['data'][0] != 0):
|
|
105
|
+
msg = ('File will not be opened via OpenSlide; '
|
|
106
|
+
'non-zero focal planes would be missed.')
|
|
107
|
+
raise TileSourceError(msg)
|
|
97
108
|
|
|
98
109
|
svsAvailableLevels = self._getAvailableLevels(self._largeImagePath)
|
|
99
110
|
if not len(svsAvailableLevels):
|
|
@@ -128,19 +139,22 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
128
139
|
# load an appropriate area and scale it to the tile size later.
|
|
129
140
|
maxSize = 16384 # This should probably be based on available memory
|
|
130
141
|
for level in range(self.levels):
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
levelpow = 2 ** (self.levels - 1 - level)
|
|
143
|
+
levelW = max(1, self.sizeX / levelpow)
|
|
144
|
+
levelH = max(1, self.sizeY / levelpow)
|
|
133
145
|
# bestlevel and scale will be the picked svs level and the scale
|
|
134
146
|
# between that level and what we really wanted. We expect scale to
|
|
135
147
|
# always be a positive integer power of two.
|
|
136
148
|
bestlevel = svsAvailableLevels[0]['level']
|
|
137
149
|
scale = 1
|
|
150
|
+
svsscale = 0
|
|
138
151
|
for svslevel in range(len(svsAvailableLevels)):
|
|
139
152
|
if (svsAvailableLevels[svslevel]['width'] < levelW - 1 or
|
|
140
153
|
svsAvailableLevels[svslevel]['height'] < levelH - 1):
|
|
141
154
|
break
|
|
142
155
|
bestlevel = svsAvailableLevels[svslevel]['level']
|
|
143
156
|
scale = int(round(svsAvailableLevels[svslevel]['width'] / levelW))
|
|
157
|
+
svsscale = svsAvailableLevels[svslevel].get('downsample', 0)
|
|
144
158
|
# If there are no tiles at a particular level, we have to read a
|
|
145
159
|
# larger area of a higher resolution level. If such an area would
|
|
146
160
|
# be excessively large, we could have memory issues, so raise an
|
|
@@ -154,6 +168,7 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
154
168
|
self._svslevels.append({
|
|
155
169
|
'svslevel': bestlevel,
|
|
156
170
|
'scale': scale,
|
|
171
|
+
'svsscale': ((svsscale / levelpow) if svsscale else 1) * scale,
|
|
157
172
|
})
|
|
158
173
|
self._bounds = None
|
|
159
174
|
try:
|
|
@@ -179,6 +194,12 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
179
194
|
self._svslevels = self._svslevels[prevlevels - self.levels:]
|
|
180
195
|
except Exception:
|
|
181
196
|
pass
|
|
197
|
+
try:
|
|
198
|
+
self._background = tuple(int(
|
|
199
|
+
self._openslide.properties['openslide.background-color']
|
|
200
|
+
[i * 2:i * 2 + 2], 16) for i in range(3))
|
|
201
|
+
except Exception:
|
|
202
|
+
self._background = None
|
|
182
203
|
self._populatedLevels = len({l['svslevel'] for l in self._svslevels})
|
|
183
204
|
|
|
184
205
|
def _getTileSize(self):
|
|
@@ -228,6 +249,7 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
228
249
|
"""
|
|
229
250
|
levels = []
|
|
230
251
|
svsLevelDimensions = self._openslide.level_dimensions
|
|
252
|
+
|
|
231
253
|
for svslevel in range(len(svsLevelDimensions)):
|
|
232
254
|
try:
|
|
233
255
|
self._openslide.read_region((0, 0), svslevel, (1, 1))
|
|
@@ -236,6 +258,10 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
236
258
|
'width': svsLevelDimensions[svslevel][0],
|
|
237
259
|
'height': svsLevelDimensions[svslevel][1],
|
|
238
260
|
}
|
|
261
|
+
try:
|
|
262
|
+
level['downsample'] = self._openslide.level_downsamples[svslevel]
|
|
263
|
+
except Exception:
|
|
264
|
+
pass
|
|
239
265
|
if level['width'] > 0 and level['height'] > 0:
|
|
240
266
|
# add to the list so that we can sort by resolution and
|
|
241
267
|
# then by earlier entries
|
|
@@ -327,12 +353,31 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
327
353
|
tile, format = self._getTileFromEmptyLevel(x, y, z, **kwargs)
|
|
328
354
|
else:
|
|
329
355
|
retries = 3
|
|
356
|
+
svsTileWidth = self.tileWidth * svslevel['scale']
|
|
357
|
+
svsTileHeight = self.tileHeight * svslevel['scale']
|
|
358
|
+
# Peculiarly, openslide has a "downsample" factor which isn't the
|
|
359
|
+
# power of 2 one would expect. This is computed based on the
|
|
360
|
+
# actual dimensions of levels, but since higher-resolution levels
|
|
361
|
+
# are not fully populated at the right and bottom, this ends up
|
|
362
|
+
# with not the actual downsampling, but some slightly higher number
|
|
363
|
+
# (e.g., 16.0018 rather than 16). Internally, when asking for a
|
|
364
|
+
# region for anything other than the maximum resolution lever, the
|
|
365
|
+
# openslide library is passed coordinates in what _seems_ to be
|
|
366
|
+
# base image coordinates, but is actually inflated by the ratio of
|
|
367
|
+
# their downsample value and the actual downsample value (e.g.,
|
|
368
|
+
# 16.0018 / 16). We multiple our values by this ratio so when
|
|
369
|
+
# openslide misapplies its downsampling we get the region we
|
|
370
|
+
# actually want
|
|
371
|
+
if svslevel['svsscale'] != 1:
|
|
372
|
+
offsetx = int(round(offsetx * svslevel['svsscale']))
|
|
373
|
+
offsety = int(round(offsety * svslevel['svsscale']))
|
|
374
|
+
svsTileWidth = int(round(svsTileWidth * svslevel['svsscale']))
|
|
375
|
+
svsTileHeight = int(round(svsTileHeight * svslevel['svsscale']))
|
|
330
376
|
while retries > 0:
|
|
331
377
|
try:
|
|
332
378
|
tile = self._openslide.read_region(
|
|
333
379
|
(offsetx, offsety), svslevel['svslevel'],
|
|
334
|
-
(
|
|
335
|
-
self.tileHeight * svslevel['scale']))
|
|
380
|
+
(svsTileWidth, svsTileHeight))
|
|
336
381
|
format = TILE_FORMAT_PIL
|
|
337
382
|
break
|
|
338
383
|
except openslide.lowlevel.OpenSlideError as exc:
|
|
@@ -349,6 +394,10 @@ class OpenslideFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
349
394
|
retries -= 1
|
|
350
395
|
if retries <= 0:
|
|
351
396
|
raise TileSourceError(msg)
|
|
397
|
+
if tile.mode == 'RGBA' and self._background:
|
|
398
|
+
tile = np.array(tile)
|
|
399
|
+
tile[tile[:, :, -1] == 0, :3] = self._background
|
|
400
|
+
tile = PIL.Image.fromarray(tile, 'RGBA')
|
|
352
401
|
# Always scale to the svs level 0 tile size.
|
|
353
402
|
if svslevel['scale'] != 1:
|
|
354
403
|
tile = tile.resize((self.tileWidth, self.tileHeight),
|
|
@@ -28,5 +28,5 @@ class OpenslideGirderTileSource(OpenslideFileTileSource, GirderTileSource):
|
|
|
28
28
|
cacheName = 'tilesource'
|
|
29
29
|
name = 'openslide'
|
|
30
30
|
|
|
31
|
-
extensionsWithAdjacentFiles = {'mrxs'}
|
|
32
|
-
mimeTypesWithAdjacentFiles = {'image/mirax'}
|
|
31
|
+
extensionsWithAdjacentFiles = {'mrxs', 'dcm', 'dicom'}
|
|
32
|
+
mimeTypesWithAdjacentFiles = {'image/mirax', 'application/dicom'}
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: large-image-source-openslide
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.33.6a165
|
|
4
4
|
Summary: An Openslide tilesource for large_image.
|
|
5
5
|
Home-page: https://github.com/girder/large_image
|
|
6
6
|
Author: Kitware, Inc.
|
|
7
7
|
Author-email: kitware@kitware.com
|
|
8
|
-
License: Apache
|
|
8
|
+
License: Apache-2.0
|
|
9
9
|
Keywords: large_image,tile source
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
16
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
-
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Requires-Python: >=3.9
|
|
20
19
|
Description-Content-Type: text/x-rst
|
|
21
20
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: large-image>=1.
|
|
21
|
+
Requires-Dist: large-image>=1.33.6.a165
|
|
23
22
|
Requires-Dist: openslide-python>=1.4.1
|
|
24
23
|
Requires-Dist: openslide-bin; platform_system == "Linux" and platform_machine == "x86_64"
|
|
25
24
|
Requires-Dist: openslide-bin; platform_system == "Linux" and platform_machine == "aarch64"
|
|
@@ -28,7 +27,20 @@ Requires-Dist: openslide-bin; platform_system == "Darwin" and platform_machine =
|
|
|
28
27
|
Requires-Dist: openslide-bin; platform_system == "Darwin" and platform_machine == "x86_64"
|
|
29
28
|
Requires-Dist: tifftools>=1.2.0
|
|
30
29
|
Provides-Extra: girder
|
|
31
|
-
Requires-Dist: girder-large-image>=1.
|
|
30
|
+
Requires-Dist: girder-large-image>=1.33.6.a165; extra == "girder"
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: author-email
|
|
33
|
+
Dynamic: classifier
|
|
34
|
+
Dynamic: description
|
|
35
|
+
Dynamic: description-content-type
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: keywords
|
|
38
|
+
Dynamic: license
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
Dynamic: provides-extra
|
|
41
|
+
Dynamic: requires-dist
|
|
42
|
+
Dynamic: requires-python
|
|
43
|
+
Dynamic: summary
|
|
32
44
|
|
|
33
45
|
An Openslide tilesource for large_image.
|
|
34
46
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
large_image_source_openslide/__init__.py,sha256=CEfTufsAco3V87GHdRtJz7KbIuLrgu1vGyc5-dtOXd4,22822
|
|
2
|
+
large_image_source_openslide/girder_source.py,sha256=wPa7xBoJ5-PKHMVy9joUNSUHTN6HCZKyR45lhR0SsRc,1236
|
|
3
|
+
large_image_source_openslide-1.33.6a165.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
4
|
+
large_image_source_openslide-1.33.6a165.dist-info/METADATA,sha256=XApXY6AO8gL5WbeS8nvvWYjrUSQQEgGc9Qe2avit_mM,1797
|
|
5
|
+
large_image_source_openslide-1.33.6a165.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
6
|
+
large_image_source_openslide-1.33.6a165.dist-info/entry_points.txt,sha256=4Z5cf63yeesvHxiR9W1dY3rfz5_V4Ck2xYhPUp4A1qA,196
|
|
7
|
+
large_image_source_openslide-1.33.6a165.dist-info/top_level.txt,sha256=wqaQQDWQl9a_l9s6n07tTxfjeEXePtHBhz1np6aUwQE,29
|
|
8
|
+
large_image_source_openslide-1.33.6a165.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
large_image_source_openslide/__init__.py,sha256=Ql2nXz2XuIySbrEse0gf-oRBmKD0ugQztLAVjOj5UF0,20056
|
|
2
|
-
large_image_source_openslide/girder_source.py,sha256=ntLgOinO7xcO85wFbjx6XEBmTgEtx5cuPZ_K6wXZzqA,1199
|
|
3
|
-
large_image_source_openslide-1.30.3.dev35.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
|
4
|
-
large_image_source_openslide-1.30.3.dev35.dist-info/METADATA,sha256=DXzCXqED-xYQ4VqsLViWr4t6bTLfZiTIZzw9I-TyeNk,1602
|
|
5
|
-
large_image_source_openslide-1.30.3.dev35.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
6
|
-
large_image_source_openslide-1.30.3.dev35.dist-info/entry_points.txt,sha256=4Z5cf63yeesvHxiR9W1dY3rfz5_V4Ck2xYhPUp4A1qA,196
|
|
7
|
-
large_image_source_openslide-1.30.3.dev35.dist-info/top_level.txt,sha256=wqaQQDWQl9a_l9s6n07tTxfjeEXePtHBhz1np6aUwQE,29
|
|
8
|
-
large_image_source_openslide-1.30.3.dev35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|