From 9cdb0508b6cbd3a3061017760a5eab4d13c3924a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 14 Feb 2022 20:28:47 +1100 Subject: [PATCH] Attach RGBA palettes from putpalette() when suitable --- Tests/test_image_putpalette.py | 13 +++++++++++++ src/PIL/Image.py | 17 +++++++---------- src/_imaging.c | 7 ++++--- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Tests/test_image_putpalette.py b/Tests/test_image_putpalette.py index 012a57a09..725ecaade 100644 --- a/Tests/test_image_putpalette.py +++ b/Tests/test_image_putpalette.py @@ -62,3 +62,16 @@ def test_putpalette_with_alpha_values(): im.putpalette(palette_with_alpha_values, "RGBA") assert_image_equal(im.convert("RGBA"), expected) + + +@pytest.mark.parametrize( + "mode, palette", + ( + ("RGBA", (1, 2, 3, 4)), + ("RGBAX", (1, 2, 3, 4, 0)), + ), +) +def test_rgba_palette(mode, palette): + im = Image.new("P", (1, 1)) + im.putpalette(palette, mode) + assert im.palette.colors == {(1, 2, 3, 4): 0} diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 02b71e612..8d36e8871 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -821,12 +821,6 @@ class Image: if self.im and self.palette and self.palette.dirty: # realize palette mode, arr = self.palette.getdata() - if mode == "RGBA": - mode = "RGB" - self.info["transparency"] = arr[3::4] - arr = bytes( - value for (index, value) in enumerate(arr) if index % 4 != 3 - ) palette_length = self.im.putpalette(mode, arr) self.palette.dirty = 0 self.palette.rawmode = None @@ -837,8 +831,11 @@ class Image: self.im.putpalettealphas(self.info["transparency"]) self.palette.mode = "RGBA" else: - self.palette.mode = "RGB" - self.palette.palette = self.im.getpalette()[: palette_length * 3] + palette_mode = "RGBA" if mode.startswith("RGBA") else "RGB" + self.palette.mode = palette_mode + self.palette.palette = self.im.getpalette(palette_mode, palette_mode)[ + : palette_length * len(palette_mode) + ] if self.im: if cffi and USE_CFFI_ACCESS: @@ -1761,8 +1758,8 @@ class Image: Alternatively, an 8-bit string may be used instead of an integer sequence. :param data: A palette sequence (either a list or a string). - :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", or a - mode that can be transformed to "RGB" (e.g. "R", "BGR;15", "RGBA;L"). + :param rawmode: The raw mode of the palette. Either "RGB", "RGBA", or a mode + that can be transformed to "RGB" or "RGBA" (e.g. "R", "BGR;15", "RGBA;L"). """ from . import ImagePalette diff --git a/src/_imaging.c b/src/_imaging.c index 2a42c0461..2ea517816 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -1641,7 +1641,7 @@ _putpalette(ImagingObject *self, PyObject *args) { ImagingShuffler unpack; int bits; - char *rawmode; + char *rawmode, *palette_mode; UINT8 *palette; Py_ssize_t palettesize; if (!PyArg_ParseTuple(args, "sy#", &rawmode, &palette, &palettesize)) { @@ -1654,7 +1654,8 @@ _putpalette(ImagingObject *self, PyObject *args) { return NULL; } - unpack = ImagingFindUnpacker("RGB", rawmode, &bits); + palette_mode = strncmp("RGBA", rawmode, 4) == 0 ? "RGBA" : "RGB"; + unpack = ImagingFindUnpacker(palette_mode, rawmode, &bits); if (!unpack) { PyErr_SetString(PyExc_ValueError, wrong_raw_mode); return NULL; @@ -1669,7 +1670,7 @@ _putpalette(ImagingObject *self, PyObject *args) { strcpy(self->image->mode, strlen(self->image->mode) == 2 ? "PA" : "P"); - self->image->palette = ImagingPaletteNew("RGB"); + self->image->palette = ImagingPaletteNew(palette_mode); unpack(self->image->palette->palette, palette, palettesize * 8 / bits);