From 8210645e4b0b80578a3abd9d2e31811c36430ecc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 23 Jun 2021 19:28:46 +1000 Subject: [PATCH] If all 256 colors are in use, then there is no need for an additional color for background or transparency --- Tests/test_imagepalette.py | 3 +++ src/PIL/GifImagePlugin.py | 10 +++++++++- src/PIL/Image.py | 41 +++++++++++++++++++++++++------------- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py index 5152abf56..829b47641 100644 --- a/Tests/test_imagepalette.py +++ b/Tests/test_imagepalette.py @@ -31,8 +31,11 @@ def test_getcolor(): assert palette.getcolor((0, 0, 0)) == palette.getcolor((0, 0, 0, 255)) + # An error is raised when the palette is full with pytest.raises(ValueError): palette.getcolor((1, 2, 3)) + # But not if the image is not using one of the palette entries + palette.getcolor((1, 2, 3), image=Image.new("P", (1, 1))) # Test unknown color specifier with pytest.raises(ValueError): diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index e84bd6fe1..135c9c68f 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -760,7 +760,15 @@ def _get_background(im, infoBackground): # WebPImagePlugin stores an RGBA value in info["background"] # So it must be converted to the same format as GifImagePlugin's # info["background"] - a global color table index - background = im.palette.getcolor(background, im) + try: + background = im.palette.getcolor(background, im) + except ValueError as e: + if str(e) == "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for the background color + return 0 + else: + raise return background diff --git a/src/PIL/Image.py b/src/PIL/Image.py index fedfe9f0d..aebc34bc7 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -979,19 +979,27 @@ class Image: if isinstance(t, tuple): try: t = trns_im.palette.getcolor(t, self) - except Exception as e: - raise ValueError( - "Couldn't allocate a palette color for transparency" - ) from e - trns_im.putpixel((0, 0), t) - - if mode in ("L", "RGB"): - trns_im = trns_im.convert(mode) + except ValueError as e: + if str(e) == "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for transparency + t = None + else: + raise ValueError( + "Couldn't allocate a palette color for transparency" + ) from e + if t is None: + trns = None else: - # can't just retrieve the palette number, got to do it - # after quantization. - trns_im = trns_im.convert("RGB") - trns = trns_im.getpixel((0, 0)) + trns_im.putpixel((0, 0), t) + + if mode in ("L", "RGB"): + trns_im = trns_im.convert(mode) + else: + # can't just retrieve the palette number, got to do it + # after quantization. + trns_im = trns_im.convert("RGB") + trns = trns_im.getpixel((0, 0)) elif self.mode == "P" and mode == "RGBA": t = self.info["transparency"] @@ -1050,9 +1058,14 @@ class Image: if new_im.mode == "P": try: new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) - except Exception: + except ValueError as e: del new_im.info["transparency"] - warnings.warn("Couldn't allocate palette entry for transparency") + if str(e) != "cannot allocate more than 256 colors": + # If all 256 colors are in use, + # then there is no need for transparency + warnings.warn( + "Couldn't allocate palette entry for transparency" + ) else: new_im.info["transparency"] = trns return new_im