large-image-source-tiff 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.
@@ -30,7 +30,9 @@ import tifftools
30
30
 
31
31
  from large_image.cache_util import LruCacheMetaclass, methodcache
32
32
  from large_image.constants import TILE_FORMAT_NUMPY, TILE_FORMAT_PIL, SourcePriority
33
- from large_image.exceptions import TileSourceError, TileSourceFileNotFoundError
33
+ from large_image.exceptions import (TileSourceError,
34
+ TileSourceFileNotFoundError,
35
+ TileSourceMalformedError)
34
36
  from large_image.tilesource import FileTileSource, nearPowerOfTwo
35
37
 
36
38
  from . import tiff_reader
@@ -63,6 +65,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
63
65
  'ptif': SourcePriority.PREFERRED,
64
66
  'ptiff': SourcePriority.PREFERRED,
65
67
  'qptiff': SourcePriority.PREFERRED,
68
+ 'svs': SourcePriority.MEDIUM,
66
69
  }
67
70
  mimeTypes = {
68
71
  None: SourcePriority.FALLBACK,
@@ -72,6 +75,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
72
75
  }
73
76
 
74
77
  _maxAssociatedImageSize = 8192
78
+ _maxUntiledImage = 4096
75
79
 
76
80
  def __init__(self, path, **kwargs): # noqa
77
81
  """
@@ -84,18 +88,20 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
84
88
 
85
89
  self._largeImagePath = str(self._getLargeImagePath())
86
90
 
91
+ lastException = None
87
92
  try:
88
93
  self._initWithTiffTools()
89
94
  return
95
+ except TileSourceMalformedError:
96
+ raise
90
97
  except Exception as exc:
91
98
  self.logger.debug('Cannot read with tifftools route; %r', exc)
99
+ lastException = exc
92
100
 
93
101
  alldir = []
94
102
  try:
95
103
  if hasattr(self, '_info'):
96
104
  alldir = self._scanDirectories()
97
- else:
98
- lastException = 'Could not parse file with tifftools'
99
105
  except IOOpenTiffError:
100
106
  msg = 'File cannot be opened via tiff source.'
101
107
  raise TileSourceError(msg)
@@ -135,7 +141,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
135
141
  continue
136
142
  # If a layer is a multiple of the tile size, the number of tiles
137
143
  # should be a power of two rounded up from the primary.
138
- if (not (td.imageWidth % td.tileWidth) and not (td.imageHeight % td.tileHeight)):
144
+ if not (td.imageWidth % td.tileWidth) and not (td.imageHeight % td.tileHeight):
139
145
  htw = highest.imageWidth // td.tileWidth
140
146
  hth = highest.imageHeight // td.tileHeight
141
147
  ttw = td.imageWidth // td.tileWidth
@@ -156,7 +162,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
156
162
  tifftools.constants.SampleFormat[sampleformat or 1].name,
157
163
  bitspersample,
158
164
  ))
159
- self._bandCount = highest._tiffInfo.get('samplesperpixel')
165
+ self._bandCount = highest._tiffInfo.get('samplesperpixel', 1)
160
166
  # Sort the directories so that the highest resolution is the last one;
161
167
  # if a level is missing, put a None value in its place.
162
168
  self._tiffDirectories = [directories.get(key) for key in
@@ -251,8 +257,13 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
251
257
  """
252
258
  sizeX = ifd['tags'][tifftools.Tag.ImageWidth.value]['data'][0]
253
259
  sizeY = ifd['tags'][tifftools.Tag.ImageLength.value]['data'][0]
