large-image-source-tifffile 1.27.5.dev6__tar.gz → 1.30.7.dev12__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/PKG-INFO +9 -2
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/README.rst +20 -40
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile/__init__.py +188 -29
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile.egg-info/PKG-INFO +9 -2
- large_image_source_tifffile-1.30.7.dev12/large_image_source_tifffile.egg-info/requires.txt +7 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/setup.py +3 -2
- large-image-source-tifffile-1.27.5.dev6/large_image_source_tifffile.egg-info/requires.txt +0 -7
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/LICENSE +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile/girder_source.py +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile.egg-info/SOURCES.txt +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile.egg-info/dependency_links.txt +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile.egg-info/entry_points.txt +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/large_image_source_tifffile.egg-info/top_level.txt +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/pyproject.toml +0 -0
- {large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/setup.cfg +0 -0
{large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/PKG-INFO
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: large-image-source-tifffile
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.30.7.dev12
|
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,9 +15,16 @@ 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
|
19
|
-
|
20
|
+
Description-Content-Type: text/x-rst
|
20
21
|
License-File: LICENSE
|
22
|
+
Requires-Dist: large-image>=1.30.7.dev12
|
23
|
+
Requires-Dist: dask[array]
|
24
|
+
Requires-Dist: tifffile[all]
|
25
|
+
Requires-Dist: zarr
|
26
|
+
Provides-Extra: girder
|
27
|
+
Requires-Dist: girder-large-image>=1.30.7.dev12; extra == "girder"
|
21
28
|
|
22
29
|
A tifffile tilesource for large_image.
|
23
30
|
|
{large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/README.rst
RENAMED
@@ -15,7 +15,7 @@ Large Image
|
|
15
15
|
:target: https://codecov.io/github/girder/large_image?branch=master
|
16
16
|
:alt: codecov.io
|
17
17
|
|
18
|
-
.. |doi-badge| image:: https://img.shields.io/badge/DOI-10.5281%2Fzenodo.4723355-blue
|
18
|
+
.. |doi-badge| image:: https://img.shields.io/badge/DOI-10.5281%2Fzenodo.4723355-blue.svg
|
19
19
|
:target: https://zenodo.org/badge/latestdoi/45569214
|
20
20
|
|
21
21
|
.. |pypi-badge| image:: https://img.shields.io/pypi/v/large-image.svg?logo=python&logoColor=white
|
@@ -39,7 +39,7 @@ Highlights
|
|
39
39
|
Installation
|
40
40
|
------------
|
41
41
|
|
42
|
-
In addition to installing the ``large-image`` package, you'll need at least one tile source (a ``large-image-source-xxx`` package). You can install everything from the main project with one of these commands:
|
42
|
+
In addition to installing the base ``large-image`` package, you'll need at least one tile source which corresponds to your target file format(s) (a ``large-image-source-xxx`` package). You can install everything from the main project with one of these commands:
|
43
43
|
|
44
44
|
Pip
|
45
45
|
~~~
|
@@ -52,7 +52,7 @@ Install all tile sources on linux::
|
|
52
52
|
|
53
53
|
pip install large-image[all] --find-links https://girder.github.io/large_image_wheels
|
54
54
|
|
55
|
-
|
55
|
+
When using large-image with an instance of `Girder`_, install all tile sources and all Girder plugins on linux::
|
56
56
|
|
57
57
|
pip install large-image[all] girder-large-image-annotation[tasks] --find-links https://girder.github.io/large_image_wheels
|
58
58
|
|
@@ -60,8 +60,9 @@ Install all tile sources and all Girder plugins on linux::
|
|
60
60
|
Conda
|
61
61
|
~~~~~
|
62
62
|
|
63
|
-
Conda makes dependency management a bit easier if not on Linux.
|
63
|
+
Conda makes dependency management a bit easier if not on Linux. The base module, converter module, and two of the source modules are available on conda-forge. You can install the following::
|
64
64
|
|
65
|
+
conda install -c conda-forge large-image
|
65
66
|
conda install -c conda-forge large-image-source-gdal
|
66
67
|
conda install -c conda-forge large-image-source-tiff
|
67
68
|
conda install -c conda-forge large-image-converter
|
@@ -118,7 +119,7 @@ Large Image consists of several Python modules designed to work together. These
|
|
118
119
|
|
119
120
|
- ``large-image-source-deepzoom``: A tile source for reading Deepzoom tiles.
|
120
121
|
|
121
|
-
- ``large-image-source-dicom``: A tile source for reading DICOM WSI
|
122
|
+
- ``large-image-source-dicom``: A tile source for reading DICOM Whole Slide Images (WSI).
|
122
123
|
|
123
124
|
- ``large-image-source-gdal``: A tile source for reading geotiff files via GDAL. This handles source data with more complex transforms than the mapnik tile source.
|
124
125
|
|
@@ -128,62 +129,41 @@ Large Image consists of several Python modules designed to work together. These
|
|
128
129
|
|
129
130
|
- ``large-image-source-nd2``: A tile source for reading nd2 (NIS Element) images.
|
130
131
|
|
131
|
-
- ``large-image-source-ometiff``: A tile source using the tiff library that can handle
|
132
|
+
- ``large-image-source-ometiff``: A tile source using the tiff library that can handle most multi-frame OMETiff files that are compliant with the specification.
|
132
133
|
|
133
134
|
- ``large-image-source-openjpeg``: A tile source using the Glymur library to read jp2 (JPEG 2000) files.
|
134
135
|
|
135
136
|
- ``large-image-source-openslide``: A tile source using the OpenSlide library. This works with svs, ndpi, Mirax, tiff, vms, and other file formats.
|
136
137
|
|
137
|
-
- ``large-image-source-pil``: A tile source for small images via the Python Imaging Library (Pillow).
|
138
|
+
- ``large-image-source-pil``: A tile source for small images via the Python Imaging Library (Pillow). By default, the maximum size is 4096, but the maximum size can be configured.
|
138
139
|
|
139
140
|
- ``large-image-source-tiff``: A tile source for reading pyramidal tiff files in common compression formats.
|
140
141
|
|
141
142
|
- ``large-image-source-tifffile``: A tile source using the tifffile library that can handle a wide variety of tiff-like files.
|
142
143
|
|
143
|
-
- ``large-image-source-vips``: A tile source for reading any files handled by libvips. This also can be used for writing tiled images from numpy arrays.
|
144
|
+
- ``large-image-source-vips``: A tile source for reading any files handled by libvips. This also can be used for writing tiled images from numpy arrays (up to 4 dimensions).
|
144
145
|
|
145
|
-
- ``large-image-source-zarr``: A tile source using the zarr library that can handle OME-Zarr (OME-NGFF) files as well as some other zarr files.
|
146
|
+
- ``large-image-source-zarr``: A tile source using the zarr library that can handle OME-Zarr (OME-NGFF) files as well as some other zarr files. This can also be used for writing N-dimensional tiled images from numpy arrays. Written images can be saved as any supported format.
|
146
147
|
|
147
148
|
- ``large-image-source-test``: A tile source that generates test tiles, including a simple fractal pattern. Useful for testing extreme zoom levels.
|
148
149
|
|
149
|
-
- ``large-image-source-dummy``: A tile source that does nothing.
|
150
|
+
- ``large-image-source-dummy``: A tile source that does nothing. This is an absolutely minimal implementation of a tile source used for testing. If you want to create a custom tile source, start with this implementation.
|
150
151
|
|
151
|
-
Most tile sources can be used with girder-large-image. You can specific an extras_require of ``girder`` to include ``girder-large-image`` with the source.
|
152
152
|
|
153
|
-
|
153
|
+
As a `Girder`_ plugin, ``large-image`` adds end points to access all of the image formats it can read both to get metadata and to act as a tile server.
|
154
|
+
In the Girder UI, ``large-image`` shows images on item pages, and can show thumbnails in item lists when browsing folders.
|
155
|
+
There is also cache management to balance memory use and speed of response in Girder when ``large-image`` is used as a tile server.
|
154
156
|
|
155
|
-
|
156
|
-
You can specify extras_require of ``tasks`` to install a Girder Worker task that can convert otherwise unreadable images to pyramidal tiff files.
|
157
|
+
Most tile sources can be used with Girder Large Image. You can specify an extras_require of ``girder`` to install the following packages:
|
157
158
|
|
158
|
-
- ``girder-large-image
|
159
|
+
- ``girder-large-image``: Large Image as a Girder 3.x plugin.
|
160
|
+
You can install ``large-image[tasks]`` to install a Girder Worker task that can convert otherwise unreadable images to pyramidal tiff files.
|
161
|
+
|
162
|
+
- ``girder-large-image-annotation``: Adds models to the Girder database for supporting annotating large images. These annotations can be rendered on images. Annotations can include polygons, points, image overlays, and other types. Each annotation can have a label and metadata.
|
159
163
|
|
160
164
|
- ``large-image-tasks``: A utility for running the converter via Girder Worker.
|
161
165
|
You can specify an extras_require of ``girder`` to include modules needed to work with the Girder remote worker or ``worker`` to include modules needed on the remote side of the Girder remote worker. If neither is specified, some conversion tasks can be run using Girder local jobs.
|
162
166
|
|
163
167
|
|
164
|
-
Developer Installation
|
165
|
-
----------------------
|
166
|
-
|
167
|
-
To install all packages from source, clone the repository::
|
168
|
-
|
169
|
-
git clone https://github.com/girder/large_image.git
|
170
|
-
cd large_image
|
171
|
-
|
172
|
-
Install all packages and dependencies::
|
173
|
-
|
174
|
-
pip install -e . -r requirements-dev.txt
|
175
|
-
|
176
|
-
If you aren't developing with Girder 3, you can skip installing those components. Use ``requirements-dev-core.txt`` instead of ``requirements-dev.txt``::
|
177
|
-
|
178
|
-
pip install -e . -r requirements-dev-core.txt
|
179
|
-
|
180
|
-
|
181
|
-
Tile source prerequisites
|
182
|
-
=========================
|
183
|
-
|
184
|
-
Many tile sources have complex prerequisites. These can be installed directly using your system's package manager or from some prebuilt Python wheels for Linux. The prebuilt wheels are not official packages, but they can be used by instructing pip to use them by preference::
|
185
|
-
|
186
|
-
pip install -e . -r requirements-dev.txt --find-links https://girder.github.io/large_image_wheels
|
187
|
-
|
188
168
|
|
189
|
-
.. _Girder: https://
|
169
|
+
.. _Girder: https://girder.readthedocs.io/en/latest/
|
@@ -5,9 +5,9 @@ import os
|
|
5
5
|
import threading
|
6
6
|
from importlib.metadata import PackageNotFoundError
|
7
7
|
from importlib.metadata import version as _importlib_version
|
8
|
+
from pathlib import Path
|
8
9
|
|
9
10
|
import numpy as np
|
10
|
-
import zarr
|
11
11
|
|
12
12
|
import large_image
|
13
13
|
from large_image.cache_util import LruCacheMetaclass, methodcache
|
@@ -16,6 +16,7 @@ from large_image.exceptions import TileSourceError, TileSourceFileNotFoundError
|
|
16
16
|
from large_image.tilesource import FileTileSource
|
17
17
|
|
18
18
|
tifffile = None
|
19
|
+
zarr = None
|
19
20
|
|
20
21
|
try:
|
21
22
|
__version__ = _importlib_version(__name__)
|
@@ -37,6 +38,7 @@ def _lazyImport():
|
|
37
38
|
module initialization because it is slow.
|
38
39
|
"""
|
39
40
|
global tifffile
|
41
|
+
global zarr
|
40
42
|
|
41
43
|
if tifffile is None:
|
42
44
|
try:
|
@@ -55,6 +57,8 @@ def _lazyImport():
|
|
55
57
|
logging.getLogger('tifffile.tifffile').addHandler(checkForMissingDataHandler())
|
56
58
|
logging.getLogger('tifffile').setLevel(logging.WARNING)
|
57
59
|
logging.getLogger('tifffile').addHandler(checkForMissingDataHandler())
|
60
|
+
if zarr is None:
|
61
|
+
import zarr
|
58
62
|
|
59
63
|
|
60
64
|
def et_findall(tag, text):
|
@@ -80,6 +84,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
80
84
|
'scn': SourcePriority.PREFERRED,
|
81
85
|
'tif': SourcePriority.LOW,
|
82
86
|
'tiff': SourcePriority.LOW,
|
87
|
+
'ome': SourcePriority.HIGHER,
|
83
88
|
}
|
84
89
|
mimeTypes = {
|
85
90
|
None: SourcePriority.FALLBACK,
|
@@ -109,6 +114,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
109
114
|
self._largeImagePath = str(self._getLargeImagePath())
|
110
115
|
|
111
116
|
_lazyImport()
|
117
|
+
self.addKnownExtensions()
|
112
118
|
try:
|
113
119
|
self._tf = tifffile.TiffFile(self._largeImagePath)
|
114
120
|
except Exception:
|
@@ -116,6 +122,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
116
122
|
raise TileSourceFileNotFoundError(self._largeImagePath) from None
|
117
123
|
msg = 'File cannot be opened via tifffile.'
|
118
124
|
raise TileSourceError(msg)
|
125
|
+
self._checkForOmeBinaryonly()
|
119
126
|
maxseries, maxsamples = self._biggestSeries()
|
120
127
|
self.tileWidth = self.tileHeight = self._tileSize
|
121
128
|
s = self._tf.series[maxseries]
|
@@ -123,6 +130,9 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
123
130
|
if len(s.levels) == 1:
|
124
131
|
self.tileWidth = self.tileHeight = self._singleTileSize
|
125
132
|
page = s.pages[0]
|
133
|
+
if not hasattr(page, 'tags'):
|
134
|
+
msg = 'File will not be opened via tifffile.'
|
135
|
+
raise TileSourceError(msg)
|
126
136
|
if ('TileWidth' in page.tags and
|
127
137
|
self._minTileSize <= page.tags['TileWidth'].value <= self._maxTileSize):
|
128
138
|
self.tileWidth = page.tags['TileWidth'].value
|
@@ -133,6 +143,10 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
133
143
|
self._iccprofiles = [page.tags['InterColorProfile'].value]
|
134
144
|
self.sizeX = s.shape[s.axes.index('X')]
|
135
145
|
self.sizeY = s.shape[s.axes.index('Y')]
|
146
|
+
while (self.tileWidth // 2 >= self.sizeX and self.tileHeight // 2 >= self.sizeY and
|
147
|
+
min(self.tileWidth, self.tileHeight) // 2 >= self._minTileSize):
|
148
|
+
self.tileWidth //= 2
|
149
|
+
self.tileHeight //= 2
|
136
150
|
self._mm_x = self._mm_y = None
|
137
151
|
try:
|
138
152
|
unit = {2: 25.4, 3: 10}[page.tags['ResolutionUnit'].value.real]
|
@@ -166,6 +180,35 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
166
180
|
msg = 'File cannot be opened via tifffile: axes and shape do not match access pattern.'
|
167
181
|
raise TileSourceError(msg)
|
168
182
|
|
183
|
+
def _checkForOmeBinaryonly(self):
|
184
|
+
from xml.etree import ElementTree as etree
|
185
|
+
|
186
|
+
omexml = getattr(self._tf, 'ome_metadata', None)
|
187
|
+
if not omexml:
|
188
|
+
return
|
189
|
+
try:
|
190
|
+
root = etree.fromstring(omexml)
|
191
|
+
except Exception:
|
192
|
+
return
|
193
|
+
metadatafile = None
|
194
|
+
for element in root:
|
195
|
+
if element.tag.endswith('BinaryOnly'):
|
196
|
+
metadatafile = element.attrib.get('MetadataFile', '')
|
197
|
+
if not metadatafile:
|
198
|
+
return
|
199
|
+
path = Path(self._largeImagePath).parent / metadatafile
|
200
|
+
if not path.is_file():
|
201
|
+
return
|
202
|
+
try:
|
203
|
+
newxml = path.open('r').read()
|
204
|
+
except Exception:
|
205
|
+
return
|
206
|
+
try:
|
207
|
+
root = etree.fromstring(newxml)
|
208
|
+
except Exception:
|
209
|
+
return
|
210
|
+
self._tf._omexml = newxml
|
211
|
+
|
169
212
|
def _biggestSeries(self):
|
170
213
|
"""
|
171
214
|
Find the series with the most pixels. Use all series that have the
|
@@ -179,7 +222,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
179
222
|
ex = 'no maximum series'
|
180
223
|
try:
|
181
224
|
for idx, s in enumerate(self._tf.series):
|
182
|
-
samples =
|
225
|
+
samples = math.prod(s.shape)
|
183
226
|
if samples > maxsamples and 'X' in s.axes and 'Y' in s.axes:
|
184
227
|
maxseries = idx
|
185
228
|
maxsamples = samples
|
@@ -228,7 +271,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
228
271
|
'sizeX': s.shape[s.axes.index('X')], 'sizeY': s.shape[s.axes.index('Y')]})
|
229
272
|
self.sizeX = max(self.sizeX, s.shape[s.axes.index('X')])
|
230
273
|
self.sizeY = max(self.sizeY, s.shape[s.axes.index('Y')])
|
231
|
-
self._framecount = len(self._series) *
|
274
|
+
self._framecount = len(self._series) * math.prod(tuple(
|
232
275
|
1 if base.axes[sidx] in 'YXS' else v for sidx, v in enumerate(base.shape)))
|
233
276
|
self._basis = {}
|
234
277
|
basis = 1
|
@@ -255,14 +298,17 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
255
298
|
for p in self._tf.pages:
|
256
299
|
if (p not in pagesInSeries and getattr(p, 'keyframe', None) is not None and
|
257
300
|
p.hash not in hashes and not len(set(p.axes) - set('YXS'))):
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
301
|
+
try:
|
302
|
+
id = 'image_%s' % p.index
|
303
|
+
entry = {'page': p.index}
|
304
|
+
entry['width'] = p.shape[p.axes.index('X')]
|
305
|
+
entry['height'] = p.shape[p.axes.index('Y')]
|
306
|
+
if (id not in self._associatedImages and
|
307
|
+
max(entry['width'], entry['height']) <= self._maxAssociatedImageSize and
|
308
|
+
max(entry['width'], entry['height']) >= self._minAssociatedImageSize):
|
309
|
+
self._associatedImages[id] = entry
|
310
|
+
except Exception:
|
311
|
+
pass
|
266
312
|
for sidx, s in enumerate(self._tf.series):
|
267
313
|
if sidx not in self._series and not len(set(s.axes) - set('YXS')):
|
268
314
|
id = 'series_%d' % sidx
|
@@ -285,6 +331,79 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
285
331
|
except Exception:
|
286
332
|
pass
|
287
333
|
|
334
|
+
def _handle_indica(self):
|
335
|
+
import xml.etree.ElementTree
|
336
|
+
|
337
|
+
import large_image.tilesource.utilities
|
338
|
+
|
339
|
+
try:
|
340
|
+
root = xml.etree.ElementTree.fromstring(self._tf.pages[0].description)
|
341
|
+
self._xml = large_image.tilesource.utilities.etreeToDict(root)
|
342
|
+
self._channels = [c['name'] for c in
|
343
|
+
self._xml['indica']['image']['channels']['channel']]
|
344
|
+
if len(self._basis) == 1 and 'I' in self._basis:
|
345
|
+
self._basis['C'] = self._basis.pop('I')
|
346
|
+
self._associatedImages.clear()
|
347
|
+
except Exception:
|
348
|
+
pass
|
349
|
+
|
350
|
+
def _handle_ome(self):
|
351
|
+
"""
|
352
|
+
For OME Tiff, if we didn't parse the mangification elsewhere, try to
|
353
|
+
parse it here.
|
354
|
+
"""
|
355
|
+
import xml.etree.ElementTree
|
356
|
+
|
357
|
+
import large_image.tilesource.utilities
|
358
|
+
|
359
|
+
_omeUnitsToMeters = {
|
360
|
+
'Ym': 1e24,
|
361
|
+
'Zm': 1e21,
|
362
|
+
'Em': 1e18,
|
363
|
+
'Pm': 1e15,
|
364
|
+
'Tm': 1e12,
|
365
|
+
'Gm': 1e9,
|
366
|
+
'Mm': 1e6,
|
367
|
+
'km': 1e3,
|
368
|
+
'hm': 1e2,
|
369
|
+
'dam': 1e1,
|
370
|
+
'm': 1,
|
371
|
+
'dm': 1e-1,
|
372
|
+
'cm': 1e-2,
|
373
|
+
'mm': 1e-3,
|
374
|
+
'\u00b5m': 1e-6,
|
375
|
+
'nm': 1e-9,
|
376
|
+
'pm': 1e-12,
|
377
|
+
'fm': 1e-15,
|
378
|
+
'am': 1e-18,
|
379
|
+
'zm': 1e-21,
|
380
|
+
'ym': 1e-24,
|
381
|
+
'\u00c5': 1e-10,
|
382
|
+
}
|
383
|
+
|
384
|
+
try:
|
385
|
+
root = xml.etree.ElementTree.fromstring(self._tf.pages[0].description)
|
386
|
+
self._xml = large_image.tilesource.utilities.etreeToDict(root)
|
387
|
+
except Exception:
|
388
|
+
return
|
389
|
+
try:
|
390
|
+
try:
|
391
|
+
base = self._xml['OME']['Image'][0]['Pixels']
|
392
|
+
except Exception:
|
393
|
+
base = self._xml['OME']['Image']['Pixels']
|
394
|
+
if self._mm_x is None and 'PhysicalSizeX' in base:
|
395
|
+
self._mm_x = (
|
396
|
+
float(base['PhysicalSizeX']) * 1e3 *
|
397
|
+
_omeUnitsToMeters[base.get('PhysicalSizeXUnit', '\u00b5m')])
|
398
|
+
if self._mm_y is None and 'PhysicalSizeY' in base:
|
399
|
+
self._mm_y = (
|
400
|
+
float(base['PhysicalSizeY']) * 1e3 *
|
401
|
+
_omeUnitsToMeters[base.get('PhysicalSizeYUnit', '\u00b5m')])
|
402
|
+
self._mm_x = self._mm_x or self._mm_y
|
403
|
+
self._mm_y = self._mm_y or self._mm_x
|
404
|
+
except Exception:
|
405
|
+
pass
|
406
|
+
|
288
407
|
def _handle_scn(self): # noqa
|
289
408
|
"""
|
290
409
|
For SCN files, parse the xml and possibly adjust how associated images
|
@@ -350,6 +469,20 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
350
469
|
except Exception:
|
351
470
|
pass
|
352
471
|
|
472
|
+
def _handle_internal_ndpi(self, intmeta):
|
473
|
+
try:
|
474
|
+
ndpi = intmeta.pop('65449')
|
475
|
+
intmeta['ndpi'] = {}
|
476
|
+
for line in ndpi.replace('\r', '\n').split('\n'):
|
477
|
+
if '=' in line:
|
478
|
+
key, value = line.split('=', 1)
|
479
|
+
key = key.strip()
|
480
|
+
value = value.strip()
|
481
|
+
if key and key not in intmeta['ndpi'] and value:
|
482
|
+
intmeta['ndpi'][key] = value
|
483
|
+
except Exception:
|
484
|
+
pass
|
485
|
+
|
353
486
|
def getNativeMagnification(self):
|
354
487
|
"""
|
355
488
|
Get the magnification at a particular level.
|
@@ -419,6 +552,10 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
419
552
|
json.dumps(result[key][subkey])
|
420
553
|
except Exception:
|
421
554
|
del result[key][subkey]
|
555
|
+
for key in dir(self._tf):
|
556
|
+
if (key.startswith('is_') and hasattr(self, '_handle_internal_' + key[3:]) and
|
557
|
+
getattr(self._tf, key)):
|
558
|
+
getattr(self, '_handle_internal_' + key[3:])(result)
|
422
559
|
if hasattr(self, '_xml') and 'xml' not in result:
|
423
560
|
result.pop('ImageDescription', None)
|
424
561
|
result['xml'] = self._xml
|
@@ -473,19 +610,12 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
473
610
|
sidx = frame // self._basis['P'][0]
|
474
611
|
else:
|
475
612
|
sidx = 0
|
476
|
-
series = self._tf.series[self._series[sidx]]
|
477
613
|
nonempty = [None] * self.levels
|
478
614
|
nonempty[self.levels - 1] = True
|
615
|
+
series = self._tf.series[self._series[sidx]]
|
616
|
+
za, hasgbs = self._getZarrArray(series, sidx)
|
479
617
|
xidx = series.axes.index('X')
|
480
618
|
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
619
|
for ll in range(1, len(series.levels)):
|
490
620
|
scale = round(math.log(max(za[0].shape[xidx] / za[ll].shape[xidx],
|
491
621
|
za[0].shape[yidx] / za[ll].shape[yidx])) / math.log(2))
|
@@ -496,6 +626,30 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
496
626
|
self._nonempty_levels_list[frame] = nonempty
|
497
627
|
return nonempty
|
498
628
|
|
629
|
+
def getPreferredLevel(self, level):
|
630
|
+
"""
|
631
|
+
Given a desired level (0 is minimum resolution, self.levels - 1 is max
|
632
|
+
resolution), return the level that contains actual data that is no
|
633
|
+
lower resolution.
|
634
|
+
|
635
|
+
:param level: desired level
|
636
|
+
:returns level: a level with actual data that is no lower resolution.
|
637
|
+
"""
|
638
|
+
return max(0, min(level, self.levels - 1))
|
639
|
+
|
640
|
+
def _getZarrArray(self, series, sidx):
|
641
|
+
with self._zarrlock:
|
642
|
+
if sidx not in self._zarrcache:
|
643
|
+
if len(self._zarrcache) > 10:
|
644
|
+
self._zarrcache = {}
|
645
|
+
za = zarr.open(series.aszarr(), mode='r')
|
646
|
+
hasgbs = hasattr(za[0], 'get_basic_selection')
|
647
|
+
if not hasgbs and math.prod(series.shape) < 256 * 1024 ** 2:
|
648
|
+
za = series.asarray()
|
649
|
+
self._zarrcache[sidx] = (za, hasgbs)
|
650
|
+
za, hasgbs = self._zarrcache[sidx]
|
651
|
+
return za, hasgbs
|
652
|
+
|
499
653
|
@methodcache()
|
500
654
|
def getTile(self, x, y, z, pilImageAllowed=False, numpyAllowed=False, **kwargs):
|
501
655
|
frame = self._getFrame(**kwargs)
|
@@ -506,14 +660,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
506
660
|
else:
|
507
661
|
sidx = 0
|
508
662
|
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]
|
663
|
+
za, hasgbs = self._getZarrArray(series, sidx)
|
517
664
|
xidx = series.axes.index('X')
|
518
665
|
yidx = series.axes.index('Y')
|
519
666
|
if hasgbs:
|
@@ -533,7 +680,7 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
533
680
|
else:
|
534
681
|
bza = za
|
535
682
|
if step > 2 ** self._maxSkippedLevels:
|
536
|
-
tile = self._getTileFromEmptyLevel(x, y, z, **kwargs)
|
683
|
+
tile, _format = self._getTileFromEmptyLevel(x, y, z, **kwargs)
|
537
684
|
tile = large_image.tilesource.base._imageToNumpy(tile)[0]
|
538
685
|
else:
|
539
686
|
sel = []
|
@@ -549,6 +696,8 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
549
696
|
sel.append(slice(series.shape[aidx]))
|
550
697
|
baxis += 'S'
|
551
698
|
else:
|
699
|
+
if axis not in self._basis and axis == 'I':
|
700
|
+
axis = 'C'
|
552
701
|
sel.append((frame // self._basis[axis][0]) % self._basis[axis][2])
|
553
702
|
tile = bza[tuple(sel)]
|
554
703
|
# rotate
|
@@ -558,6 +707,16 @@ class TifffileFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
558
707
|
return self._outputTile(tile, TILE_FORMAT_NUMPY, x, y, z,
|
559
708
|
pilImageAllowed, numpyAllowed, **kwargs)
|
560
709
|
|
710
|
+
@classmethod
|
711
|
+
def addKnownExtensions(cls):
|
712
|
+
if not hasattr(cls, '_addedExtensions'):
|
713
|
+
_lazyImport()
|
714
|
+
cls._addedExtensions = True
|
715
|
+
cls.extensions = cls.extensions.copy()
|
716
|
+
for ext in tifffile.TIFF.FILE_EXTENSIONS:
|
717
|
+
if ext not in cls.extensions:
|
718
|
+
cls.extensions[ext] = SourcePriority.IMPLICIT
|
719
|
+
|
561
720
|
|
562
721
|
def open(*args, **kwargs):
|
563
722
|
"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: large-image-source-tifffile
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.30.7.dev12
|
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,9 +15,16 @@ 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
|
19
|
-
|
20
|
+
Description-Content-Type: text/x-rst
|
20
21
|
License-File: LICENSE
|
22
|
+
Requires-Dist: large-image>=1.30.7.dev12
|
23
|
+
Requires-Dist: dask[array]
|
24
|
+
Requires-Dist: tifffile[all]
|
25
|
+
Requires-Dist: zarr
|
26
|
+
Provides-Extra: girder
|
27
|
+
Requires-Dist: girder-large-image>=1.30.7.dev12; extra == "girder"
|
21
28
|
|
22
29
|
A tifffile tilesource for large_image.
|
23
30
|
|
{large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/setup.py
RENAMED
@@ -19,8 +19,7 @@ def prerelease_local_scheme(version):
|
|
19
19
|
|
20
20
|
if os.getenv('CIRCLE_BRANCH') in ('master', ):
|
21
21
|
return ''
|
22
|
-
|
23
|
-
return get_local_node_and_date(version)
|
22
|
+
return get_local_node_and_date(version)
|
24
23
|
|
25
24
|
|
26
25
|
try:
|
@@ -37,6 +36,7 @@ setup(
|
|
37
36
|
'fallback_version': '0.0.0'},
|
38
37
|
description=description,
|
39
38
|
long_description=long_description,
|
39
|
+
long_description_content_type='text/x-rst',
|
40
40
|
license='Apache Software License 2.0',
|
41
41
|
author='Kitware, Inc.',
|
42
42
|
author_email='kitware@kitware.com',
|
@@ -49,6 +49,7 @@ setup(
|
|
49
49
|
'Programming Language :: Python :: 3.10',
|
50
50
|
'Programming Language :: Python :: 3.11',
|
51
51
|
'Programming Language :: Python :: 3.12',
|
52
|
+
'Programming Language :: Python :: 3.13',
|
52
53
|
],
|
53
54
|
install_requires=[
|
54
55
|
f'large-image{limit_version}',
|
{large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/LICENSE
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/pyproject.toml
RENAMED
File without changes
|
{large-image-source-tifffile-1.27.5.dev6 → large_image_source_tifffile-1.30.7.dev12}/setup.cfg
RENAMED
File without changes
|