Skip to content

Commit

Permalink
Merge pull request #593 from girder/simplify-thumbnail-code
Browse files Browse the repository at this point in the history
Simplify thumbnail generation.
  • Loading branch information
manthey authored Apr 19, 2021
2 parents 5b9876e + 2a29792 commit b623535
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 46 deletions.
8 changes: 0 additions & 8 deletions girder/test_girder/test_tiles_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,14 +836,6 @@ def testGetTileSource(server, admin, fsAssetstore):
image, mime = source.getThumbnail(encoding='JPEG', width=200)
assert image[:len(utilities.JPEGHeader)] == utilities.JPEGHeader

# Test the level0 thumbnail code path
image, mime = source.getThumbnail(
encoding='PNG', width=200, height=100, levelZero=True, fill='blue')
assert image[:len(utilities.PNGHeader)] == utilities.PNGHeader
(width, height) = struct.unpack('!LL', image[16:24])
assert width == 200
assert height == 100


@pytest.mark.usefixtures('unbindLargeImage')
@pytest.mark.plugin('large_image')
Expand Down
40 changes: 7 additions & 33 deletions large_image/tilesource/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1694,17 +1694,16 @@ def getTileMimeType(self):
return TileOutputMimeTypes.get(self.encoding, 'image/jpeg')

@methodcache()
def getThumbnail(self, width=None, height=None, levelZero=False, **kwargs):
def getThumbnail(self, width=None, height=None, **kwargs):
"""
Get a basic thumbnail from the current tile source. Aspect ratio is
preserved. If neither width nor height is given, a default value is
used. If both are given, the thumbnail will be no larger than either
size.
size. A thumbnail has the same options as a region except that it
always includes the entire image and has a default size of 256 x 256.
:param width: maximum width in pixels.
:param height: maximum height in pixels.
:param levelZero: if true, always use the level zero tile. Otherwise,
the thumbnail is generated so that it is never upsampled.
:param kwargs: optional arguments. Some options are encoding,
jpegQuality, jpegSubsampling, and tiffCompression.
:returns: thumbData, thumbMime: the image data and the mime type.
Expand All @@ -1714,35 +1713,10 @@ def getThumbnail(self, width=None, height=None, levelZero=False, **kwargs):
raise ValueError('Invalid width or height. Minimum value is 2.')
if width is None and height is None:
width = height = 256
# There are two code paths for generating thumbnails. If
# alwaysUseLevelZero is True, then the the thumbnail is generated more
# swiftly, but may look poor. We may want to add a parameter for this
# option, or only use the high-quality results.
if not levelZero:
params = dict(kwargs)
params['output'] = {'maxWidth': width, 'maxHeight': height}
params.pop('region', None)
return self.getRegion(**params)
metadata = self.getMetadata()
tileData = self.getTile(0, 0, 0)
image = _imageToPIL(tileData)
imageWidth = int(math.floor(
metadata['sizeX'] * 2 ** -(metadata['levels'] - 1)))
imageHeight = int(math.floor(
metadata['sizeY'] * 2 ** -(metadata['levels'] - 1)))
image = image.crop((0, 0, imageWidth, imageHeight))

if width or height:
maxWidth, maxHeight = width, height
width, height, calcScale = self._calculateWidthHeight(
width, height, imageWidth, imageHeight)

image = image.resize(
(width, height),
PIL.Image.BICUBIC if width > imageWidth else PIL.Image.LANCZOS)
if kwargs.get('fill') and maxWidth and maxHeight:
image = _letterboxImage(image, maxWidth, maxHeight, kwargs['fill'])
return _encodeImage(image, **kwargs)
params = dict(kwargs)
params['output'] = {'maxWidth': width, 'maxHeight': height}
params.pop('region', None)
return self.getRegion(**params)

def getPreferredLevel(self, level):
"""
Expand Down
10 changes: 5 additions & 5 deletions sources/gdal/large_image_source_gdal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,17 +879,17 @@ def _getRegionBounds(self, metadata, left=None, top=None, right=None,
metadata, left, top, right, bottom, width, height, units, **kwargs)

@methodcache()
def getThumbnail(self, width=None, height=None, levelZero=False, **kwargs):
def getThumbnail(self, width=None, height=None, **kwargs):
"""
Get a basic thumbnail from the current tile source. Aspect ratio is
preserved. If neither width nor height is given, a default value is
used. If both are given, the thumbnail will be no larger than either
size.
size. A thumbnail has the same options as a region except that it
always includes the entire image if there is no projection and has a
default size of 256 x 256.
:param width: maximum width in pixels.
:param height: maximum height in pixels.
:param levelZero: if true, always use the level zero tile. Otherwise,
the thumbnail is generated so that it is never upsampled.
:param kwargs: optional arguments. Some options are encoding,
jpegQuality, jpegSubsampling, and tiffCompression.
:returns: thumbData, thumbMime: the image data and the mime type.
Expand All @@ -904,7 +904,7 @@ def getThumbnail(self, width=None, height=None, levelZero=False, **kwargs):
params['output'] = {'maxWidth': width, 'maxHeight': height}
params['region'] = {'units': 'projection'}
return self.getRegion(**params)
return super().getThumbnail(width, height, levelZero, **kwargs)
return super().getThumbnail(width, height, **kwargs)

def toNativePixelCoordinates(self, x, y, proj=None, roundResults=True):
"""
Expand Down

0 comments on commit b623535

Please sign in to comment.