From 7a8ef967f1805bbbe332b8d1b28e7aecf766f6b4 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Wed, 24 Aug 2022 11:03:23 -0400 Subject: [PATCH] Better ignore tiff directories that aren't part of the pyramid. We had one test file with a "thumbnail" image that was tiled but at a different resolution than expected. This was mistakenly used as a level of the image. --- CHANGELOG.md | 1 + sources/tiff/large_image_source_tiff/__init__.py | 14 +++++++++++++- test/datastore.py | 5 ++++- test/test_source_base.py | 9 ++++----- test/test_source_tiff.py | 6 ++++++ 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cacc7e86..480d1eb4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Bug Fixes - Fix iterating tiles where the overlap larger than the tile size ([940](../../pull/940)) +- Better ignore tiff directories that aren't part of the pyramid ([943](../../pull/943)) ## 1.16.1 diff --git a/sources/tiff/large_image_source_tiff/__init__.py b/sources/tiff/large_image_source_tiff/__init__.py index fdee1febd..697df4a51 100644 --- a/sources/tiff/large_image_source_tiff/__init__.py +++ b/sources/tiff/large_image_source_tiff/__init__.py @@ -85,7 +85,7 @@ class TiffFileTileSource(FileTileSource, metaclass=LruCacheMetaclass): _maxAssociatedImageSize = 8192 - def __init__(self, path, **kwargs): + def __init__(self, path, **kwargs): # noqa """ Initialize the tile class. See the base class for other available parameters. @@ -141,6 +141,18 @@ def __init__(self, path, **kwargs): ((td.imageHeight % td.tileHeight) and not nearPowerOfTwo(td.imageHeight, highest.imageHeight))): continue + # If a layer is a multiple of the tile size, the number of tiles + # should be a power of two rounded up from the primary. + if (not (td.imageWidth % td.tileWidth) and not (td.imageHeight % td.tileHeight)): + htw = highest.imageWidth // td.tileWidth + hth = highest.imageHeight // td.tileHeight + ttw = td.imageWidth // td.tileWidth + tth = td.imageHeight // td.tileHeight + while (htw > ttw and htw > 1) or (hth > tth and hth > 1): + htw = (htw + 1) // 2 + hth = (hth + 1) // 2 + if htw != ttw or hth != tth: + continue directories[level] = td if not len(directories) or (len(directories) < 2 and max(directories.keys()) + 1 > 4): raise TileSourceError( diff --git a/test/datastore.py b/test/datastore.py index 8c88e6649..fe9f007ba 100644 --- a/test/datastore.py +++ b/test/datastore.py @@ -79,7 +79,10 @@ 'TC_NG_SFBay_US_Geo.tif': 'sha512:da2e66528f77a5e10af5de9e496074b77277c3da81dafc69790189510e5a7e18dba9e966329d36c979f1b547f0d36a82fbc4cfccc65ae9ef9e2747b5a9ee77b0', # noqa # Geospatial tiff - cloud optimized 'TC_NG_SFBay_US_Geo_COG.tif': 'sha512:5e56cdb8fb1a02615698a153862c10d5292b1ad42836a6e8bce5627e93a387dc0d3c9b6cfbd539796500bc2d3e23eafd07550f8c214e9348880bbbc6b3b0ea0c', # noqa - + # Tiff with extra overview that was originally misinterpreted as a layer + # Source: generated from a tifftools dump with the image descriptions and + # topmost layer removed. + 'extraoverview.tiff': 'sha512:22793cc6285ad11fbb47927c3d546d35e531a73852b79a9248ba489b421792e3a55da61e00079372bcf72a7e11b12e1ee69d553620edf46ff8d86ad2a9da9fc5', # noqa } diff --git a/test/test_source_base.py b/test/test_source_base.py index d3a2ef27b..7270ab8f6 100644 --- a/test/test_source_base.py +++ b/test/test_source_base.py @@ -43,11 +43,11 @@ 'openjpeg': {'read': r'\.(jp2)$'}, 'openslide': { 'read': r'\.(ptif|svs|tif.*)$', - 'noread': r'(oahu|DDX58_AXL|huron\.image2_jpeg2k|landcover_sample|d042-353\.crop|US_Geo\.)', + 'noread': r'(oahu|DDX58_AXL|huron\.image2_jpeg2k|landcover_sample|d042-353\.crop|US_Geo\.|extraoverview)', # noqa 'skipTiles': r'one_layer_missing'}, 'pil': { 'read': r'\.(jpeg|png|tif.*)$', - 'noread': r'(G10-3|JK-kidney|d042-353|huron|one_layer_missing|US_Geo)'}, + 'noread': r'(G10-3|JK-kidney|d042-353|huron|one_layer_missing|US_Geo|extraoverview)'}, 'test': {'any': True, 'skipTiles': r''}, 'tiff': { 'read': r'\.(ptif|scn|svs|tif.*)$', @@ -57,7 +57,7 @@ 'vips': { 'read': r'', 'noread': r'\.(nc|nd2|yml|yaml|json|czi|png|svs|scn)$', - 'skipTiles': r'(sample_image\.ptif|one_layer_missing_tiles|JK-kidney_B-gal_H3_4C_1-500sec\.jp2)'}, # noqa + 'skipTiles': r'(sample_image\.ptif|one_layer_missing_tiles|JK-kidney_B-gal_H3_4C_1-500sec\.jp2|extraoverview)'}, # noqa } if sys.version_info >= (3, 7): SourceAndFiles.update({ @@ -70,8 +70,7 @@ else: # Python 3.6 has an older version of PIL that won't read some of the # ome.tif files. - SourceAndFiles['pil']['noread'] = \ - r'(G10-3|JK-kidney|d042-353|huron|sample.*ome|one_layer_missing|US_Geo)' + SourceAndFiles['pil']['noread'] = SourceAndFiles['pil']['noread'][:-1] + '|sample.*ome)' def testNearPowerOfTwo(): diff --git a/test/test_source_tiff.py b/test/test_source_tiff.py index a01a8d926..da0f0b239 100644 --- a/test/test_source_tiff.py +++ b/test/test_source_tiff.py @@ -868,3 +868,9 @@ def testTileFrames(): info = tifftools.read_tiff(image) assert len(info['ifds']) == 3 os.unlink(image) + + +def testExtraOverview(): + imagePath = datastore.fetch('extraoverview.tiff') + source = large_image_source_tiff.open(imagePath) + assert len([d for d in source._tiffDirectories if d is not None]) == 3