254
- tileWidth = baseifd['tags'][tifftools.Tag.TileWidth.value]['data'][0]
255
- tileHeight = baseifd['tags'][tifftools.Tag.TileLength.value]['data'][0]
260
+ if tifftools.Tag.TileWidth.value in baseifd['tags']:
261
+ tileWidth = baseifd['tags'][tifftools.Tag.TileWidth.value]['data'][0]
262
+ tileHeight = baseifd['tags'][tifftools.Tag.TileLength.value]['data'][0]
263
+ else:
264
+ tileWidth = sizeX
265
+ tileHeight = baseifd['tags'][tifftools.Tag.RowsPerStrip.value]['data'][0]
266
+
256
267
  for tag in {
257
268
  tifftools.Tag.SamplesPerPixel.value,
258
269
  tifftools.Tag.BitsPerSample.value,
@@ -297,7 +308,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
297
308
  directories are the same size and format; all non-tiled directories are
298
309
  treated as associated images.
299
310
  """
300
- dir0 = self.getTiffDir(0)
311
+ dir0 = self.getTiffDir(0, mustBeTiled=None)
301
312
  self.tileWidth = dir0.tileWidth
302
313
  self.tileHeight = dir0.tileHeight
303
314
  self.sizeX = dir0.imageWidth
@@ -311,21 +322,26 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
311
322
  tifftools.constants.SampleFormat[sampleformat or 1].name,
312
323
  bitspersample,
313
324
  ))
314
- self._bandCount = dir0._tiffInfo.get('samplesperpixel')
325
+ self._bandCount = dir0._tiffInfo.get('samplesperpixel', 1)
315
326
  info = _cached_read_tiff(self._largeImagePath)
316
327
  self._info = info
317
328
  frames = []
318
329
  associated = [] # for now, a list of directories
319
- curframe = -1
330
+ used_subifd = False
320
331
  for idx, ifd in enumerate(info['ifds']):
321
332
  # if not tiles, add to associated images
322
333
  if tifftools.Tag.tileWidth.value not in ifd['tags']:
323
- associated.append(idx)
334
+ associated.append((idx, False))
324
335
  continue
325
- level = self._levelFromIfd(ifd, info['ifds'][0])
336
+ try:
337
+ level = self._levelFromIfd(ifd, info['ifds'][0])
338
+ except TileSourceError:
339
+ if idx and used_subifd:
340
+ associated.append((idx, True))
341
+ continue
342
+ raise
326
343
  # if the same resolution as the main image, add a frame
327
344
  if level == self.levels - 1:
328
- curframe += 1
329
345
  frames.append({'dirs': [None] * self.levels})
330
346
  frames[-1]['dirs'][-1] = (idx, 0)
331
347
  try:
@@ -358,15 +374,52 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
358
374
  if len(subifds) != 1:
359
375
  msg = 'When stored in subifds, each subifd should be a single ifd.'
360
376
  raise TileSourceError(msg)
361
- level = self._levelFromIfd(subifds[0], info['ifds'][0])
377
+ if (tifftools.Tag.StripOffsets.value not in subifds[0]['tags'] and
378
+ tifftools.Tag.TileOffsets.value not in subifds[0]['tags']):
379
+ msg = 'Subifd has no strip or tile offsets.'
380
+ raise TileSourceMalformedError(msg)
381
+ try:
382
+ level = self._levelFromIfd(subifds[0], info['ifds'][0])
383
+ except Exception:
384
+ break
362
385
  if level < self.levels - 1 and frames[-1]['dirs'][level] is None:
363
386
  frames[-1]['dirs'][level] = (idx, subidx + 1)
387
+ used_subifd = True
364
388
  else:
365
389
  msg = 'Tile layers are in a surprising order'
366
390
  raise TileSourceError(msg)
391
+ # If we have a single untiled ifd that is "small", use it
392
+ if tifftools.Tag.tileWidth.value not in info['ifds'][0]['tags']:
393
+ if (
394
+ self.sizeX > self._maxUntiledImage or self.sizeY > self._maxUntiledImage or
395
+ (len(info['ifds']) != 1 or tifftools.Tag.SubIfd.value in ifd['tags']) or
396
+ (tifftools.Tag.ImageDescription.value in ifd['tags'] and
397
+ 'ImageJ' in ifd['tags'][tifftools.Tag.ImageDescription.value]['data'])
398
+ ):
399
+ msg = 'A tiled TIFF is required.'
400
+ raise ValidationTiffError(msg)
401
+ associated = []
402
+ level = self._levelFromIfd(ifd, info['ifds'][0])
403
+ frames.append({'dirs': [None] * self.levels})
404
+ frames[-1]['dirs'][-1] = (idx, 0)
405
+ try:
406
+ frameMetadata = json.loads(
407
+ ifd['tags'][tifftools.Tag.ImageDescription.value]['data'])
408
+ for key in {'channels', 'frame'}:
409
+ if key in frameMetadata:
410
+ frames[-1][key] = frameMetadata[key]
411
+ except Exception:
412
+ pass
413
+ if tifftools.Tag.ICCProfile.value in ifd['tags']:
414
+ if not hasattr(self, '_iccprofiles'):
415
+ self._iccprofiles = []
416
+ while len(self._iccprofiles) < len(frames) - 1:
417
+ self._iccprofiles.append(None)
418
+ self._iccprofiles.append(ifd['tags'][
419
+ tifftools.Tag.ICCProfile.value]['data'])
367
420
  self._associatedImages = {}
368
- for dirNum in associated:
369
- self._addAssociatedImage(dirNum)
421
+ for dirNum, isTiled in associated:
422
+ self._addAssociatedImage(dirNum, isTiled)
370
423
  self._frames = frames
371
424
  self._tiffDirectories = [
372
425
  self.getTiffDir(
@@ -448,7 +501,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
448
501
  frame.setdefault('frame', {})
449
502
  frame['frame']['IndexC'] = idx
450
503
 
451
- def _addAssociatedImage(self, directoryNum, mustBeTiled=False, topImage=None):
504
+ def _addAssociatedImage(self, directoryNum, mustBeTiled=False, topImage=None, imageId=None):
452
505
  """
453
506
  Check if the specified TIFF directory contains an image with a sensible
454
507
  image description that can be used as an ID. If so, and if the image
@@ -459,6 +512,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
459
512
  untiled images.
460
513
  :param topImage: if specified, add image-embedded metadata to this
461
514
  image.
515
+ :param imageId: if specified, use this as the image name.
462
516
  """
463
517
  try:
464
518
  associated = self.getTiffDir(directoryNum, mustBeTiled)
@@ -472,6 +526,8 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
472
526
  id = 'dir%d' % directoryNum
473
527
  if not len(self._associatedImages):
474
528
  id = 'macro'
529
+ if imageId:
530
+ id = imageId
475
531
  if not id and not mustBeTiled:
476
532
  id = {1: 'label', 9: 'macro'}.get(associated._tiffInfo.get('subfiletype'))
477
533
  if not isinstance(id, str):
@@ -483,7 +539,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
483
539
  associated._pixelInfo['width'] <= self._maxAssociatedImageSize and
484
540
  associated._pixelInfo['height'] <= self._maxAssociatedImageSize and
485
541
  id not in self._associatedImages):
486
- image = associated._tiffFile.read_image()
542
+ image = associated.read_image()
487
543
  # Optrascan scanners store xml image descriptions in a "tiled
488
544
  # image". Check if this is the case, and, if so, parse such
489
545
  # data
@@ -630,20 +686,16 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
630
686
  else:
631
687
  dir = self._tiffDirectories[z]
632
688
  try:
633
- allowStyle = True
634
689
  if dir is None:
635
690
  try:
636
691
  if not kwargs.get('inSparseFallback'):
637
- tile = self._getTileFromEmptyLevel(x, y, z, **kwargs)
692
+ tile, format = self._getTileFromEmptyLevel(x, y, z, **kwargs)
638
693
  else:
639
694
  raise IOTiffError('Missing z level %d' % z)
640
695
  except Exception:
641
696
  if sparseFallback:
642
697
  raise IOTiffError('Missing z level %d' % z)
643
- else:
644
- raise
645
- allowStyle = False
646
- format = TILE_FORMAT_PIL
698
+ raise
647
699
  else:
648
700
  tile = dir.getTile(x, y, asarray=numpyAllowed == 'always')
649
701
  format = 'JPEG'
@@ -652,7 +704,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
652
704
  if isinstance(tile, np.ndarray):
653
705
  format = TILE_FORMAT_NUMPY
654
706
  return self._outputTile(tile, format, x, y, z, pilImageAllowed,
655
- numpyAllowed, applyStyle=allowStyle, **kwargs)
707
+ numpyAllowed, **kwargs)
656
708
  except InvalidOperationTiffError as e:
657
709
  raise TileSourceError(e.args[0])
658
710
  except IOTiffError as e:
@@ -701,7 +753,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
701
753
  else:
702
754
  image = PIL.Image.new('RGBA', (self.tileWidth, self.tileHeight))
703
755
  return self._outputTile(image, TILE_FORMAT_PIL, x, y, z, pilImageAllowed,
704
- numpyAllowed, applyStyle=False, **kwargs)
756
+ numpyAllowed, **kwargs)
705
757
  raise TileSourceError('Internal I/O failure: %s' % exception.args[0])
706
758
 
707
759
  def _nonemptyLevelsList(self, frame=0):
@@ -726,7 +778,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
726
778
  """
727
779
  imageList = set(self._associatedImages)
728
780
  for td in self._tiffDirectories:
729
- if td is not None:
781
+ if td is not None and td is not False:
730
782
  imageList |= set(td._embeddedImages)
731
783
  return sorted(imageList)
732
784
 
@@ -741,11 +793,11 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass):
741
793
  # _associatedImages. There are some sample files where libtiff's
