large-image-source-vips 1.23.7.dev4__tar.gz → 1.33.4.dev37__tar.gz
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_vips-1.33.4.dev37/PKG-INFO +42 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/README.rst +48 -60
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/large_image_source_vips/__init__.py +151 -34
- large_image_source_vips-1.33.4.dev37/large_image_source_vips.egg-info/PKG-INFO +42 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/large_image_source_vips.egg-info/SOURCES.txt +1 -0
- large_image_source_vips-1.33.4.dev37/large_image_source_vips.egg-info/requires.txt +7 -0
- large_image_source_vips-1.33.4.dev37/pyproject.toml +7 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/setup.py +7 -29
- large-image-source-vips-1.23.7.dev4/PKG-INFO +0 -25
- large-image-source-vips-1.23.7.dev4/large_image_source_vips.egg-info/PKG-INFO +0 -25
- large-image-source-vips-1.23.7.dev4/large_image_source_vips.egg-info/requires.txt +0 -10
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/LICENSE +0 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/large_image_source_vips/girder_source.py +0 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/large_image_source_vips.egg-info/dependency_links.txt +0 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/large_image_source_vips.egg-info/entry_points.txt +0 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/large_image_source_vips.egg-info/top_level.txt +0 -0
- {large-image-source-vips-1.23.7.dev4 → large_image_source_vips-1.33.4.dev37}/setup.cfg +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: large-image-source-vips
|
|
3
|
+
Version: 1.33.4.dev37
|
|
4
|
+
Summary: A libvips tilesource for large_image.
|
|
5
|
+
Home-page: https://github.com/girder/large_image
|
|
6
|
+
Author: Kitware, Inc.
|
|
7
|
+
Author-email: kitware@kitware.com
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Keywords: large_image,tile source
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/x-rst
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: large-image>=1.33.4.dev37
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: packaging
|
|
23
|
+
Requires-Dist: pyvips
|
|
24
|
+
Provides-Extra: girder
|
|
25
|
+
Requires-Dist: girder-large-image; extra == "girder"
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: author-email
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
Dynamic: provides-extra
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
39
|
+
|
|
40
|
+
A libvips tilesource for large_image.
|
|
41
|
+
|
|
42
|
+
See the large-image package for more details.
|
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
Large Image
|
|
2
2
|
===========
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
.. image:: https://img.shields.io/circleci/build/github/girder/large_image.svg
|
|
5
|
+
:target: https://circleci.com/gh/girder/large_image
|
|
6
|
+
:alt: Build Status
|
|
5
7
|
|
|
6
|
-
..
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
.. image:: https://img.shields.io/badge/license-Apache%202-blue.svg
|
|
9
|
+
:target: https://raw.githubusercontent.com/girder/large_image/master/LICENSE
|
|
10
|
+
:alt: License
|
|
9
11
|
|
|
10
|
-
..
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
.. image:: https://img.shields.io/codecov/c/github/girder/large_image.svg
|
|
13
|
+
:target: https://codecov.io/github/girder/large_image?branch=master
|
|
14
|
+
:alt: codecov.io
|
|
13
15
|
|
|
14
|
-
..
|
|
15
|
-
|
|
16
|
-
:alt: codecov.io
|
|
16
|
+
.. image:: https://img.shields.io/badge/DOI-10.5281%2Fzenodo.4562625-blue.svg
|
|
17
|
+
:target: https://doi.org/10.5281/zenodo.4562625
|
|
17
18
|
|
|
18
|
-
..
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
.. |pypi-badge| image:: https://img.shields.io/pypi/v/large-image.svg?logo=python&logoColor=white
|
|
22
|
-
:target: https://pypi.org/project/large-image/
|
|
19
|
+
.. image:: https://img.shields.io/pypi/v/large-image.svg?logo=python&logoColor=white
|
|
20
|
+
:target: https://pypi.org/project/large-image/
|
|
23
21
|
|
|
24
22
|
*Python modules to work with large, multiresolution images.*
|
|
25
23
|
|
|
@@ -39,16 +37,20 @@ Highlights
|
|
|
39
37
|
Installation
|
|
40
38
|
------------
|
|
41
39
|
|
|
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:
|
|
40
|
+
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
41
|
|
|
44
42
|
Pip
|
|
45
43
|
~~~
|
|
46
44
|
|
|
45
|
+
Install common tile sources on linux, OSX, or Windows::
|
|
46
|
+
|
|
47
|
+
pip install large-image[common]
|
|
48
|
+
|
|
47
49
|
Install all tile sources on linux::
|
|
48
50
|
|
|
49
51
|
pip install large-image[all] --find-links https://girder.github.io/large_image_wheels
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
When using large-image with an instance of `Girder`_, install all tile sources and all Girder plugins on linux::
|
|
52
54
|
|
|
53
55
|
pip install large-image[all] girder-large-image-annotation[tasks] --find-links https://girder.github.io/large_image_wheels
|
|
54
56
|
|
|
@@ -56,8 +58,9 @@ Install all tile sources and all Girder plugins on linux::
|
|
|
56
58
|
Conda
|
|
57
59
|
~~~~~
|
|
58
60
|
|
|
59
|
-
Conda makes dependency management a bit easier if not on Linux.
|
|
61
|
+
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::
|
|
60
62
|
|
|
63
|
+
conda install -c conda-forge large-image
|
|
61
64
|
conda install -c conda-forge large-image-source-gdal
|
|
62
65
|
conda install -c conda-forge large-image-source-tiff
|
|
63
66
|
conda install -c conda-forge large-image-converter
|
|
@@ -101,81 +104,66 @@ Large Image consists of several Python modules designed to work together. These
|
|
|
101
104
|
|
|
102
105
|
- ``performance``: include optional modules that can improve performance
|
|
103
106
|
|
|
107
|
+
- ``common``: all of the tile sources and above packages that will install directly from pypi without other external libraries on linux, OSX, and Windows.
|
|
108
|
+
|
|
104
109
|
- ``all``: for all of the above
|
|
105
110
|
|
|
106
111
|
- ``large-image-converter``: A utility for using pyvips and other libraries to convert images into pyramidal tiff files that can be read efficiently by large_image.
|
|
107
|
-
You can specify extras_require of ``jp2k`` to include modules to allow output to JPEG2000 compression, ``sources`` to include all sources,
|
|
112
|
+
You can specify extras_require of ``jp2k`` to include modules to allow output to JPEG2000 compression, ``sources`` to include all sources, ``stats`` to include modules to allow computing compression noise statistics, ``geospatial`` to include support for converting geospatial sources, or ``all`` for all of the optional extras_require.
|
|
108
113
|
|
|
109
114
|
- Tile sources:
|
|
110
115
|
|
|
111
|
-
- ``large-image-source-
|
|
112
|
-
|
|
113
|
-
- ``large-image-source-openslide``: A tile source using the OpenSlide library. This works with svs, ndpi, Mirax, tiff, vms, and other file formats.
|
|
116
|
+
- ``large-image-source-bioformats``: A tile source for reading any file handled by the Java Bioformats library.
|
|
114
117
|
|
|
115
|
-
- ``large-image-source-
|
|
118
|
+
- ``large-image-source-deepzoom``: A tile source for reading Deepzoom tiles.
|
|
116
119
|
|
|
117
|
-
- ``large-image-source-
|
|
120
|
+
- ``large-image-source-dicom``: A tile source for reading DICOM Whole Slide Images (WSI).
|
|
118
121
|
|
|
119
122
|
- ``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.
|
|
120
123
|
|
|
121
124
|
- ``large-image-source-mapnik``: A tile source for reading geotiff and netcdf files via Mapnik and GDAL. This handles more vector issues than the gdal tile source.
|
|
122
125
|
|
|
123
|
-
- ``large-image-source-openjpeg``: A tile source using the Glymur library to read jp2 (JPEG 2000) files.
|
|
124
|
-
|
|
125
|
-
- ``large-image-source-nd2``: A tile source for reading nd2 (NIS Element) images.
|
|
126
|
-
|
|
127
|
-
- ``large-image-source-bioformats``: A tile source for reading any file handled by the Java Bioformats library.
|
|
128
|
-
|
|
129
|
-
- ``large-image-source-deepzoom``: A tile source for reading Deepzoom tiles.
|
|
130
|
-
|
|
131
126
|
- ``large-image-source-multi``: A tile source for compositing other tile sources into a single multi-frame source.
|
|
132
127
|
|
|
133
|
-
- ``large-image-source-
|
|
134
|
-
|
|
135
|
-
- ``large-image-source-tifffile``: A tile source using the tifffile library that can handle a wide variety of tiff-like files.
|
|
128
|
+
- ``large-image-source-nd2``: A tile source for reading nd2 (NIS Element) images.
|
|
136
129
|
|
|
137
|
-
- ``large-image-source-
|
|
130
|
+
- ``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.
|
|
138
131
|
|
|
139
|
-
- ``large-image-source-
|
|
140
|
-
|
|
141
|
-
- ``large-image-source-dummy``: A tile source that does nothing.
|
|
132
|
+
- ``large-image-source-openjpeg``: A tile source using the Glymur library to read jp2 (JPEG 2000) files.
|
|
142
133
|
|
|
143
|
-
|
|
134
|
+
- ``large-image-source-openslide``: A tile source using the OpenSlide library. This works with svs, ndpi, Mirax, tiff, vms, and other file formats.
|
|
144
135
|
|
|
145
|
-
-
|
|
136
|
+
- ``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.
|
|
146
137
|
|
|
147
|
-
- ``
|
|
148
|
-
You can specify extras_require of ``tasks`` to install a Girder Worker task that can convert otherwise unreadable images to pyramidal tiff files.
|
|
138
|
+
- ``large-image-source-tiff``: A tile source for reading pyramidal tiff files in common compression formats.
|
|
149
139
|
|
|
150
|
-
- ``
|
|
140
|
+
- ``large-image-source-tifffile``: A tile source using the tifffile library that can handle a wide variety of tiff-like files.
|
|
151
141
|
|
|
152
|
-
- ``large-image-
|
|
153
|
-
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.
|
|
142
|
+
- ``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).
|
|
154
143
|
|
|
144
|
+
- ``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.
|
|
155
145
|
|
|
156
|
-
|
|
157
|
-
----------------------
|
|
146
|
+
- ``large-image-source-test``: A tile source that generates test tiles, including a simple fractal pattern. Useful for testing extreme zoom levels.
|
|
158
147
|
|
|
159
|
-
|
|
148
|
+
- ``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.
|
|
160
149
|
|
|
161
|
-
git clone https://github.com/girder/large_image.git
|
|
162
|
-
cd large_image
|
|
163
150
|
|
|
164
|
-
|
|
151
|
+
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.
|
|
152
|
+
In the Girder UI, ``large-image`` shows images on item pages, and can show thumbnails in item lists when browsing folders.
|
|
153
|
+
There is also cache management to balance memory use and speed of response in Girder when ``large-image`` is used as a tile server.
|
|
165
154
|
|
|
166
|
-
|
|
155
|
+
Most tile sources can be used with Girder Large Image. You can specify an extras_require of ``girder`` to install the following packages:
|
|
167
156
|
|
|
168
|
-
|
|
157
|
+
- ``girder-large-image``: Large Image as a Girder 3.x plugin.
|
|
169
158
|
|
|
170
|
-
|
|
159
|
+
You can install ``large-image[tasks]`` to install a Girder Worker task that can convert otherwise unreadable images to pyramidal tiff files.
|
|
171
160
|
|
|
161
|
+
- ``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.
|
|
172
162
|
|
|
173
|
-
|
|
174
|
-
=========================
|
|
163
|
+
- ``large-image-tasks``: A utility for running the converter via Girder Worker.
|
|
175
164
|
|
|
176
|
-
|
|
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.
|
|
177
166
|
|
|
178
|
-
pip install -e . -r requirements-dev.txt --find-links https://girder.github.io/large_image_wheels
|
|
179
167
|
|
|
180
168
|
|
|
181
|
-
.. _Girder: https://
|
|
169
|
+
.. _Girder: https://girder.readthedocs.io/en/latest/
|
|
@@ -16,22 +16,28 @@ from large_image.constants import (NEW_IMAGE_PATH_FLAG, TILE_FORMAT_NUMPY,
|
|
|
16
16
|
dtypeToGValue)
|
|
17
17
|
from large_image.exceptions import TileSourceError, TileSourceFileNotFoundError
|
|
18
18
|
from large_image.tilesource import FileTileSource
|
|
19
|
-
from large_image.tilesource.utilities import _imageToNumpy
|
|
19
|
+
from large_image.tilesource.utilities import _imageToNumpy, _newFromFileLock, nearPowerOfTwo
|
|
20
20
|
|
|
21
21
|
logging.getLogger('pyvips').setLevel(logging.ERROR)
|
|
22
22
|
|
|
23
23
|
# Default to ignoring files with no extension and some specific extensions.
|
|
24
|
-
config.ConfigValues
|
|
25
|
-
r'(^[^.]*|\.(yml|yaml|json|png|svs))$'
|
|
24
|
+
config.ConfigValues.setdefault(
|
|
25
|
+
'source_vips_ignored_names', r'(^[^.]*|\.(yml|yaml|json|png|svs|mrxs))$')
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _clearVipsCache():
|
|
29
|
-
|
|
30
|
-
pyvips.
|
|
31
|
-
pyvips.
|
|
32
|
-
|
|
33
|
-
pyvips.
|
|
34
|
-
pyvips.
|
|
29
|
+
oldfiles = pyvips.cache_get_max_files()
|
|
30
|
+
oldmax = pyvips.cache_get_max()
|
|
31
|
+
oldmem = pyvips.cache_get_max_mem()
|
|
32
|
+
# print('Clearing vips cache: size %r, max files %r, max %r, mem %r' % (
|
|
33
|
+
# pyvips.cache_get_size(), oldfiles, oldmax, oldmem))
|
|
34
|
+
pyvips.cache_set_max_files(0)
|
|
35
|
+
# This shouldn't ever go to zero
|
|
36
|
+
pyvips.cache_set_max(1)
|
|
37
|
+
pyvips.cache_set_max_mem(0)
|
|
38
|
+
pyvips.cache_set_max_files(oldfiles)
|
|
39
|
+
pyvips.cache_set_max(oldmax)
|
|
40
|
+
pyvips.cache_set_max_mem(oldmem)
|
|
35
41
|
|
|
36
42
|
|
|
37
43
|
_cacheClearFuncs.append(_clearVipsCache)
|
|
@@ -50,10 +56,11 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
50
56
|
mimeTypes = {
|
|
51
57
|
None: SourcePriority.FALLBACK,
|
|
52
58
|
}
|
|
59
|
+
newPriority = SourcePriority.MEDIUM
|
|
53
60
|
|
|
54
61
|
_tileSize = 256
|
|
55
62
|
|
|
56
|
-
def __init__(self, path, **kwargs):
|
|
63
|
+
def __init__(self, path, **kwargs): # noqa
|
|
57
64
|
"""
|
|
58
65
|
Initialize the tile class. See the base class for other available
|
|
59
66
|
parameters.
|
|
@@ -61,20 +68,29 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
61
68
|
:param path: a filesystem path for the tile source.
|
|
62
69
|
"""
|
|
63
70
|
super().__init__(path, **kwargs)
|
|
71
|
+
self.addKnownExtensions()
|
|
64
72
|
|
|
73
|
+
self._suffix = ''
|
|
65
74
|
if str(path).startswith(NEW_IMAGE_PATH_FLAG):
|
|
66
|
-
|
|
75
|
+
self._initNew(**kwargs)
|
|
76
|
+
return
|
|
67
77
|
self._largeImagePath = str(self._getLargeImagePath())
|
|
68
78
|
self._editable = False
|
|
69
79
|
|
|
70
|
-
|
|
80
|
+
config._ignoreSourceNames('vips', self._largeImagePath)
|
|
71
81
|
try:
|
|
72
|
-
|
|
82
|
+
with _newFromFileLock:
|
|
83
|
+
self._image = pyvips.Image.new_from_file(self._largeImagePath)
|
|
73
84
|
except pyvips.error.Error:
|
|
74
85
|
if not os.path.isfile(self._largeImagePath):
|
|
75
86
|
raise TileSourceFileNotFoundError(self._largeImagePath) from None
|
|
76
87
|
msg = 'File cannot be opened via pyvips'
|
|
77
88
|
raise TileSourceError(msg)
|
|
89
|
+
# Ask pdfs to render at a higher resolution
|
|
90
|
+
if ('vips-loader' in self._image.get_fields() and
|
|
91
|
+
self._image.get('vips-loader') in {'pdfload'}):
|
|
92
|
+
self._suffix = ',dpi=144'
|
|
93
|
+
self._image = pyvips.Image.new_from_file(self._largeImagePath + '[dpi=300]')
|
|
78
94
|
self.sizeX = self._image.width
|
|
79
95
|
self.sizeY = self._image.height
|
|
80
96
|
self.tileWidth = self.tileHeight = self._tileSize
|
|
@@ -82,15 +98,29 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
82
98
|
if 'n-pages' in self._image.get_fields():
|
|
83
99
|
pages = self._image.get('n-pages')
|
|
84
100
|
self._frames = [0]
|
|
101
|
+
self._lowres = {}
|
|
85
102
|
for page in range(1, pages):
|
|
86
|
-
subInputPath = self._largeImagePath + '[page
|
|
87
|
-
|
|
103
|
+
subInputPath = self._largeImagePath + f'[page={page}{self._suffix}]'
|
|
104
|
+
with _newFromFileLock:
|
|
105
|
+
try:
|
|
106
|
+
subImage = pyvips.Image.new_from_file(subInputPath)
|
|
107
|
+
except Exception:
|
|
108
|
+
continue
|
|
88
109
|
if subImage.width == self.sizeX and subImage.height == self.sizeY:
|
|
89
110
|
self._frames.append(page)
|
|
90
111
|
continue
|
|
112
|
+
if (self.sizeX - 16 < subImage.width <= self.sizeX and
|
|
113
|
+
self.sizeY - 16 < subImage.height <= self.sizeY):
|
|
114
|
+
self._frames.append(page)
|
|
115
|
+
continue
|
|
91
116
|
if subImage.width * subImage.height < self.sizeX * self.sizeY:
|
|
117
|
+
if (nearPowerOfTwo(self.sizeX, subImage.width) and
|
|
118
|
+
nearPowerOfTwo(self.sizeY, subImage.height)):
|
|
119
|
+
level = int(round(math.log(self.sizeX / subImage.width) / math.log(2)))
|
|
120
|
+
self._lowres.setdefault(len(self._frames) - 1, {})[level] = page
|
|
92
121
|
continue
|
|
93
122
|
self._frames = [page]
|
|
123
|
+
self._lowres = {}
|
|
94
124
|
self.sizeX = subImage.width
|
|
95
125
|
self.sizeY = subImage.height
|
|
96
126
|
try:
|
|
@@ -98,12 +128,41 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
98
128
|
except Exception:
|
|
99
129
|
pass
|
|
100
130
|
self._image = subImage
|
|
131
|
+
self._checkLowerLevels()
|
|
101
132
|
self.levels = int(max(1, math.ceil(math.log(
|
|
102
133
|
float(max(self.sizeX, self.sizeY)) / self.tileWidth) / math.log(2)) + 1))
|
|
103
|
-
if len(self._frames) > 1:
|
|
134
|
+
if len(self._frames) > 1 or self._lowres is not None:
|
|
104
135
|
self._recentFrames = cachetools.LRUCache(maxsize=6)
|
|
105
136
|
self._frameLock = threading.RLock()
|
|
106
137
|
|
|
138
|
+
def _checkLowerLevels(self):
|
|
139
|
+
if (len(self._lowres) != len(self._frames) or
|
|
140
|
+
min(len(v) for v in self._lowres.values()) !=
|
|
141
|
+
max(len(v) for v in self._lowres.values()) or
|
|
142
|
+
min(len(v) for v in self._lowres.values()) == 0):
|
|
143
|
+
self._lowres = None
|
|
144
|
+
if len(self._frames) == 1 and 'openslide.level-count' in self._image.get_fields():
|
|
145
|
+
self._lowres = [{}]
|
|
146
|
+
for oslevel in range(1, int(self._image.get('openslide.level-count'))):
|
|
147
|
+
with _newFromFileLock:
|
|
148
|
+
try:
|
|
149
|
+
subImage = pyvips.Image.new_from_file(
|
|
150
|
+
self._largeImagePath, level=oslevel)
|
|
151
|
+
except Exception:
|
|
152
|
+
continue
|
|
153
|
+
if subImage.width * subImage.height < self.sizeX * self.sizeY:
|
|
154
|
+
if (nearPowerOfTwo(self.sizeX, subImage.width) and
|
|
155
|
+
nearPowerOfTwo(self.sizeY, subImage.height)):
|
|
156
|
+
level = int(round(math.log(
|
|
157
|
+
self.sizeX / subImage.width) / math.log(2)))
|
|
158
|
+
self._lowres[0][level] = (self._frames[0], oslevel)
|
|
159
|
+
if not len(self._lowres[0]):
|
|
160
|
+
self._lowres = None
|
|
161
|
+
else:
|
|
162
|
+
self._lowres = list(self._lowres.values())
|
|
163
|
+
if self._lowres is not None:
|
|
164
|
+
self._populatedLevels = len(self._lowres[0]) + 1
|
|
165
|
+
|
|
107
166
|
def _initNew(self, **kwargs):
|
|
108
167
|
"""
|
|
109
168
|
Initialize the tile class for creating a new image.
|
|
@@ -115,6 +174,7 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
115
174
|
self.sizeX = self.sizeY = self.levels = 0
|
|
116
175
|
self.tileWidth = self.tileHeight = self._tileSize
|
|
117
176
|
self._frames = [0]
|
|
177
|
+
self._lowres = None
|
|
118
178
|
self._cacheValue = str(uuid.uuid4())
|
|
119
179
|
self._output = None
|
|
120
180
|
self._editable = True
|
|
@@ -170,24 +230,38 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
170
230
|
self._addMetadataFrameInformation(result)
|
|
171
231
|
return result
|
|
172
232
|
|
|
173
|
-
def _getFrameImage(self, frame=0):
|
|
233
|
+
def _getFrameImage(self, frame=0, lowres=None):
|
|
174
234
|
"""
|
|
175
235
|
Get the vips image associated with a specific frame.
|
|
176
236
|
|
|
177
237
|
:param frame: the 0-based frame to get.
|
|
238
|
+
:param lowres: the lower resolution part of the frame
|
|
178
239
|
:returns: a vips image.
|
|
179
240
|
"""
|
|
180
241
|
if self._image is None and self._output:
|
|
181
242
|
self._outputToImage()
|
|
182
243
|
img = self._image
|
|
183
|
-
if frame > 0:
|
|
244
|
+
if frame > 0 or lowres:
|
|
184
245
|
with self._frameLock:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
246
|
+
key = (frame, lowres)
|
|
247
|
+
frameval = self._frames[frame]
|
|
248
|
+
params = {}
|
|
249
|
+
if lowres is not None:
|
|
250
|
+
if isinstance(self._lowres[frame][lowres], tuple):
|
|
251
|
+
frameval = self._lowres[frame][lowres][0]
|
|
252
|
+
params = {'level': self._lowres[frame][lowres][1]}
|
|
253
|
+
else:
|
|
254
|
+
frameval = self._lowres[frame][lowres]
|
|
255
|
+
if key not in self._recentFrames:
|
|
256
|
+
if frameval:
|
|
257
|
+
subpath = self._largeImagePath + f'[page={frameval}{self._suffix}]'
|
|
258
|
+
else:
|
|
259
|
+
subpath = self._largeImagePath
|
|
260
|
+
with _newFromFileLock:
|
|
261
|
+
img = pyvips.Image.new_from_file(subpath, **params)
|
|
262
|
+
self._recentFrames[key] = img
|
|
189
263
|
else:
|
|
190
|
-
img = self._recentFrames[
|
|
264
|
+
img = self._recentFrames[key]
|
|
191
265
|
return img
|
|
192
266
|
|
|
193
267
|
def getNativeMagnification(self):
|
|
@@ -206,14 +280,35 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
206
280
|
def getTile(self, x, y, z, pilImageAllowed=False, numpyAllowed=False, **kwargs):
|
|
207
281
|
frame = self._getFrame(**kwargs)
|
|
208
282
|
self._xyzInRange(x, y, z, frame, len(self._frames))
|
|
209
|
-
img = self._getFrameImage(frame)
|
|
210
283
|
x0, y0, x1, y1, step = self._xyzToCorners(x, y, z)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
284
|
+
lowres = None
|
|
285
|
+
if self._lowres and step > 1:
|
|
286
|
+
use = 0
|
|
287
|
+
for ll in self._lowres[frame].keys():
|
|
288
|
+
if 2 ** ll <= step:
|
|
289
|
+
use = max(use, ll)
|
|
290
|
+
if use:
|
|
291
|
+
lowres = use
|
|
292
|
+
div = 2 ** use
|
|
293
|
+
x0 //= div
|
|
294
|
+
y0 //= div
|
|
295
|
+
x1 //= div
|
|
296
|
+
y1 //= div
|
|
297
|
+
step //= div
|
|
298
|
+
img = self._getFrameImage(frame, lowres)
|
|
299
|
+
tileimg = img.crop(min(x0, img.width), min(y0, img.height),
|
|
300
|
+
min(x1, img.width) - min(x0, img.width),
|
|
301
|
+
min(y1, img.height) - min(y0, img.height))
|
|
302
|
+
try:
|
|
303
|
+
if step != 1:
|
|
304
|
+
tileimg = tileimg.resize(1.0 / step, kernel=pyvips.enums.Kernel.NEAREST, gap=0)
|
|
305
|
+
tile = np.ndarray(
|
|
306
|
+
buffer=tileimg.write_to_memory(),
|
|
307
|
+
dtype=GValueToDtype[tileimg.format],
|
|
308
|
+
shape=[tileimg.height, tileimg.width, tileimg.bands])
|
|
309
|
+
except Exception:
|
|
310
|
+
self.logger.exception('Failed to getTile')
|
|
311
|
+
tile = np.zeros((1, 1))
|
|
217
312
|
return self._outputTile(tile, TILE_FORMAT_NUMPY, x, y, z,
|
|
218
313
|
pilImageAllowed, numpyAllowed, **kwargs)
|
|
219
314
|
|
|
@@ -298,7 +393,8 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
298
393
|
"""
|
|
299
394
|
if self._output is not None:
|
|
300
395
|
self._image = None
|
|
301
|
-
w
|
|
396
|
+
w = self._output['width'] - min(0, self._output['minx'])
|
|
397
|
+
h = self._output['height'] - min(0, self._output['miny'])
|
|
302
398
|
w = max(self.minWidth or w, w)
|
|
303
399
|
h = max(self.minHeight or h, h)
|
|
304
400
|
self.sizeX = w
|
|
@@ -310,7 +406,10 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
310
406
|
def addTile(self, tile, x=0, y=0, mask=None, interpretation=None):
|
|
311
407
|
"""
|
|
312
408
|
Add a numpy or image tile to the image, expanding the image as needed
|
|
313
|
-
to accommodate it.
|
|
409
|
+
to accommodate it. Note that x and y can be negative. If so, the
|
|
410
|
+
output image (and internal memory access of the image) will act as if
|
|
411
|
+
the 0, 0 point is the most negative position. Cropping is applied
|
|
412
|
+
after this offset.
|
|
314
413
|
|
|
315
414
|
:param tile: a numpy array, PIL Image, vips image, or a binary string
|
|
316
415
|
with an image. The numpy array can have 2 or 3 dimensions.
|
|
@@ -431,7 +530,9 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
431
530
|
if img.format == 'float' and entry['image'].format == 'double':
|
|
432
531
|
entryimage = entryimage.cast(img.format)
|
|
433
532
|
branch = branch.composite(
|
|
434
|
-
entryimage, pyvips.BlendMode.OVER,
|
|
533
|
+
entryimage, pyvips.BlendMode.OVER,
|
|
534
|
+
x=entry['x'] - min(0, self._output['minx']),
|
|
535
|
+
y=entry['y'] - min(0, self._output['miny']))
|
|
435
536
|
if not ((idx + 1) % leaves) or idx + 1 == len(self._output['images']):
|
|
436
537
|
trunk = trunk.composite(branch, pyvips.BlendMode.OVER, x=0, y=0)
|
|
437
538
|
branch = baseimg.copy()
|
|
@@ -593,9 +694,25 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
|
|
|
593
694
|
if not self._editable:
|
|
594
695
|
return self._image.format
|
|
595
696
|
return self._getVipsFormat()
|
|
596
|
-
|
|
597
697
|
# TODO: specify bit depth / bandFormat explicitly
|
|
598
698
|
|
|
699
|
+
@property
|
|
700
|
+
def origin(self):
|
|
701
|
+
if not self._editable:
|
|
702
|
+
return {'x': 0, 'y': 0}
|
|
703
|
+
return {'x': min(0, self._output['minx'] or 0),
|
|
704
|
+
'y': min(0, self._output['miny'] or 0)}
|
|
705
|
+
|
|
706
|
+
@classmethod
|
|
707
|
+
def addKnownExtensions(cls):
|
|
708
|
+
if not hasattr(cls, '_addedExtensions'):
|
|
709
|
+
cls._addedExtensions = True
|
|
710
|
+
cls.extensions = cls.extensions.copy()
|
|
711
|
+
for dotext in pyvips.base.get_suffixes():
|
|
712
|
+
ext = dotext.lstrip('.')
|
|
713
|
+
if ext not in cls.extensions:
|
|
714
|
+
cls.extensions[ext] = SourcePriority.IMPLICIT
|
|
715
|
+
|
|
599
716
|
|
|
600
717
|
def open(*args, **kwargs):
|
|
601
718
|
"""Create an instance of the module class."""
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: large-image-source-vips
|
|
3
|
+
Version: 1.33.4.dev37
|
|
4
|
+
Summary: A libvips tilesource for large_image.
|
|
5
|
+
Home-page: https://github.com/girder/large_image
|
|
6
|
+
Author: Kitware, Inc.
|
|
7
|
+
Author-email: kitware@kitware.com
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Keywords: large_image,tile source
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/x-rst
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: large-image>=1.33.4.dev37
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: packaging
|
|
23
|
+
Requires-Dist: pyvips
|
|
24
|
+
Provides-Extra: girder
|
|
25
|
+
Requires-Dist: girder-large-image; extra == "girder"
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: author-email
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
Dynamic: provides-extra
|
|
36
|
+
Dynamic: requires-dist
|
|
37
|
+
Dynamic: requires-python
|
|
38
|
+
Dynamic: summary
|
|
39
|
+
|
|
40
|
+
A libvips tilesource for large_image.
|
|
41
|
+
|
|
42
|
+
See the large-image package for more details.
|
|
@@ -6,58 +6,37 @@ description = 'A libvips tilesource for large_image.'
|
|
|
6
6
|
long_description = description + '\n\nSee the large-image package for more details.'
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
def prerelease_local_scheme(version):
|
|
10
|
-
"""
|
|
11
|
-
Return local scheme version unless building on master in CircleCI.
|
|
12
|
-
|
|
13
|
-
This function returns the local scheme version number
|
|
14
|
-
(e.g. 0.0.0.dev<N>+g<HASH>) unless building on CircleCI for a
|
|
15
|
-
pre-release in which case it ignores the hash and produces a
|
|
16
|
-
PEP440 compliant pre-release version number (e.g. 0.0.0.dev<N>).
|
|
17
|
-
"""
|
|
18
|
-
from setuptools_scm.version import get_local_node_and_date
|
|
19
|
-
|
|
20
|
-
if os.getenv('CIRCLE_BRANCH') in ('master', ):
|
|
21
|
-
return ''
|
|
22
|
-
else:
|
|
23
|
-
return get_local_node_and_date(version)
|
|
24
|
-
|
|
25
|
-
|
|
26
9
|
try:
|
|
27
10
|
from setuptools_scm import get_version
|
|
28
11
|
|
|
29
|
-
version = get_version(root='../..'
|
|
30
|
-
limit_version = f'>={version}' if '+' not in version else ''
|
|
12
|
+
version = get_version(root='../..')
|
|
13
|
+
limit_version = f'>={version}' if '+' not in version and not os.getenv('TOX_ENV_NAME') else ''
|
|
31
14
|
except (ImportError, LookupError):
|
|
32
15
|
limit_version = ''
|
|
33
16
|
|
|
34
17
|
setup(
|
|
35
18
|
name='large-image-source-vips',
|
|
36
|
-
use_scm_version={'root': '../..', 'local_scheme': prerelease_local_scheme,
|
|
37
|
-
'fallback_version': '0.0.0'},
|
|
38
|
-
setup_requires=['setuptools-scm'],
|
|
39
19
|
description=description,
|
|
40
20
|
long_description=long_description,
|
|
41
|
-
|
|
21
|
+
long_description_content_type='text/x-rst',
|
|
22
|
+
license='Apache-2.0',
|
|
42
23
|
author='Kitware, Inc.',
|
|
43
24
|
author_email='kitware@kitware.com',
|
|
44
25
|
classifiers=[
|
|
45
26
|
'Development Status :: 5 - Production/Stable',
|
|
46
|
-
'License :: OSI Approved :: Apache Software License',
|
|
47
27
|
'Programming Language :: Python :: 3',
|
|
48
|
-
'Programming Language :: Python :: 3.6',
|
|
49
|
-
'Programming Language :: Python :: 3.7',
|
|
50
|
-
'Programming Language :: Python :: 3.8',
|
|
51
28
|
'Programming Language :: Python :: 3.9',
|
|
52
29
|
'Programming Language :: Python :: 3.10',
|
|
53
30
|
'Programming Language :: Python :: 3.11',
|
|
31
|
+
'Programming Language :: Python :: 3.12',
|
|
32
|
+
'Programming Language :: Python :: 3.13',
|
|
54
33
|
],
|
|
34
|
+
python_requires='>=3.9',
|
|
55
35
|
install_requires=[
|
|
56
36
|
f'large-image{limit_version}',
|
|
57
37
|
'numpy',
|
|
58
38
|
'packaging',
|
|
59
39
|
'pyvips',
|
|
60
|
-
'importlib-metadata<5 ; python_version < "3.8"',
|
|
61
40
|
],
|
|
62
41
|
extras_require={
|
|
63
42
|
'girder': 'girder-large-image',
|
|
@@ -65,7 +44,6 @@ setup(
|
|
|
65
44
|
keywords='large_image, tile source',
|
|
66
45
|
packages=find_packages(exclude=['test', 'test.*']),
|
|
67
46
|
url='https://github.com/girder/large_image',
|
|
68
|
-
python_requires='>=3.6',
|
|
69
47
|
entry_points={
|
|
70
48
|
'large_image.source': [
|
|
71
49
|
'vips = large_image_source_vips:VipsFileTileSource',
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: large-image-source-vips
|
|
3
|
-
Version: 1.23.7.dev4
|
|
4
|
-
Summary: A libvips tilesource for large_image.
|
|
5
|
-
Home-page: https://github.com/girder/large_image
|
|
6
|
-
Author: Kitware, Inc.
|
|
7
|
-
Author-email: kitware@kitware.com
|
|
8
|
-
License: Apache Software License 2.0
|
|
9
|
-
Keywords: large_image,tile source
|
|
10
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Requires-Python: >=3.6
|
|
20
|
-
Provides-Extra: girder
|
|
21
|
-
License-File: LICENSE
|
|
22
|
-
|
|
23
|
-
A libvips tilesource for large_image.
|
|
24
|
-
|
|
25
|
-
See the large-image package for more details.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: large-image-source-vips
|
|
3
|
-
Version: 1.23.7.dev4
|
|
4
|
-
Summary: A libvips tilesource for large_image.
|
|
5
|
-
Home-page: https://github.com/girder/large_image
|
|
6
|
-
Author: Kitware, Inc.
|
|
7
|
-
Author-email: kitware@kitware.com
|
|
8
|
-
License: Apache Software License 2.0
|
|
9
|
-
Keywords: large_image,tile source
|
|
10
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Requires-Python: >=3.6
|
|
20
|
-
Provides-Extra: girder
|
|
21
|
-
License-File: LICENSE
|
|
22
|
-
|
|
23
|
-
A libvips tilesource for large_image.
|
|
24
|
-
|
|
25
|
-
See the large-image package for more details.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|