def getTile(self, x, y, z, pilImageAllowed=False, sparseFallback=False, **kwargs): if (z < 0 or z >= len(self._omeLevels) or self._omeLevels[z] is None or kwargs.get('frame') in (None, 0, '0', '')): return super(OMETiffFileTileSource, self).getTile( x, y, z, pilImageAllowed=pilImageAllowed, sparseFallback=sparseFallback, **kwargs) frame = int(kwargs['frame']) if frame < 0 or frame >= len(self._omebase['TiffData']): raise TileSourceException('Frame does not exist') dirnum = int(self._omeLevels[z]['TiffData'][frame]['IFD']) if dirnum in self._directoryCache: dir = self._directoryCache[dirnum] else: if len(self._directoryCache) >= self._directoryCacheMaxSize: self._directoryCache = {} dir = TiledTiffDirectory(self._getLargeImagePath(), dirnum) self._directoryCache[dirnum] = dir try: tile = dir.getTile(x, y) format = 'JPEG' if PIL and isinstance(tile, PIL.Image.Image): format = TILE_FORMAT_PIL return self._outputTile(tile, format, x, y, z, pilImageAllowed, **kwargs) except InvalidOperationTiffException as e: raise TileSourceException(e.args[0]) except IOTiffException as e: return self.getTileIOTiffException( x, y, z, pilImageAllowed=pilImageAllowed, sparseFallback=sparseFallback, exception=e, **kwargs)
def __init__(self, path, **kwargs): """ Initialize the tile class. See the base class for other available parameters. :param path: a filesystem path for the tile source. """ # Note this is the super of the parent class, not of this class. super(TiffFileTileSource, self).__init__(path, **kwargs) largeImagePath = self._getLargeImagePath() self._largeImagePath = largeImagePath try: base = TiledTiffDirectory(largeImagePath, 0, mustBeTiled=None) except TiffException: raise TileSourceException('Not a recognized OME Tiff') info = getattr(base, '_description_record', None) if not info or not info.get('OME'): raise TileSourceException('Not an OME Tiff') self._omeinfo = info['OME'] self._checkForOMEZLoop(largeImagePath) self._parseOMEInfo() omeimages = [ entry['Pixels'] for entry in self._omeinfo['Image'] if len(entry['Pixels']['TiffData']) == len(self._omebase['TiffData'])] levels = [max(0, int(math.ceil(math.log(max( float(entry['SizeX']) / base.tileWidth, float(entry['SizeY']) / base.tileHeight)) / math.log(2)))) for entry in omeimages] omebylevel = dict(zip(levels, omeimages)) self._omeLevels = [omebylevel.get(key) for key in range(max(omebylevel.keys()) + 1)] if base._tiffInfo.get('istiled'): self._tiffDirectories = [ TiledTiffDirectory(largeImagePath, int(entry['TiffData'][0].get('IFD', 0))) if entry else None for entry in self._omeLevels] else: self._tiffDirectories = [ TiledTiffDirectory(largeImagePath, 0, mustBeTiled=None) if entry else None for entry in self._omeLevels] self.tileWidth = base.tileWidth self.tileHeight = base.tileHeight self.levels = len(self._tiffDirectories) self.sizeX = base.imageWidth self.sizeY = base.imageHeight # We can get the embedded images, but we don't currently use non-tiled # images as associated images. This would require enumerating tiff # directories not mentioned by the ome list. self._associatedImages = {}
def _checkForOMEZLoop(self, largeImagePath): """ Check if the OME description lists a Z-loop that isn't referenced by the frames or TiffData list and is present based on the number of tiff directories. This can modify self._omeinfo. :param largeImagePath: used for checking for the maximum directory. """ info = self._omeinfo try: zloopinfo = info['Image']['Description'].split('Z Stack Loop: ')[1] zloop = int(zloopinfo.split()[0]) stepinfo = zloopinfo.split('Step: ')[1].split() stepmm = float(stepinfo[0]) stepmm *= {u'mm': 1, u'\xb5m': 0.001}[stepinfo[1]] planes = len(info['Image']['Pixels']['Plane']) for plane in info['Image']['Pixels']['Plane']: if int(plane.get('TheZ', 0)) != 0: return if int(info['Image']['Pixels']['SizeZ']) != 1: return except Exception: return if zloop <= 1 or not stepmm or not planes: return if len(info['Image']['Pixels'].get('TiffData', {})): return expecteddir = planes * zloop try: lastdir = TiledTiffDirectory(largeImagePath, expecteddir - 1, mustBeTiled=None) if not lastdir._tiffFile.lastdirectory(): return except Exception: return tiffdata = [] for z in range(zloop): for plane in info['Image']['Pixels']['Plane']: td = plane.copy() td['TheZ'] = str(z) # This position is probably wrong -- it seems like the # listed position is likely to be the center of the stack, not # the bottom, but we'd have to confirm it. td['PositionZ'] = str( float(td.get('PositionZ', 0)) + z * stepmm * 1000) tiffdata.append(td) info['Image']['Pixels']['TiffData'] = tiffdata info['Image']['Pixels']['Plane'] = tiffdata info['Image']['Pixels']['PlanesFromZloop'] = 'true' info['Image']['Pixels']['SizeZ'] = str(zloop)
def __init__(self, path, **kwargs): """ Initialize the tile class. See the base class for other available parameters. :param path: a filesystem path for the tile source. """ super(TiffFileTileSource, self).__init__(path, **kwargs) largeImagePath = self._getLargeImagePath() try: base = TiledTiffDirectory(largeImagePath, 0) except TiffException: raise TileSourceException('Not a tiled OME Tiff') info = getattr(base, '_description_xml', None) if not info.get('OME'): raise TileSourceException('Not an OME Tiff') self._omeinfo = info['OME'] if isinstance(self._omeinfo['Image'], dict): self._omeinfo['Image'] = [self._omeinfo['Image']] for img in self._omeinfo['Image']: if isinstance(img['Pixels'].get('TiffData'), dict): img['Pixels']['TiffData'] = [img['Pixels']['TiffData']] if isinstance(img['Pixels'].get('Plane'), dict): img['Pixels']['Plane'] = [img['Pixels']['Plane']] try: self._omebase = self._omeinfo['Image'][0]['Pixels'] if len({entry['UUID']['FileName'] for entry in self._omebase['TiffData']}) > 1: raise TileSourceException('OME Tiff references multiple files') if (len(self._omebase['TiffData']) != int(self._omebase['SizeC']) * int(self._omebase['SizeT']) * int(self._omebase['SizeZ']) or len(self._omebase['TiffData']) != len( self._omebase.get('Plane', self._omebase['TiffData']))): raise TileSourceException('OME Tiff contains frames that contain multiple planes') except (KeyError, ValueError, IndexError): raise TileSourceException('OME Tiff does not contain an expected record') omeimages = [ entry['Pixels'] for entry in self._omeinfo['Image'] if len(entry['Pixels']['TiffData']) == len(self._omebase['TiffData'])] levels = [max(0, int(math.ceil(math.log(max( float(entry['SizeX']) / base.tileWidth, float(entry['SizeY']) / base.tileHeight)) / math.log(2)))) for entry in omeimages] omebylevel = dict(zip(levels, omeimages)) self._omeLevels = [omebylevel.get(key) for key in range(max(omebylevel.keys()) + 1)] self._tiffDirectories = [ TiledTiffDirectory(largeImagePath, int(entry['TiffData'][0]['IFD'])) if entry else None for entry in self._omeLevels] self._directoryCache = {} self._directoryCacheMaxSize = max(20, len(self._omebase['TiffData']) * 3) self.tileWidth = base.tileWidth self.tileHeight = base.tileHeight self.levels = len(self._tiffDirectories) self.sizeX = base.imageWidth self.sizeY = base.imageHeight # We can get the embedded images, but we don't currently use non-tiled # images as associated images. This would require enumerating tiff # directories not mentioned by the ome list. self._associatedImages = {}