742
794
  # read_image fails to read the _associatedImage properly because of
743
795
  # separated jpeg information. For the samples we currently have,
744
- # preferring the _embeddedImages is sufficient, but if find other files
745
- # with seemingly bad associated images, we may need to read them with a
746
- # more complex process than read_image.
796
+ # preferring the _embeddedImages is sufficient, but if we find other
797
+ # files with seemingly bad associated images, we may need to read them
798
+ # with a more complex process than read_image.
747
799
  for td in self._tiffDirectories:
748
- if td is not None and imageKey in td._embeddedImages:
800
+ if td is not None and td is not False and imageKey in td._embeddedImages:
749
801
  return PIL.Image.open(io.BytesIO(base64.b64decode(td._embeddedImages[imageKey])))
750
802
  if imageKey in self._associatedImages:
751
803
  return PIL.Image.fromarray(self._associatedImages[imageKey])
@@ -121,7 +121,12 @@ class TiledTiffDirectory:
121
121
  self._tileLock = threading.RLock()
122
122
 
123
123
  self._open(filePath, directoryNum, subDirectoryNum)
124
- self._loadMetadata()
124
+ try:
125
+ self._loadMetadata()
126
+ except Exception:
127
+ self.logger.exception('Could not parse tiff metadata')
128
+ raise IOOpenTiffError(
129
+ 'Could not open TIFF file: %s' % filePath)
125
130
  self.logger.debug(
126
131
  'TiffDirectory %d:%d Information %r',
127
132
  directoryNum, subDirectoryNum or 0, self._tiffInfo)
