Skip to content

Commit

Permalink
Improve warnings on inefficient tiff files.
Browse files Browse the repository at this point in the history
Also, for striped images, use less memory when compositing stripes for
lower resolutions.
  • Loading branch information
manthey committed Oct 20, 2021
1 parent 3be65e6 commit 0a77d24
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 6 deletions.
11 changes: 11 additions & 0 deletions sources/ometiff/large_image_source_ometiff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ class OMETiffFileTileSource(TiffFileTileSource, metaclass=LruCacheMetaclass):
'ome': SourcePriority.PREFERRED,
}

# The expect number of pixels that would need to be read to read the worst-
# case tile.
_maxUntiledChunk = 512 * 1024 * 1024

def __init__(self, path, **kwargs):
"""
Initialize the tile class. See the base class for other available
Expand Down Expand Up @@ -123,6 +127,12 @@ def __init__(self, path, **kwargs):
TiledTiffDirectory(largeImagePath, 0, mustBeTiled=None)
if entry else None
for entry in self._omeLevels]
self._checkForInefficientDirectories(warn=False)
_maxChunk = min(base.imageWidth, base.tileWidth * self._skippedLevels ** 2) * \
min(base.imageHeight, base.tileHeight * self._skippedLevels ** 2)
if _maxChunk > self._maxUntiledChunk:
raise TileSourceError(
'Untiled image is too large to access with the OME Tiff source')
self.tileWidth = base.tileWidth
self.tileHeight = base.tileHeight
self.levels = len(self._tiffDirectories)
Expand All @@ -133,6 +143,7 @@ def __init__(self, path, **kwargs):
# images as associated images. This would require enumerating tiff
# directories not mentioned by the ome list.
self._associatedImages = {}
self._checkForInefficientDirectories()

def _checkForOMEZLoop(self, largeImagePath):
"""
Expand Down
22 changes: 16 additions & 6 deletions sources/tiff/large_image_source_tiff/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def __init__(self, path, **kwargs):
self.levels = len(self._tiffDirectories)
self.sizeX = highest.imageWidth
self.sizeY = highest.imageHeight
self._checkForInefficientDirectories()

def _scanDirectories(self):
largeImagePath = self._largeImagePath
Expand Down Expand Up @@ -314,16 +315,25 @@ def _initWithTiffTools(self): # noqa
if frames[0]['dirs'][idx] is not None else None
for idx in range(self.levels - 1)]
self._tiffDirectories.append(dir0)
self._checkForInefficientDirectories()
return True

def _checkForInefficientDirectories(self, warn=True):
"""
Raise a warning for inefficient files.
:param warn: if True and inefficient, emit a warning.
"""
missing = [v is None for v in self._tiffDirectories]
maxMissing = max(0 if not v else missing.index(False, idx) - idx
for idx, v in enumerate(missing))
self._skippedLevels = maxMissing
if maxMissing >= self._maxSkippedLevels:
config.getConfig('logger').warning(
'Tiff image is missing many lower resolution levels (%d). '
'It will be inefficient to read lower resolution tiles.', maxMissing)
if warn:
config.getConfig('logger').warning(
'Tiff image is missing many lower resolution levels (%d). '
'It will be inefficient to read lower resolution tiles.', maxMissing)
self._inefficientWarning = True
return True

def _reorient_numpy_image(self, image, orientation):
"""
Expand Down Expand Up @@ -631,8 +641,8 @@ def getTileFromEmptyDirectory(self, x, y, z, **kwargs):
while z - basez > self._maxSkippedLevels:
z -= self._maxSkippedLevels
scale = int(scale / 2 ** self._maxSkippedLevels)
tile = PIL.Image.new(
'RGBA', (self.tileWidth * scale, self.tileHeight * scale))
tile = PIL.Image.new('RGBA', (
min(self.sizeX, self.tileWidth * scale), min(self.sizeY, self.tileHeight * scale)))
maxX = 2.0 ** (z + 1 - self.levels) * self.sizeX / self.tileWidth
maxY = 2.0 ** (z + 1 - self.levels) * self.sizeY / self.tileHeight
for newX in range(scale):
Expand Down

0 comments on commit 0a77d24

Please sign in to comment.