large-image-source-tifffile 1.28.3.dev2__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.
@@ -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):
@@ -180,7 +183,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
180
183
  ex = 'no maximum series'
181
184
  try:
182
185
  for idx, s in enumerate(self._tf.series):
183
- samples = np.prod(s.shape)
186
+ samples = math.prod(s.shape)
184
187
  if samples > maxsamples and 'X' in s.axes and 'Y' in s.axes:
185
188
  maxseries = idx
186
189
  maxsamples = samples
@@ -229,7 +232,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
229
232
  'sizeX': s.shape[s.axes.index('X')], 'sizeY': s.shape[s.axes.index('Y')]})
230
233
  self.sizeX = max(self.sizeX, s.shape[s.axes.index('X')])
231
234
  self.sizeY = max(self.sizeY, s.shape[s.axes.index('Y')])
232
- self._framecount = len(self._series) * np.prod(tuple(
235
+ self._framecount = len(self._series) * math.prod(tuple(
233
236
  1 if base.axes[sidx] in 'YXS' else v for sidx, v in enumerate(base.shape)))
234
237
  self._basis = {}
235
238
  basis = 1
@@ -256,14 +259,17 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
256
259
  for p in self._tf.pages:
257
260
  if (p not in pagesInSeries and getattr(p, 'keyframe', None) is not None and
258
261
  p.hash not in hashes and not len(set(p.axes) - set('YXS'))):
259
- id = 'image_%s' % p.index
260
- entry = {'page': p.index}
261
- entry['width'] = p.shape[p.axes.index('X')]
262
- entry['height'] = p.shape[p.axes.index('Y')]
263
- if (id not in self._associatedImages and
264
- max(entry['width'], entry['height']) <= self._maxAssociatedImageSize and
265
- max(entry['width'], entry['height']) >= self._minAssociatedImageSize):
266
- self._associatedImages[id] = entry
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
267
273
  for sidx, s in enumerate(self._tf.series):
268
274
  if sidx not in self._series and not len(set(s.axes) - set('YXS')):
269
275
  id = 'series_%d' % sidx
@@ -286,6 +292,79 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
286
292
  except Exception:
287
293
  pass
288
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
+
289
368
  def _handle_scn(self): # noqa
290
369
  """
291
370
  For SCN files, parse the xml and possibly adjust how associated images
@@ -351,6 +430,20 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
351
430
  except Exception:
352
431
  pass
353
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
+
354
447
  def getNativeMagnification(self):
355
448
  """
356
449
  Get the magnification at a particular level.
@@ -420,6 +513,10 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
420
513
  json.dumps(result[key][subkey])
421
514
  except Exception:
422
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)
423
520
  if hasattr(self, '_xml') and 'xml' not in result:
424
521
  result.pop('ImageDescription', None)
425
522
  result['xml'] = self._xml
@@ -490,6 +587,17 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
490
587
  self._nonempty_levels_list[frame] = nonempty
491
588
  return nonempty
492
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
+
493
601
  def _getZarrArray(self, series, sidx):
494
602
  with self._zarrlock:
495
603
  if sidx not in self._zarrcache:
@@ -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
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: large-image-source-tifffile
3
- Version: 1.28.3.dev2
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 >=1.28.3.dev2
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 >=1.28.3.dev2 ; extra == 'girder'
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,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,8 +0,0 @@
1
- large_image_source_tifffile/__init__.py,sha256=7hREWGbhyYOcz94l_vxMAOTUSJKtJY37TEIZdkvamNw,25001
2
- large_image_source_tifffile/girder_source.py,sha256=8YsxpSK_UzbAcpjn6fIMlgKye2FchkB8_HTSQV0FpRA,1064
3
- large_image_source_tifffile-1.28.3.dev2.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
4
- large_image_source_tifffile-1.28.3.dev2.dist-info/METADATA,sha256=2XRfComEY1H1fO7m6luWIfzukgRCnPmPJw6RVkiDpZw,1061
5
- large_image_source_tifffile-1.28.3.dev2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- large_image_source_tifffile-1.28.3.dev2.dist-info/entry_points.txt,sha256=aILCN5f7-Zj8-WRXcABxCQvqJv9VLTvqRhZ_7HEyokc,190
7
- large_image_source_tifffile-1.28.3.dev2.dist-info/top_level.txt,sha256=feOAsix2Rzy6mjy2Ua-N0-L6tlKsgvLdRhO6Hd8_ZFs,28
8
- large_image_source_tifffile-1.28.3.dev2.dist-info/RECORD,,