Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Harden which output formats are supported. #951

Merged
merged 2 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Better ignore tiff directories that aren't part of the pyramid ([943](../../pull/943))
- Fix an issue with styling frames in ome tiffs ([945](../../pull/945))
- Better handle large user records in annotation elements ([949](../../pull/949))
- Harden which output formats are supported ([950](../../pull/950))

### Changes
- Adjusted rest request logging rates for region endpoint ([948](../../pull/948))
Expand Down
18 changes: 17 additions & 1 deletion large_image/tilesource/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,19 @@ def _encodeImageBinary(image, encoding, jpegQuality, jpegSubsampling, tiffCompre
elif encoding == 'PNG':
params['compress_level'] = 2
output = io.BytesIO()
image.save(output, encoding, **params)
try:
image.save(output, encoding, **params)
except Exception:
retry = True
if image.mode not in {'RGB', 'L'}:
image = image.convert('RGB')
try:
image.convert('RGB').save(output, encoding, **params)
retry = False
except Exception:
pass
if retry:
image.convert('1').save(output, encoding, **params)
return ImageBytes(
output.getvalue(),
mimetype=f'image/{encoding.lower().replace("tiled", "tiff")}'
Expand Down Expand Up @@ -931,6 +943,10 @@ def addPILFormatsToOutputOptions():
# Call this to actual register the extensions
PIL.Image.registered_extensions()
for key, value in PIL.Image.MIME.items():
# We don't support these formats; ICNS and ICO have fixed sizes; PALM
# and PDF can't be read back by PIL without extensions
if key in {'ICNS', 'ICO', 'PALM', 'PDF'}:
continue
if key not in TileOutputMimeTypes and key in PIL.Image.SAVE:
TileOutputMimeTypes[key] = value
for key, value in PIL.Image.registered_extensions().items():
Expand Down
23 changes: 23 additions & 0 deletions test/test_source_base.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import io
import os
import re
import sys
from pathlib import Path

import PIL.Image
import pytest

import large_image
Expand Down Expand Up @@ -540,3 +542,24 @@ def testImageBytes():
assert 'ImageBytes' in repr(ib)
assert ib._repr_jpeg_() is None
assert ib._repr_png_() is None


@pytest.mark.parametrize('format', [
format for format in large_image.constants.TileOutputMimeTypes
if format not in {'TILED'}])
def testOutputFormats(format):
imagePath = datastore.fetch('sample_image.ptif')
testDir = os.path.dirname(os.path.realpath(__file__))
imagePathRGBA = os.path.join(testDir, 'test_files', 'rgba_geotiff.tiff')

ts = large_image.open(imagePath, encoding=format)
img = PIL.Image.open(io.BytesIO(ts.getTile(0, 0, 0)))
assert (img.width, img.height) == (256, 256)
img = PIL.Image.open(io.BytesIO(ts.getThumbnail(encoding=format)[0]))
assert (img.width, img.height) == (256, 53)

ts = large_image.open(imagePathRGBA, encoding=format)
img = PIL.Image.open(io.BytesIO(ts.getTile(0, 0, 0)))
assert (img.width, img.height) == (256, 256)
img = PIL.Image.open(io.BytesIO(ts.getThumbnail(encoding=format)[0]))
assert (img.width, img.height) == (256, 256)