From 359596726cba83c7cf146a266acbc06364b2383e Mon Sep 17 00:00:00 2001 From: David Manthey Date: Fri, 8 Apr 2022 08:25:58 -0400 Subject: [PATCH] Make threadsafe. --- .../vips/large_image_source_vips/__init__.py | 14 +++--- test/test_source_vips.py | 44 ++++++++++++++----- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/sources/vips/large_image_source_vips/__init__.py b/sources/vips/large_image_source_vips/__init__.py index b08010d41..b38fb9e28 100644 --- a/sources/vips/large_image_source_vips/__init__.py +++ b/sources/vips/large_image_source_vips/__init__.py @@ -98,7 +98,7 @@ def _initNew(self, **kwargs): self._output = None self._editable = True self._bandRanges = None - self._addLock = threading.Lock() + self._addLock = threading.RLock() def getState(self): # Use the _cacheValue to avoid caching the source and tiles if we are @@ -247,7 +247,7 @@ def _addVipsImage(self, vimg, x=0, y=0): vimgTemp = pyvips.Image.new_temp_file('%s.v') vimg.write(vimgTemp) vimg = vimgTemp - with self._addLock(): + with self._addLock: if self._output is None: self._output = { 'images': [], @@ -297,10 +297,10 @@ def addTile(self, tile, x=0, y=0, mask=None, interpretation=None): if type(tile) != pyvips.vimage.Image: tile, mode = _imageToNumpy(tile) interpretation = interpretation or mode - with self._addLock(): + with self._addLock: self._updateBandRanges(tile) if interpretation == 'pixelmap': - with self._addLock(): + with self._addLock: self._interpretation = 'pixelmap' tile = numpy.dstack(( (tile % 256).astype(int), @@ -343,7 +343,7 @@ def _outputToImage(self): alpha channel is always included unless the intrepretation is multichannel. """ - with self._addLock(): + with self._addLock: bands = self._output['bands'] if bands in {1, 3}: bands += 1 @@ -396,7 +396,7 @@ def write(self, path, lossy=True, alpha=True, overwriteAllowed=True): """ if not overwriteAllowed and os.path.exists(path): raise TileSourceError('Output path exists (%s)' % str(path)) - with self._addLock(): + with self._addLock: img = self._getFrameImage(0) # TODO: set image description: e.g., # img.set_type( @@ -408,7 +408,7 @@ def write(self, path, lossy=True, alpha=True, overwriteAllowed=True): img = img[:-1] if not lossy: img.write_to_file( - path, tile_width=self.tileWidth, tile_height=self.tileHieght, + path, tile_width=self.tileWidth, tile_height=self.tileHeight, pyramid=True, bigtiff=True, region_shrink='nearest', compression='lzw', predictor='horizontal') else: diff --git a/test/test_source_vips.py b/test/test_source_vips.py index b47a9af8a..1c77b7349 100644 --- a/test/test_source_vips.py +++ b/test/test_source_vips.py @@ -3,7 +3,6 @@ import tempfile import large_image_source_vips -import pytest import large_image @@ -12,21 +11,20 @@ def testTilesFromVips(): - imagePath = datastore.fetch('sample_image.ptif') + imagePath = datastore.fetch('d042-353.crop.small.float32.tif') source = large_image_source_vips.open(imagePath) tileMetadata = source.getMetadata() assert tileMetadata['tileWidth'] == 256 assert tileMetadata['tileHeight'] == 256 - assert tileMetadata['sizeX'] == 58368 - assert tileMetadata['sizeY'] == 12288 - assert tileMetadata['levels'] == 9 - assert tileMetadata['magnification'] == pytest.approx(40, 1) + assert tileMetadata['sizeX'] == 480 + assert tileMetadata['sizeY'] == 320 + assert tileMetadata['levels'] == 2 utilities.checkTilesZXY(source, tileMetadata) def testInternalMetadata(): - imagePath = datastore.fetch('sample_image.ptif') + imagePath = datastore.fetch('d042-353.crop.small.float32.tif') source = large_image_source_vips.open(imagePath) metadata = source.getInternalMetadata() assert 'vips-loader' in metadata @@ -35,18 +33,42 @@ def testInternalMetadata(): def testNewAndWrite(): imagePath = datastore.fetch('sample_image.ptif') source = large_image.open(imagePath) - sourceMetadata = source.getMetadata() out = large_image_source_vips.new() - for tile in source.tileIterator(format=large_image.constants.TILE_FORMAT_NUMPY): + for tile in source.tileIterator( + format=large_image.constants.TILE_FORMAT_NUMPY, + region=dict(right=4000, bottom=2000), + ): out.addTile(tile['tile'], x=tile['x'], y=tile['y']) tmpdir = tempfile.mkdtemp() outputPath = os.path.join(tmpdir, 'temp.tiff') try: out.write(outputPath) - assert os.path.getsize(outputPath) > 500000 + assert os.path.getsize(outputPath) > 50000 + result = large_image.open(outputPath) + resultMetadata = result.getMetadata() + assert resultMetadata['sizeX'] == 4000 + finally: + shutil.rmtree(tmpdir) + + +def testNewAndWriteLossless(): + imagePath = datastore.fetch('sample_image.ptif') + source = large_image.open(imagePath) + out = large_image_source_vips.new() + for tile in source.tileIterator( + format=large_image.constants.TILE_FORMAT_NUMPY, + region=dict(right=4000, bottom=2000), + ): + out.addTile(tile['tile'], x=tile['x'], y=tile['y']) + + tmpdir = tempfile.mkdtemp() + outputPath = os.path.join(tmpdir, 'temp.tiff') + try: + out.write(outputPath, lossy=False) + assert os.path.getsize(outputPath) > 50000 result = large_image.open(outputPath) resultMetadata = result.getMetadata() - assert sourceMetadata['sizeX'] == resultMetadata['sizeX'] + assert resultMetadata['sizeX'] == 4000 finally: shutil.rmtree(tmpdir)