@@ -207,8 +212,8 @@ class TiledTiffDirectory:
207
212
  # the create_image.py script, such as flatten or colourspace. These
208
213
  # should only be done if necessary, which would require the conversion
209
214
  # job to check output and perform subsequent processing as needed.
210
- if (not self._tiffInfo.get('samplesperpixel') or
211
- self._tiffInfo.get('samplesperpixel') < 1):
215
+ if (not self._tiffInfo.get('samplesperpixel', 1) or
216
+ self._tiffInfo.get('samplesperpixel', 1) < 1):
212
217
  msg = 'Only RGB and greyscale TIFF files are supported'
213
218
  raise ValidationTiffError(msg)
214
219
 
@@ -442,12 +447,11 @@ class TiledTiffDirectory:
442
447
 
443
448
  if tileByteCountsLibtiffType == libtiff_ctypes.TIFFDataType.TIFF_LONG8:
444
449
  return ctypes.c_uint64
445
- elif tileByteCountsLibtiffType == \
450
+ if tileByteCountsLibtiffType == \
446
451
  libtiff_ctypes.TIFFDataType.TIFF_SHORT:
447
452
  return ctypes.c_uint16
448
- else:
449
- raise IOTiffError(
450
- 'Invalid type for TIFFTAG_TILEBYTECOUNTS: %s' % tileByteCountsLibtiffType)
453
+ raise IOTiffError(
454
+ 'Invalid type for TIFFTAG_TILEBYTECOUNTS: %s' % tileByteCountsLibtiffType)
451
455
 
