mirror of
https://mau.dev/maunium/synapse.git
synced 2024-11-10 12:02:43 +01:00
Handle image transparency better when thumbnailing. (#9473)
Properly uses RGBA mode for 1- and 8-bit images with transparency (instead of RBG mode).
This commit is contained in:
parent
3ce650057d
commit
075c16b410
3 changed files with 30 additions and 11 deletions
1
changelog.d/9473.bugfix
Normal file
1
changelog.d/9473.bugfix
Normal file
|
@ -0,0 +1 @@
|
|||
Fix long-standing bug when generating thumbnails for some images with transparency: `TypeError: cannot unpack non-iterable int object`.
|
|
@ -96,9 +96,14 @@ class Thumbnailer:
|
|||
def _resize(self, width: int, height: int) -> Image:
|
||||
# 1-bit or 8-bit color palette images need converting to RGB
|
||||
# otherwise they will be scaled using nearest neighbour which
|
||||
# looks awful
|
||||
if self.image.mode in ["1", "P"]:
|
||||
self.image = self.image.convert("RGB")
|
||||
# looks awful.
|
||||
#
|
||||
# If the image has transparency, use RGBA instead.
|
||||
if self.image.mode in ["1", "L", "P"]:
|
||||
mode = "RGB"
|
||||
if self.image.info.get("transparency", None) is not None:
|
||||
mode = "RGBA"
|
||||
self.image = self.image.convert(mode)
|
||||
return self.image.resize((width, height), Image.ANTIALIAS)
|
||||
|
||||
def scale(self, width: int, height: int, output_type: str) -> BytesIO:
|
||||
|
|
|
@ -105,7 +105,7 @@ class MediaStorageTests(unittest.HomeserverTestCase):
|
|||
self.assertEqual(test_body, body)
|
||||
|
||||
|
||||
@attr.s
|
||||
@attr.s(slots=True, frozen=True)
|
||||
class _TestImage:
|
||||
"""An image for testing thumbnailing with the expected results
|
||||
|
||||
|
@ -117,13 +117,15 @@ class _TestImage:
|
|||
test should just check for success.
|
||||
expected_scaled: The expected bytes from scaled thumbnailing, or None if
|
||||
test should just check for a valid image returned.
|
||||
expected_found: True if the file should exist on the server, or False if
|
||||
a 404 is expected.
|
||||
"""
|
||||
|
||||
data = attr.ib(type=bytes)
|
||||
content_type = attr.ib(type=bytes)
|
||||
extension = attr.ib(type=bytes)
|
||||
expected_cropped = attr.ib(type=Optional[bytes])
|
||||
expected_scaled = attr.ib(type=Optional[bytes])
|
||||
expected_cropped = attr.ib(type=Optional[bytes], default=None)
|
||||
expected_scaled = attr.ib(type=Optional[bytes], default=None)
|
||||
expected_found = attr.ib(default=True, type=bool)
|
||||
|
||||
|
||||
|
@ -153,6 +155,21 @@ class _TestImage:
|
|||
),
|
||||
),
|
||||
),
|
||||
# small png with transparency.
|
||||
(
|
||||
_TestImage(
|
||||
unhexlify(
|
||||
b"89504e470d0a1a0a0000000d49484452000000010000000101000"
|
||||
b"00000376ef9240000000274524e5300010194fdae0000000a4944"
|
||||
b"4154789c636800000082008177cd72b60000000049454e44ae426"
|
||||
b"082"
|
||||
),
|
||||
b"image/png",
|
||||
b".png",
|
||||
# Note that we don't check the output since it varies across
|
||||
# different versions of Pillow.
|
||||
),
|
||||
),
|
||||
# small lossless webp
|
||||
(
|
||||
_TestImage(
|
||||
|
@ -162,8 +179,6 @@ class _TestImage:
|
|||
),
|
||||
b"image/webp",
|
||||
b".webp",
|
||||
None,
|
||||
None,
|
||||
),
|
||||
),
|
||||
# an empty file
|
||||
|
@ -172,9 +187,7 @@ class _TestImage:
|
|||
b"",
|
||||
b"image/gif",
|
||||
b".gif",
|
||||
None,
|
||||
None,
|
||||
False,
|
||||
expected_found=False,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
Loading…
Reference in a new issue