diff --git a/server/tilesource/openjpeg.py b/server/tilesource/openjpeg.py index 1124c203b..1ca0b37a7 100644 --- a/server/tilesource/openjpeg.py +++ b/server/tilesource/openjpeg.py @@ -75,6 +75,9 @@ class OpenjpegFileTileSource(FileTileSource): } _xmlTag = b'mxl ' + _minTileSize = 256 + _maxTileSize = 512 + def __init__(self, path, **kwargs): """ Initialize the tile class. See the base class for other available @@ -99,10 +102,24 @@ def __init__(self, path, **kwargs): except IndexError: raise TileSourceException('File cannot be opened via Glymur and OpenJPEG.') self.levels = self._openjpeg.codestream.segment[2].num_res + 1 + self._minlevel = 0 self.tileWidth = self.tileHeight = 2 ** int(math.ceil(max( math.log(float(self.sizeX)) / math.log(2) - self.levels + 1, math.log(float(self.sizeY)) / math.log(2) - self.levels + 1))) - # read associated images and metadata from boxes + # Small and large tiles are both inefficient. Large tiles don't work + # with some viewers (leaflet and Slide Atlas, for instance) + if self.tileWidth < self._minTileSize or self.tileWidth > self._maxTileSize: + self.tileWidth = self.tileHeight = min( + self._maxTileSize, max(self._minTileSize, self.tileWidth)) + self.levels = math.ceil(math.log(float(max( + self.sizeX, self.sizeY)) / self.tileWidth) / math.log(2)) + 1 + self._minlevel = self.levels - self._openjpeg.codestream.segment[2].num_res - 1 + self._getAssociatedImages() + + def _getAssociatedImages(self): + """ + Read associated images and metadata from boxes. + """ self._associatedImages = {} for box in self._openjpeg.box: if box.box_id == self._xmlTag or box.box_id in self._boxToTag: @@ -203,6 +220,10 @@ def getTile(self, x, y, z, pilImageAllowed=False, **kwargs): raise TileSourceException('x is outside layer') if y < 0 or y0 >= self.sizeY: raise TileSourceException('y is outside layer') + scale = None + if z < self._minlevel: + scale = 2 ** (self._minlevel - z) + step = 2 ** (self.levels - 1 - self._minlevel) # possible open the file multiple times so multiple threads can access # it concurrently. with self._openjpegLock: @@ -218,6 +239,8 @@ def getTile(self, x, y, z, pilImageAllowed=False, **kwargs): if len(tile.shape) == 3: mode = ['L', 'LA', 'RGB', 'RGBA'][tile.shape[2] - 1] tile = PIL.Image.frombytes(mode, (tile.shape[1], tile.shape[0]), tile) + if scale: + tile = tile.resize((tile.size[0] // scale, tile.size[1] // scale), PIL.Image.LANCZOS) if tile.size != (self.tileWidth, self.tileHeight): wrap = PIL.Image.new(mode, (self.tileWidth, self.tileHeight)) wrap.paste(tile, (0, 0)) diff --git a/web_client/views/imageViewerWidget/leaflet.js b/web_client/views/imageViewerWidget/leaflet.js index 1858098bd..b416b8562 100644 --- a/web_client/views/imageViewerWidget/leaflet.js +++ b/web_client/views/imageViewerWidget/leaflet.js @@ -23,6 +23,7 @@ var LeafletImageViewerWidget = ImageViewerWidget.extend({ }, render: function () { + var errmsg; // If script or metadata isn't loaded, then abort if (!window.L || !this.tileWidth || !this.tileHeight || this.deleted) { return this; @@ -34,7 +35,15 @@ var LeafletImageViewerWidget = ImageViewerWidget.extend({ } if (this.tileWidth !== this.tileHeight) { - console.error('The Leaflet viewer only supports square tiles.'); + errmsg = 'The Leaflet viewer only supports square tiles.'; + } + if (this.tileWidth > 256) { + errmsg = 'The Leaflet viewer does not support tiles wider than 256 pixels.'; + } + if (errmsg) { + this.viewer = $('
').text(errmsg); + this.$el.append(this.viewer); + console.error(errmsg); return this; } diff --git a/web_client/views/imageViewerWidget/slideatlas.js b/web_client/views/imageViewerWidget/slideatlas.js index a108cb8d3..501b6964b 100644 --- a/web_client/views/imageViewerWidget/slideatlas.js +++ b/web_client/views/imageViewerWidget/slideatlas.js @@ -25,6 +25,7 @@ var SlideAtlasImageViewerWidget = ImageViewerWidget.extend({ }, render: function () { + var errmsg; // If script or metadata isn't loaded, then abort if (!window.SA || !this.tileWidth || !this.tileHeight || this.deleted) { return this; @@ -36,7 +37,15 @@ var SlideAtlasImageViewerWidget = ImageViewerWidget.extend({ } if (this.tileWidth !== this.tileHeight) { - console.error('The SlideAtlas viewer only supports square tiles.'); + errmsg = 'The SlideAtlas viewer only supports square tiles.'; + } + if (this.tileWidth > 256) { + errmsg = 'The SlideAtlas viewer does not support tiles wider than 256 pixels.'; + } + if (errmsg) { + this.viewer = $('
').text(errmsg); + this.$el.append(this.viewer); + console.error(errmsg); return this; }