diff --git a/CHANGELOG.md b/CHANGELOG.md index e87f483c4..8f1ba9213 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,13 @@ # Change Log -## 1.18.1 +## 1.19.0 + +### Features +- Add a frames property to the tile source as a short hand for getting the number of frames from the metadata ([#1014](../../pull/1014)) ### Improvements - Better release file handles ([#1007](../../pull/1007)) -- Support tiny images from the test source ([#1011](../../pull/1011)) +- Support tiny images from the test source ([#1013](../../pull/1013)) ### Changes - Don't report filename in internal PIL metadata ([#1006](../../pull/1006)) diff --git a/large_image/tilesource/base.py b/large_image/tilesource/base.py index 290d06530..cad7837c0 100644 --- a/large_image/tilesource/base.py +++ b/large_image/tilesource/base.py @@ -2572,6 +2572,13 @@ def getPixel(self, includeTileRecord=False, **kwargs): pixel.update(dict(zip([img.mode.lower()], [img.load()[0, 0]]))) return pixel + @property + def frames(self): + """A property with the number of frames.""" + if not hasattr(self, '_frameCount'): + self._frameCount = len(self.getMetadata().get('frames', [])) or 1 + return self._frameCount + class FileTileSource(TileSource): diff --git a/sources/nd2/large_image_source_nd2/__init__.py b/sources/nd2/large_image_source_nd2/__init__.py index d798230ed..2574fa429 100644 --- a/sources/nd2/large_image_source_nd2/__init__.py +++ b/sources/nd2/large_image_source_nd2/__init__.py @@ -172,7 +172,7 @@ def __init__(self, path, **kwargs): self.levels = int(max(1, math.ceil(math.log( float(max(self.sizeX, self.sizeY)) / self.tileWidth) / math.log(2)) + 1)) try: - self._framecount = ( + self._frameCount = ( self._nd2.metadata.contents.channelCount * self._nd2.metadata.contents.frameCount) except Exception: self._nd2.close() @@ -224,7 +224,7 @@ def getMetadata(self): axes = self._nd2order[:self._nd2order.index('Y')][::-1] sizes = self._nd2.sizes result['frames'] = frames = [] - for idx in range(self._framecount): + for idx in range(self._frameCount): frame = {'Frame': idx} basis = 1 ref = {} @@ -265,10 +265,10 @@ def getInternalMetadata(self, **kwargs): @methodcache() def getTile(self, x, y, z, pilImageAllowed=False, numpyAllowed=False, **kwargs): frame = self._getFrame(**kwargs) - self._xyzInRange(x, y, z, frame, self._framecount) + self._xyzInRange(x, y, z, frame, self._frameCount) x0, y0, x1, y1, step = self._xyzToCorners(x, y, z) tileframe = self._nd2array - fc = self._framecount + fc = self._frameCount fp = frame for axis in self._nd2order[:self._nd2order.index('Y')]: fc //= self._nd2.sizes[axis] diff --git a/test/test_source_base.py b/test/test_source_base.py index 2e9f9dd05..22fad6c68 100644 --- a/test/test_source_base.py +++ b/test/test_source_base.py @@ -186,7 +186,9 @@ def testSourcesTilesAndMethods(source, filename): # assert len(ts.histogram()['histogram']) >= 1 # assert ts.histogram(onlyMinMax=True)['min'][0] is not None # Test multiple frames if they exist + assert ts.frames >= 1 if len(tileMetadata.get('frames', [])) > 1: + assert ts.frames == len(tileMetadata['frames']) tsf = sourceClass(imagePath, frame=len(tileMetadata['frames']) - 1) tileMetadata = tsf.getMetadata() utilities.checkTilesZXY(tsf, tileMetadata)