large-image-source-vips 1.30.7.dev71__tar.gz → 1.31.1.dev2__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.
Files changed (14) hide show
  1. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/PKG-INFO +2 -2
  2. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips/__init__.py +73 -10
  3. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips.egg-info/PKG-INFO +2 -2
  4. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips.egg-info/requires.txt +1 -1
  5. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/LICENSE +0 -0
  6. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/README.rst +0 -0
  7. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips/girder_source.py +0 -0
  8. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips.egg-info/SOURCES.txt +0 -0
  9. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips.egg-info/dependency_links.txt +0 -0
  10. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips.egg-info/entry_points.txt +0 -0
  11. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/large_image_source_vips.egg-info/top_level.txt +0 -0
  12. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/pyproject.toml +0 -0
  13. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/setup.cfg +0 -0
  14. {large_image_source_vips-1.30.7.dev71 → large_image_source_vips-1.31.1.dev2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: large-image-source-vips
3
- Version: 1.30.7.dev71
3
+ Version: 1.31.1.dev2
4
4
  Summary: A libvips tilesource for large_image.
5
5
  Home-page: https://github.com/girder/large_image
6
6
  Author: Kitware, Inc.
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: >=3.8
20
20
  Description-Content-Type: text/x-rst
21
21
  License-File: LICENSE
22
- Requires-Dist: large-image>=1.30.7.dev71
22
+ Requires-Dist: large-image>=1.31.1.dev2
23
23
  Requires-Dist: numpy
24
24
  Requires-Dist: packaging
25
25
  Requires-Dist: pyvips
@@ -16,7 +16,7 @@ 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, _newFromFileLock
19
+ from large_image.tilesource.utilities import _imageToNumpy, _newFromFileLock, nearPowerOfTwo
20
20
 
21
21
  logging.getLogger('pyvips').setLevel(logging.ERROR)
22
22
 
@@ -98,6 +98,7 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
98
98
  if 'n-pages' in self._image.get_fields():
99
99
  pages = self._image.get('n-pages')
100
100
  self._frames = [0]
101
+ self._lowres = {}
101
102
  for page in range(1, pages):
102
103
  subInputPath = self._largeImagePath + f'[page={page}{self._suffix}]'
103
104
  with _newFromFileLock:
@@ -113,8 +114,13 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
113
114
  self._frames.append(page)
114
115
  continue
115
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
116
121
  continue
117
122
  self._frames = [page]
123
+ self._lowres = {}
118
124
  self.sizeX = subImage.width
119
125
  self.sizeY = subImage.height
120
126
  try:
@@ -122,12 +128,41 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
122
128
  except Exception:
123
129
  pass
124
130
  self._image = subImage
131
+ self._checkLowerLevels()
125
132
  self.levels = int(max(1, math.ceil(math.log(
126
133
  float(max(self.sizeX, self.sizeY)) / self.tileWidth) / math.log(2)) + 1))
127
- if len(self._frames) > 1:
134
+ if len(self._frames) > 1 or self._lowres is not None:
128
135
  self._recentFrames = cachetools.LRUCache(maxsize=6)
129
136
  self._frameLock = threading.RLock()
130
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
+
131
166
  def _initNew(self, **kwargs):
132
167
  """
133
168
  Initialize the tile class for creating a new image.
@@ -139,6 +174,7 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
139
174
  self.sizeX = self.sizeY = self.levels = 0
140
175
  self.tileWidth = self.tileHeight = self._tileSize
141
176
  self._frames = [0]
177
+ self._lowres = None
142
178
  self._cacheValue = str(uuid.uuid4())
143
179
  self._output = None
144
180
  self._editable = True
@@ -194,25 +230,38 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
194
230
  self._addMetadataFrameInformation(result)
195
231
  return result
196
232
 
197
- def _getFrameImage(self, frame=0):
233
+ def _getFrameImage(self, frame=0, lowres=None):
198
234
  """
199
235
  Get the vips image associated with a specific frame.
200
236
 
201
237
  :param frame: the 0-based frame to get.
238
+ :param lowres: the lower resolution part of the frame
202
239
  :returns: a vips image.
203
240
  """
204
241
  if self._image is None and self._output:
205
242
  self._outputToImage()
206
243
  img = self._image
207
- if frame > 0:
244
+ if frame > 0 or lowres:
208
245
  with self._frameLock:
209
- if frame not in self._recentFrames:
210
- subpath = self._largeImagePath + f'[page={self._frames[frame]}{self._suffix}]'
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
211
260
  with _newFromFileLock:
212
- img = pyvips.Image.new_from_file(subpath)
213
- self._recentFrames[frame] = img
261
+ img = pyvips.Image.new_from_file(subpath, **params)
262
+ self._recentFrames[key] = img
214
263
  else:
215
- img = self._recentFrames[frame]
264
+ img = self._recentFrames[key]
216
265
  return img
217
266
 
218
267
  def getNativeMagnification(self):
@@ -231,8 +280,22 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
231
280
  def getTile(self, x, y, z, pilImageAllowed=False, numpyAllowed=False, **kwargs):
232
281
  frame = self._getFrame(**kwargs)
233
282
  self._xyzInRange(x, y, z, frame, len(self._frames))
234
- img = self._getFrameImage(frame)
235
283
  x0, y0, x1, y1, step = self._xyzToCorners(x, y, z)
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)
236
299
  tileimg = img.crop(min(x0, img.width), min(y0, img.height),
237
300
  min(x1, img.width) - min(x0, img.width),
238
301
  min(y1, img.height) - min(y0, img.height))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: large-image-source-vips
3
- Version: 1.30.7.dev71
3
+ Version: 1.31.1.dev2
4
4
  Summary: A libvips tilesource for large_image.
5
5
  Home-page: https://github.com/girder/large_image
6
6
  Author: Kitware, Inc.
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: >=3.8
20
20
  Description-Content-Type: text/x-rst
21
21
  License-File: LICENSE
22
- Requires-Dist: large-image>=1.30.7.dev71
22
+ Requires-Dist: large-image>=1.31.1.dev2
23
23
  Requires-Dist: numpy
24
24
  Requires-Dist: packaging
25
25
  Requires-Dist: pyvips
@@ -1,4 +1,4 @@
1
- large-image>=1.30.7.dev71
1
+ large-image>=1.31.1.dev2
2
2
  numpy
3
3
  packaging
4
4
  pyvips