From c0951cfd4610d773868f9d1f7130fb2924e05d32 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Thu, 9 Jan 2025 17:14:54 -0500 Subject: [PATCH] Be slightly more flexible in reading multi-frames from vips --- CHANGELOG.md | 1 + girder/test_girder/test_web_client.py | 1 + .../vips/large_image_source_vips/__init__.py | 20 +++++++++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60692f886..30c47468f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Improvements - Better report if rasterized vector files are geospatial ([#1769](../../pull/1769)) +- Provide some latitude in vips multiframe detection ([#1770](../../pull/1770)) ## 1.30.6 diff --git a/girder/test_girder/test_web_client.py b/girder/test_girder/test_web_client.py index b13645272..4ba589d12 100644 --- a/girder/test_girder/test_web_client.py +++ b/girder/test_girder/test_web_client.py @@ -22,6 +22,7 @@ def testWebClient(boundServer, fsAssetstore, db, spec, girderWorker): runWebClientTest(boundServer, spec, 15000) +@pytest.mark.singular @pytest.mark.usefixtures('unbindLargeImage') @pytest.mark.plugin('large_image') @pytest.mark.parametrize('spec', [ diff --git a/sources/vips/large_image_source_vips/__init__.py b/sources/vips/large_image_source_vips/__init__.py index 9f3a49e09..e7d491706 100644 --- a/sources/vips/large_image_source_vips/__init__.py +++ b/sources/vips/large_image_source_vips/__init__.py @@ -60,7 +60,7 @@ class VipsFileTileSource(FileTileSource, metaclass=LruCacheMetaclass): _tileSize = 256 - def __init__(self, path, **kwargs): + def __init__(self, path, **kwargs): # noqa """ Initialize the tile class. See the base class for other available parameters. @@ -70,6 +70,7 @@ def __init__(self, path, **kwargs): super().__init__(path, **kwargs) self.addKnownExtensions() + self._suffix = '' if str(path).startswith(NEW_IMAGE_PATH_FLAG): self._initNew(**kwargs) return @@ -85,6 +86,11 @@ def __init__(self, path, **kwargs): raise TileSourceFileNotFoundError(self._largeImagePath) from None msg = 'File cannot be opened via pyvips' raise TileSourceError(msg) + # Ask pdfs to render at a higher resolution + if ('vips-loader' in self._image.get_fields() and + self._image.get('vips-loader') in {'pdfload'}): + self._suffix = ',dpi=144' + self._image = pyvips.Image.new_from_file(self._largeImagePath + '[dpi=300]') self.sizeX = self._image.width self.sizeY = self._image.height self.tileWidth = self.tileHeight = self._tileSize @@ -93,7 +99,7 @@ def __init__(self, path, **kwargs): pages = self._image.get('n-pages') self._frames = [0] for page in range(1, pages): - subInputPath = self._largeImagePath + '[page=%d]' % page + subInputPath = self._largeImagePath + f'[page={page}{self._suffix}]' with _newFromFileLock: try: subImage = pyvips.Image.new_from_file(subInputPath) @@ -102,6 +108,10 @@ def __init__(self, path, **kwargs): if subImage.width == self.sizeX and subImage.height == self.sizeY: self._frames.append(page) continue + if (self.sizeX - 16 < subImage.width <= self.sizeX and + self.sizeY - 16 < subImage.height <= self.sizeY): + self._frames.append(page) + continue if subImage.width * subImage.height < self.sizeX * self.sizeY: continue self._frames = [page] @@ -197,7 +207,7 @@ def _getFrameImage(self, frame=0): if frame > 0: with self._frameLock: if frame not in self._recentFrames: - subpath = self._largeImagePath + '[page=%d]' % self._frames[frame] + subpath = self._largeImagePath + f'[page={self._frames[frame]}{self._suffix}]' with _newFromFileLock: img = pyvips.Image.new_from_file(subpath) self._recentFrames[frame] = img @@ -223,7 +233,9 @@ def getTile(self, x, y, z, pilImageAllowed=False, numpyAllowed=False, **kwargs): self._xyzInRange(x, y, z, frame, len(self._frames)) img = self._getFrameImage(frame) x0, y0, x1, y1, step = self._xyzToCorners(x, y, z) - tileimg = img.crop(x0, y0, x1 - x0, y1 - y0) + tileimg = img.crop(min(x0, img.width), min(y0, img.height), + min(x1, img.width) - min(x0, img.width), + min(y1, img.height) - min(y0, img.height)) try: if step != 1: tileimg = tileimg.resize(1.0 / step, kernel=pyvips.enums.Kernel.NEAREST, gap=0)