large-image-source-tifffile 1.27.5.dev6__py3-none-any.whl → 1.30.7.dev10__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- large_image_source_tifffile/__init__.py +149 -29
- {large_image_source_tifffile-1.27.5.dev6.dist-info → large_image_source_tifffile-1.30.7.dev10.dist-info}/METADATA +18 -4
- large_image_source_tifffile-1.30.7.dev10.dist-info/RECORD +8 -0
- {large_image_source_tifffile-1.27.5.dev6.dist-info → large_image_source_tifffile-1.30.7.dev10.dist-info}/WHEEL +1 -1
- large_image_source_tifffile-1.27.5.dev6.dist-info/RECORD +0 -8
- {large_image_source_tifffile-1.27.5.dev6.dist-info → large_image_source_tifffile-1.30.7.dev10.dist-info}/LICENSE +0 -0
- {large_image_source_tifffile-1.27.5.dev6.dist-info → large_image_source_tifffile-1.30.7.dev10.dist-info}/entry_points.txt +0 -0
- {large_image_source_tifffile-1.27.5.dev6.dist-info → large_image_source_tifffile-1.30.7.dev10.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,6 @@ from importlib.metadata import PackageNotFoundError
|
|
7
7
|
from importlib.metadata import version as _importlib_version
|
8
8
|
|
9
9
|
import numpy as np
|
10
|
-
import zarr
|
11
10
|
|
12
11
|
import large_image
|
13
12
|
from large_image.cache_util import LruCacheMetaclass, methodcache
|
@@ -16,6 +15,7 @@ from large_image.exceptions import TileSourceError, TileSourceFileNotFoundError
|
|
16
15
|
from large_image.tilesource import FileTileSource
|
17
16
|
|
18
17
|
tifffile = None
|
18
|
+
zarr = None
|
19
19
|
|
20
20
|
try:
|
21
21
|
__version__ = _importlib_version(__name__)
|
@@ -37,6 +37,7 @@ def _lazyImport():
|
|
37
37
|
module initialization because it is slow.
|
38
38
|
"""
|
39
39
|
global tifffile
|
40
|
+
global zarr
|
40
41
|
|
41
42
|
if tifffile is None:
|
42
43
|
try:
|
@@ -55,6 +56,8 @@ def _lazyImport():
|
|
55
56
|
logging.getLogger('tifffile.tifffile').addHandler(checkForMissingDataHandler())
|
56
57
|
logging.getLogger('tifffile').setLevel(logging.WARNING)
|
57
58
|
logging.getLogger('tifffile').addHandler(checkForMissingDataHandler())
|
59
|
+
if zarr is None:
|
60
|
+
import zarr
|
58
61
|
|
59
62
|
|
60
63
|
def et_findall(tag, text):
|
@@ -109,6 +112,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
109
112
|
self._largeImagePath = str(self._getLargeImagePath())
|
110
113
|
|
111
114
|
_lazyImport()
|
115
|
+
self.addKnownExtensions()
|
112
116
|
try:
|
113
117
|
self._tf = tifffile.TiffFile(self._largeImagePath)
|
114
118
|
except Exception:
|
@@ -179,7 +183,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
179
183
|
ex = 'no maximum series'
|
180
184
|
try:
|
181
185
|
for idx, s in enumerate(self._tf.series):
|
182
|
-
samples =
|
186
|
+
samples = math.prod(s.shape)
|
183
187
|
if samples > maxsamples and 'X' in s.axes and 'Y' in s.axes:
|
184
188
|
maxseries = idx
|
185
189
|
maxsamples = samples
|
@@ -228,7 +232,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
228
232
|
'sizeX': s.shape[s.axes.index('X')], 'sizeY': s.shape[s.axes.index('Y')]})
|
229
233
|
self.sizeX = max(self.sizeX, s.shape[s.axes.index('X')])
|
230
234
|
self.sizeY = max(self.sizeY, s.shape[s.axes.index('Y')])
|
231
|
-
self._framecount = len(self._series) *
|
235
|
+
self._framecount = len(self._series) * math.prod(tuple(
|
232
236
|
1 if base.axes[sidx] in 'YXS' else v for sidx, v in enumerate(base.shape)))
|
233
237
|
self._basis = {}
|
234
238
|
basis = 1
|
@@ -255,14 +259,17 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
255
259
|
for p in self._tf.pages:
|
256
260
|
if (p not in pagesInSeries and getattr(p, 'keyframe', None) is not None and
|
257
261
|
p.hash not in hashes and not len(set(p.axes) - set('YXS'))):
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
262
|
+
try:
|
263
|
+
id = 'image_%s' % p.index
|
264
|
+
entry = {'page': p.index}
|
265
|
+
entry['width'] = p.shape[p.axes.index('X')]
|
266
|
+
entry['height'] = p.shape[p.axes.index('Y')]
|
267
|
+
if (id not in self._associatedImages and
|
268
|
+
max(entry['width'], entry['height']) <= self._maxAssociatedImageSize and
|
269
|
+
max(entry['width'], entry['height']) >= self._minAssociatedImageSize):
|
270
|
+
self._associatedImages[id] = entry
|
271
|
+
except Exception:
|
272
|
+
pass
|
266
273
|
for sidx, s in enumerate(self._tf.series):
|
267
274
|
if sidx not in self._series and not len(set(s.axes) - set('YXS')):
|
268
275
|
id = 'series_%d' % sidx
|
@@ -285,6 +292,79 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
285
292
|
except Exception:
|
286
293
|
pass
|
287
294
|
|
295
|
+
def _handle_indica(self):
|
296
|
+
import xml.etree.ElementTree
|
297
|
+
|
298
|
+
import large_image.tilesource.utilities
|
299
|
+
|
300
|
+
try:
|
301
|
+
root = xml.etree.ElementTree.fromstring(self._tf.pages[0].description)
|
302
|
+
self._xml = large_image.tilesource.utilities.etreeToDict(root)
|
303
|
+
self._channels = [c['name'] for c in
|
304
|
+
self._xml['indica']['image']['channels']['channel']]
|
305
|
+
if len(self._basis) == 1 and 'I' in self._basis:
|
306
|
+
self._basis['C'] = self._basis.pop('I')
|
307
|
+
self._associatedImages.clear()
|
308
|
+
except Exception:
|
309
|
+
pass
|
310
|
+
|
311
|
+
def _handle_ome(self):
|
312
|
+
"""
|
313
|
+
For OME Tiff, if we didn't parse the mangification elsewhere, try to
|
314
|
+
parse it here.
|
315
|
+
"""
|
316
|
+
import xml.etree.ElementTree
|
317
|
+
|
318
|
+
import large_image.tilesource.utilities
|
319
|
+
|
320
|
+
_omeUnitsToMeters = {
|
321
|
+
'Ym': 1e24,
|
322
|
+
'Zm': 1e21,
|
323
|
+
'Em': 1e18,
|
324
|
+
'Pm': 1e15,
|
325
|
+
'Tm': 1e12,
|
326
|
+
'Gm': 1e9,
|
327
|
+
'Mm': 1e6,
|
328
|
+
'km': 1e3,
|
329
|
+
'hm': 1e2,
|
330
|
+
'dam': 1e1,
|
331
|
+
'm': 1,
|
332
|
+
'dm': 1e-1,
|
333
|
+
'cm': 1e-2,
|
334
|
+
'mm': 1e-3,
|
335
|
+
'\u00b5m': 1e-6,
|
336
|
+
'nm': 1e-9,
|
337
|
+
'pm': 1e-12,
|
338
|
+
'fm': 1e-15,
|
339
|
+
'am': 1e-18,
|
340
|
+
'zm': 1e-21,
|
341
|
+
'ym': 1e-24,
|
342
|
+
'\u00c5': 1e-10,
|
343
|
+
}
|
344
|
+
|
345
|
+
try:
|
346
|
+
root = xml.etree.ElementTree.fromstring(self._tf.pages[0].description)
|
347
|
+
self._xml = large_image.tilesource.utilities.etreeToDict(root)
|
348
|
+
except Exception:
|
349
|
+
return
|
350
|
+
try:
|
351
|
+
try:
|
352
|
+
base = self._xml['OME']['Image'][0]['Pixels']
|
353
|
+
except Exception:
|
354
|
+
base = self._xml['OME']['Image']['Pixels']
|
355
|
+
if self._mm_x is None and 'PhysicalSizeX' in base:
|
356
|
+
self._mm_x = (
|
357
|
+
float(base['PhysicalSizeX']) * 1e3 *
|
358
|
+
_omeUnitsToMeters[base.get('PhysicalSizeXUnit', '\u00b5m')])
|
359
|
+
if self._mm_y is None and 'PhysicalSizeY' in base:
|
360
|
+
self._mm_y = (
|
361
|
+
float(base['PhysicalSizeY']) * 1e3 *
|
362
|
+
_omeUnitsToMeters[base.get('PhysicalSizeYUnit', '\u00b5m')])
|
363
|
+
self._mm_x = self._mm_x or self._mm_y
|
364
|
+
self._mm_y = self._mm_y or self._mm_x
|
365
|
+
except Exception:
|
366
|
+
pass
|
367
|
+
|
288
368
|
def _handle_scn(self): # noqa
|
289
369
|
"""
|
290
370
|
For SCN files, parse the xml and possibly adjust how associated images
|
@@ -350,6 +430,20 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
350
430
|
except Exception:
|
351
431
|
pass
|
352
432
|
|
433
|
+
def _handle_internal_ndpi(self, intmeta):
|
434
|
+
try:
|
435
|
+
ndpi = intmeta.pop('65449')
|
436
|
+
intmeta['ndpi'] = {}
|
437
|
+
for line in ndpi.replace('\r', '\n').split('\n'):
|
438
|
+
if '=' in line:
|
439
|
+
key, value = line.split('=', 1)
|
440
|
+
key = key.strip()
|
441
|
+
value = value.strip()
|
442
|
+
if key and key not in intmeta['ndpi'] and value:
|
443
|
+
intmeta['ndpi'][key] = value
|
444
|
+
except Exception:
|
445
|
+
pass
|
446
|
+
|
353
447
|
def getNativeMagnification(self):
|
354
448
|
"""
|
355
449
|
Get the magnification at a particular level.
|
@@ -419,6 +513,10 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
419
513
|
json.dumps(result[key][subkey])
|
420
514
|
except Exception:
|
421
515
|
del result[key][subkey]
|
516
|
+
for key in dir(self._tf):
|
517
|
+
if (key.startswith('is_') and hasattr(self, '_handle_internal_' + key[3:]) and
|
518
|
+
getattr(self._tf, key)):
|
519
|
+
getattr(self, '_handle_internal_' + key[3:])(result)
|
422
520
|
if hasattr(self, '_xml') and 'xml' not in result:
|
423
521
|
result.pop('ImageDescription', None)
|
424
522
|
result['xml'] = self._xml
|
@@ -473,19 +571,12 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
473
571
|
sidx = frame // self._basis['P'][0]
|
474
572
|
else:
|
475
573
|
sidx = 0
|
476
|
-
series = self._tf.series[self._series[sidx]]
|
477
574
|
nonempty = [None] * self.levels
|
478
575
|
nonempty[self.levels - 1] = True
|
576
|
+
series = self._tf.series[self._series[sidx]]
|
577
|
+
za, hasgbs = self._getZarrArray(series, sidx)
|
479
578
|
xidx = series.axes.index('X')
|
480
579
|
yidx = series.axes.index('Y')
|
481
|
-
with self._zarrlock:
|
482
|
-
if sidx not in self._zarrcache:
|
483
|
-
if len(self._zarrcache) > 10:
|
484
|
-
self._zarrcache = {}
|
485
|
-
za = zarr.open(series.aszarr(), mode='r')
|
486
|
-
hasgbs = hasattr(za[0], 'get_basic_selection')
|
487
|
-
self._zarrcache[sidx] = (za, hasgbs)
|
488
|
-
za, hasgbs = self._zarrcache[sidx]
|
489
580
|
for ll in range(1, len(series.levels)):
|
490
581
|
scale = round(math.log(max(za[0].shape[xidx] / za[ll].shape[xidx],
|
491
582
|
za[0].shape[yidx] / za[ll].shape[yidx])) / math.log(2))
|
@@ -496,6 +587,30 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
496
587
|
self._nonempty_levels_list[frame] = nonempty
|
497
588
|
return nonempty
|
498
589
|
|
590
|
+
def getPreferredLevel(self, level):
|
591
|
+
"""
|
592
|
+
Given a desired level (0 is minimum resolution, self.levels - 1 is max
|
593
|
+
resolution), return the level that contains actual data that is no
|
594
|
+
lower resolution.
|
595
|
+
|
596
|
+
:param level: desired level
|
597
|
+
:returns level: a level with actual data that is no lower resolution.
|
598
|
+
"""
|
599
|
+
return max(0, min(level, self.levels - 1))
|
600
|
+
|
601
|
+
def _getZarrArray(self, series, sidx):
|
602
|
+
with self._zarrlock:
|
603
|
+
if sidx not in self._zarrcache:
|
604
|
+
if len(self._zarrcache) > 10:
|
605
|
+
self._zarrcache = {}
|
606
|
+
za = zarr.open(series.aszarr(), mode='r')
|
607
|
+
hasgbs = hasattr(za[0], 'get_basic_selection')
|
608
|
+
if not hasgbs and math.prod(series.shape) < 256 * 1024 ** 2:
|
609
|
+
za = series.asarray()
|
610
|
+
self._zarrcache[sidx] = (za, hasgbs)
|
611
|
+
za, hasgbs = self._zarrcache[sidx]
|
612
|
+
return za, hasgbs
|
613
|
+
|
499
614
|
@methodcache()
|
500
615
|
def getTile(self, x, y, z, pilImageAllowed=False, numpyAllowed=False, **kwargs):
|
501
616
|
frame = self._getFrame(**kwargs)
|
@@ -506,14 +621,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
506
621
|
else:
|
507
622
|
sidx = 0
|
508
623
|
series = self._tf.series[self._series[sidx]]
|
509
|
-
|
510
|
-
if sidx not in self._zarrcache:
|
511
|
-
if len(self._zarrcache) > 10:
|
512
|
-
self._zarrcache = {}
|
513
|
-
za = zarr.open(series.aszarr(), mode='r')
|
514
|
-
hasgbs = hasattr(za[0], 'get_basic_selection')
|
515
|
-
self._zarrcache[sidx] = (za, hasgbs)
|
516
|
-
za, hasgbs = self._zarrcache[sidx]
|
624
|
+
za, hasgbs = self._getZarrArray(series, sidx)
|
517
625
|
xidx = series.axes.index('X')
|
518
626
|
yidx = series.axes.index('Y')
|
519
627
|
if hasgbs:
|
@@ -533,7 +641,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
533
641
|
else:
|
534
642
|
bza = za
|
535
643
|
if step > 2 ** self._maxSkippedLevels:
|
536
|
-
tile = self._getTileFromEmptyLevel(x, y, z, **kwargs)
|
644
|
+
tile, _format = self._getTileFromEmptyLevel(x, y, z, **kwargs)
|
537
645
|
tile = large_image.tilesource.base._imageToNumpy(tile)[0]
|
538
646
|
else:
|
539
647
|
sel = []
|
@@ -549,6 +657,8 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
549
657
|
sel.append(slice(series.shape[aidx]))
|
550
658
|
baxis += 'S'
|
551
659
|
else:
|
660
|
+
if axis not in self._basis and axis == 'I':
|
661
|
+
axis = 'C'
|
552
662
|
sel.append((frame // self._basis[axis][0]) % self._basis[axis][2])
|
553
663
|
tile = bza[tuple(sel)]
|
554
664
|
# rotate
|
@@ -558,6 +668,16 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
558
668
|
return self._outputTile(tile, TILE_FORMAT_NUMPY, x, y, z,
|
559
669
|
pilImageAllowed, numpyAllowed, **kwargs)
|
560
670
|
|
671
|
+
@classmethod
|
672
|
+
def addKnownExtensions(cls):
|
673
|
+
if not hasattr(cls, '_addedExtensions'):
|
674
|
+
_lazyImport()
|
675
|
+
cls._addedExtensions = True
|
676
|
+
cls.extensions = cls.extensions.copy()
|
677
|
+
for ext in tifffile.TIFF.FILE_EXTENSIONS:
|
678
|
+
if ext not in cls.extensions:
|
679
|
+
cls.extensions[ext] = SourcePriority.IMPLICIT
|
680
|
+
|
561
681
|
|
562
682
|
def open(*args, **kwargs):
|
563
683
|
"""
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: large-image-source-tifffile
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.30.7.dev10
|
4
4
|
Summary: A tifffile tilesource for large_image.
|
5
5
|
Home-page: https://github.com/girder/large_image
|
6
6
|
Author: Kitware, Inc.
|
@@ -15,14 +15,28 @@ Classifier: Programming Language :: Python :: 3.9
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.10
|
16
16
|
Classifier: Programming Language :: Python :: 3.11
|
17
17
|
Classifier: Programming Language :: Python :: 3.12
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
18
19
|
Requires-Python: >=3.8
|
20
|
+
Description-Content-Type: text/x-rst
|
19
21
|
License-File: LICENSE
|
20
|
-
Requires-Dist: large-image
|
22
|
+
Requires-Dist: large-image>=1.30.7.dev10
|
21
23
|
Requires-Dist: dask[array]
|
22
24
|
Requires-Dist: tifffile[all]
|
23
25
|
Requires-Dist: zarr
|
24
26
|
Provides-Extra: girder
|
25
|
-
Requires-Dist: girder-large-image
|
27
|
+
Requires-Dist: girder-large-image>=1.30.7.dev10; extra == "girder"
|
28
|
+
Dynamic: author
|
29
|
+
Dynamic: author-email
|
30
|
+
Dynamic: classifier
|
31
|
+
Dynamic: description
|
32
|
+
Dynamic: description-content-type
|
33
|
+
Dynamic: home-page
|
34
|
+
Dynamic: keywords
|
35
|
+
Dynamic: license
|
36
|
+
Dynamic: provides-extra
|
37
|
+
Dynamic: requires-dist
|
38
|
+
Dynamic: requires-python
|
39
|
+
Dynamic: summary
|
26
40
|
|
27
41
|
A tifffile tilesource for large_image.
|
28
42
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
large_image_source_tifffile/__init__.py,sha256=vU1bFrCyklocQjzwiwiAITwLm0sfk-TnyDlIAwxqFeA,28899
|
2
|
+
large_image_source_tifffile/girder_source.py,sha256=8YsxpSK_UzbAcpjn6fIMlgKye2FchkB8_HTSQV0FpRA,1064
|
3
|
+
large_image_source_tifffile-1.30.7.dev10.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
4
|
+
large_image_source_tifffile-1.30.7.dev10.dist-info/METADATA,sha256=ESkktkSCBeCvqOXMH5oFMgUnce9s94mAc3CkHO2o-V4,1405
|
5
|
+
large_image_source_tifffile-1.30.7.dev10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
6
|
+
large_image_source_tifffile-1.30.7.dev10.dist-info/entry_points.txt,sha256=aILCN5f7-Zj8-WRXcABxCQvqJv9VLTvqRhZ_7HEyokc,190
|
7
|
+
large_image_source_tifffile-1.30.7.dev10.dist-info/top_level.txt,sha256=feOAsix2Rzy6mjy2Ua-N0-L6tlKsgvLdRhO6Hd8_ZFs,28
|
8
|
+
large_image_source_tifffile-1.30.7.dev10.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
large_image_source_tifffile/__init__.py,sha256=7jHLRfFXszTDfTcD6aRylJthE03lK5FCHh4rKkHtHEw,24668
|
2
|
-
large_image_source_tifffile/girder_source.py,sha256=8YsxpSK_UzbAcpjn6fIMlgKye2FchkB8_HTSQV0FpRA,1064
|
3
|
-
large_image_source_tifffile-1.27.5.dev6.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
4
|
-
large_image_source_tifffile-1.27.5.dev6.dist-info/METADATA,sha256=8nBvBa8UIknq6Y8vtuL_hKFRzWg9ne44VyqOsfA9M2U,1061
|
5
|
-
large_image_source_tifffile-1.27.5.dev6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
-
large_image_source_tifffile-1.27.5.dev6.dist-info/entry_points.txt,sha256=aILCN5f7-Zj8-WRXcABxCQvqJv9VLTvqRhZ_7HEyokc,190
|
7
|
-
large_image_source_tifffile-1.27.5.dev6.dist-info/top_level.txt,sha256=feOAsix2Rzy6mjy2Ua-N0-L6tlKsgvLdRhO6Hd8_ZFs,28
|
8
|
-
large_image_source_tifffile-1.27.5.dev6.dist-info/RECORD,,
|
File without changes
|
File without changes
|