large-image-source-tiff 1.27.5.dev6__py3-none-any.whl → 1.30.7.dev10__py3-none-any.whl

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.
@@ -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,,