452
456
  def _getJpegFrameSize(self, tileNum):
453
457
  """
@@ -524,10 +528,10 @@ class TiledTiffDirectory:
524
528
  if bytesRead == -1:
525
529
  msg = 'Failed to read raw tile'
526
530
  raise IOTiffError(msg)
527
- elif bytesRead < rawTileSize:
531
+ if bytesRead < rawTileSize:
528
532
  msg = 'Buffer underflow when reading tile'
529
533
  raise IOTiffError(msg)
530
- elif bytesRead > rawTileSize:
534
+ if bytesRead > rawTileSize:
531
535
  # It's unlikely that this will ever occur, but incomplete reads will
532
536
  # be checked for by looking for the JPEG end marker
533
537
  msg = 'Buffer overflow when reading tile'
@@ -607,7 +611,7 @@ class TiledTiffDirectory:
607
611
  self._tiffInfo.get('bitspersample'),
608
612
  self._tiffInfo.get('sampleformat') if self._tiffInfo.get(
609
613
  'sampleformat') is not None else libtiff_ctypes.SAMPLEFORMAT_UINT)
610
- image = np.empty((th, tw, self._tiffInfo['samplesperpixel']),
614
+ image = np.empty((th, tw, self._tiffInfo.get('samplesperpixel', 1)),
611
615
  dtype=_ctypesFormattbl[format])
612
616
  imageBuffer = image.ctypes.data_as(ctypes.POINTER(ctypes.c_char))
613
617
  if self._tiffInfo.get('istiled'):
@@ -635,7 +639,7 @@ class TiledTiffDirectory:
635
639
  raise IOTiffError(
636
640
  'Read an unexpected number of bytes from an encoded tile' if readSize >= 0 else
637
641
  'Failed to read from an encoded tile')
638
- if (self._tiffInfo.get('samplesperpixel') == 3 and
642
+ if (self._tiffInfo.get('samplesperpixel', 1) == 3 and
639
643
  self._tiffInfo.get('photometric') == libtiff_ctypes.PHOTOMETRIC_YCBCR):
640
644
  if self._tiffInfo.get('bitspersample') == 16:
641
645
  image = np.floor_divide(image, 256).astype(np.uint8)
@@ -783,11 +787,13 @@ class TiledTiffDirectory:
783
787
 
784
788
  if (not self._tiffInfo.get('istiled') or
785
789
  self._tiffInfo.get('compression') not in {
786
- libtiff_ctypes.COMPRESSION_JPEG, 33003, 33005, 34712} or
790
+ libtiff_ctypes.COMPRESSION_JPEG, 33003, 33004, 33005, 34712} or
787
791
  self._tiffInfo.get('bitspersample') != 8 or
788
792
  self._tiffInfo.get('sampleformat') not in {
789
793
  None, libtiff_ctypes.SAMPLEFORMAT_UINT} or
790
- (asarray and self._tiffInfo.get('compression') not in {33003, 33005, 34712} and (
794
+ (asarray and self._tiffInfo.get('compression') not in {
795
+ 33003, 33004, 33005, 34712,
796
+ } and (
791
797
  self._tiffInfo.get('compression') != libtiff_ctypes.COMPRESSION_JPEG or
792
798
  self._tiffInfo.get('photometric') != libtiff_ctypes.PHOTOMETRIC_YCBCR))):
793
799
  return self._getUncompressedTile(tileNum)
@@ -803,9 +809,18 @@ class TiledTiffDirectory:
803
809
  # Write JPEG End Of Image marker
804
810
  imageBuffer.write(b'\xff\xd9')
805
811
  return imageBuffer.getvalue()
806
- # Get the whole frame, which is in a JPEG or JPEG 2000 format, and
812
+ # Get the whole frame, which is in a JPEG or JPEG 2000 format
813
+ frame = self._getJpegFrame(tileNum, True)
814
+ # For JP2K, see if we can convert it faster than PIL
815
+ if self._tiffInfo.get('compression') in {33003, 33004, 33005, 34712}:
816
+ try:
817
+ import openjpeg
818
+
819
+ return openjpeg.decode(frame)
820
+ except Exception:
821
+ pass
807
822
  # convert it to a PIL image
808
- imageBuffer.write(self._getJpegFrame(tileNum, True))
823
+ imageBuffer.write(frame)
809
824
  image = PIL.Image.open(imageBuffer)
810
825
  # Converting the image mode ensures that it gets loaded once and is in
811
826
  # a form we expect. If this isn't done, then PIL can load the image
@@ -822,7 +837,7 @@ class TiledTiffDirectory:
822
837
  self._embeddedImages = {}
823
838
 
824
839
  if not meta:
825
- return
840
+ return None
826
841
  if not isinstance(meta, str):
827
842
  meta = meta.decode(errors='ignore')
828
843
  try:
@@ -844,7 +859,7 @@ class TiledTiffDirectory:
844
859
  meta.split('|MPP = ', 1)[1].split('|')[0].strip()) * 0.001
845
860
  except Exception:
846
861
  pass
847
- return
862
+ return None
848
863
  try:
849
864
  image = xml.find(
850
865
  ".//DataObject[@ObjectType='DPScannedImage']")
@@ -880,3 +895,26 @@ class TiledTiffDirectory:
880
895
  except Exception:
881
896
  pass
882
897
  return True
898
+
899
+ def read_image(self):
900
+ """
901
+ Use the underlying _tiffFile to read an image. But, if it is in a jp2k
902
+ encoding, read the raw data and convert it.
903
+ """
904
+ if self._tiffInfo.get('compression') not in {33003, 33004, 33005, 34712}:
905
+ return self._tiffFile.read_image()
906
+ output = None
907
+ for yidx, y in enumerate(range(0, self.imageHeight, self.tileHeight)):
908
+ for xidx, x in enumerate(range(0, self.imageWidth, self.tileWidth)):
909
+ tile = self.getTile(xidx, yidx, asarray=True)
910
+ if len(tile.shape) == 2:
911
+ tile = tile[:, :, np.newaxis]
912
+ if output is None:
913
+ output = np.zeros(
914
+ (self.imageHeight, self.imageWidth, tile.shape[2]), dtype=tile.dtype)
915
+ if tile.shape[0] > self.imageHeight - y:
916
+ tile = tile[:self.imageHeight - y, :, :]
917
+ if tile.shape[1] > self.imageWidth - x:
918
+ tile = tile[:, :self.imageWidth - x, :]
919
+ output[y:y + tile.shape[0], x:x + tile.shape[1], :] = tile
920
+ return output
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: large-image-source-tiff
3
- Version: 1.27.5.dev6
3
+ Version: 1.30.7.dev10
4
4
  Summary: A TIFF tilesource for large_image.
5
5
  Home-page: https://github.com/girder/large_image
6
6
  Author: Kitware, Inc.
@@ -15,13 +15,29 @@ 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.27.5.dev6
22
+ Requires-Dist: large-image>=1.30.7.dev10
21
23
  Requires-Dist: pylibtiff
22
- Requires-Dist: tifftools >=1.2.0
24
+ Requires-Dist: tifftools>=1.2.0
25
+ Provides-Extra: all
26
+ Requires-Dist: pylibjpeg-openjpeg; extra == "all"
23
27
  Provides-Extra: girder
24
- Requires-Dist: girder-large-image >=1.27.5.dev6 ; extra == 'girder'
28
+ Requires-Dist: girder-large-image>=1.30.7.dev10; extra == "girder"
29
+ Dynamic: author
30
+ Dynamic: author-email
31
+ Dynamic: classifier
32
+ Dynamic: description
33
+ Dynamic: description-content-type
34
+ Dynamic: home-page
35
+ Dynamic: keywords
36
+ Dynamic: license
37
+ Dynamic: provides-extra
38
+ Dynamic: requires-dist
39
+ Dynamic: requires-python
40
+ Dynamic: summary
25
41
 
26
42
  A TIFF tilesource for large_image.
27
43
 
@@ -0,0 +1,10 @@
1
+ large_image_source_tiff/__init__.py,sha256=o-NkH3SI7XLmEdejSREFMw39kfTMu2LiV3GGHsmNrPQ,36588
2
+ large_image_source_tiff/exceptions.py,sha256=NgdwloaDCtbtUMe2BU2lXEU8IwQSYtaokIwGIFypCps,617
3
+ large_image_source_tiff/girder_source.py,sha256=Dp2e3O4VTANYXZI_eybgzs5BcyuMcw2-MAzCUJ8zzPg,1031
4
+ large_image_source_tiff/tiff_reader.py,sha256=gkAhuB4-IRzNLlNr958HKE9JZpRJwVo4zRGMd4rsD2o,40338
5
+ large_image_source_tiff-1.30.7.dev10.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
6
+ large_image_source_tiff-1.30.7.dev10.dist-info/METADATA,sha256=O5AbEZVfjpc5zu9f10kzVnxMz86Jqq-E18IFCQ_lvkQ,1444
7
+ large_image_source_tiff-1.30.7.dev10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
8
+ large_image_source_tiff-1.30.7.dev10.dist-info/entry_points.txt,sha256=iZ43sIcj98SND7nDUC-_4qroBL6apyXN4iSbPXZ8LE4,166
9
+ large_image_source_tiff-1.30.7.dev10.dist-info/top_level.txt,sha256=QRx_D2oeiOOz_5FlBOAoDPF-E4Q-aFmerUWlaeP14B8,24
10
+ large_image_source_tiff-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,10 +0,0 @@
1
- large_image_source_tiff/__init__.py,sha256=0XCpYfa6BDT4m22xtLYO6qlxJ7vCFrWopWQQQo37FGQ,33986
2
- large_image_source_tiff/exceptions.py,sha256=NgdwloaDCtbtUMe2BU2lXEU8IwQSYtaokIwGIFypCps,617
3
- large_image_source_tiff/girder_source.py,sha256=Dp2e3O4VTANYXZI_eybgzs5BcyuMcw2-MAzCUJ8zzPg,1031
4
- large_image_source_tiff/tiff_reader.py,sha256=xZGz9P97LHfL5kmxVCL1ek0ry259LNp39yGls6tnpnM,38634
5
- large_image_source_tiff-1.27.5.dev6.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
6
- large_image_source_tiff-1.27.5.dev6.dist-info/METADATA,sha256=R2M0aEGAX6nMGr7yciHUYN2OJNqzK4r_-Uh_kylwrb4,1031
7
- large_image_source_tiff-1.27.5.dev6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
8
- large_image_source_tiff-1.27.5.dev6.dist-info/entry_points.txt,sha256=iZ43sIcj98SND7nDUC-_4qroBL6apyXN4iSbPXZ8LE4,166
9
- large_image_source_tiff-1.27.5.dev6.dist-info/top_level.txt,sha256=QRx_D2oeiOOz_5FlBOAoDPF-E4Q-aFmerUWlaeP14B8,24
10
- large_image_source_tiff-1.27.5.dev6.dist-info/RECORD,,