diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index d571692b1..3c2e96356 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -205,14 +205,14 @@ def test_optimize_full_l(): def test_optimize_if_palette_can_be_reduced_by_half(): - with Image.open("Tests/images/test.colors.gif") as im: - # Reduce dimensions because original is too big for _get_optimize() - im = im.resize((591, 443)) - im_rgb = im.convert("RGB") + im = Image.new("P", (8, 1)) + im.palette = ImagePalette.raw("RGB", bytes((0, 0, 0) * 150)) + for i in range(8): + im.putpixel((i, 0), (i + 1, 0, 0)) for optimize, colors in ((False, 256), (True, 8)): out = BytesIO() - im_rgb.save(out, "GIF", optimize=optimize) + im.save(out, "GIF", optimize=optimize) with Image.open(out) as reloaded: assert len(reloaded.palette.palette) // 3 == colors @@ -1180,18 +1180,17 @@ def test_palette_save_L(tmp_path): def test_palette_save_P(tmp_path): - # Pass in a different palette, then construct what the image would look like. - # Forcing a non-straight grayscale palette. - - im = hopper("P") - palette = bytes(255 - i // 3 for i in range(768)) + im = Image.new("P", (1, 2)) + im.putpixel((0, 1), 1) out = str(tmp_path / "temp.gif") - im.save(out, palette=palette) + im.save(out, palette=bytes((1, 2, 3, 4, 5, 6))) with Image.open(out) as reloaded: - im.putpalette(palette) - assert_image_equal(reloaded, im) + reloaded_rgb = reloaded.convert("RGB") + + assert reloaded_rgb.getpixel((0, 0)) == (1, 2, 3) + assert reloaded_rgb.getpixel((0, 1)) == (4, 5, 6) def test_palette_save_duplicate_entries(tmp_path): diff --git a/Tests/test_image.py b/Tests/test_image.py index b9c57770c..83dac7080 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -638,8 +638,8 @@ class TestImage: im.remap_palette(None) def test_remap_palette_transparency(self): - im = Image.new("P", (1, 2)) - im.putpixel((0, 1), 1) + im = Image.new("P", (1, 2), (0, 0, 0)) + im.putpixel((0, 1), (255, 0, 0)) im.info["transparency"] = 0 im_remapped = im.remap_palette([1, 0]) diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 01a182cf1..f5775f09c 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -117,11 +117,11 @@ def test_trns_p(tmp_path): f = str(tmp_path / "temp.png") im_l = im.convert("L") - assert im_l.info["transparency"] == 1 # undone + assert im_l.info["transparency"] == 0 im_l.save(f) im_rgb = im.convert("RGB") - assert im_rgb.info["transparency"] == (0, 1, 2) # undone + assert im_rgb.info["transparency"] == (0, 0, 0) im_rgb.save(f) diff --git a/Tests/test_image_putpalette.py b/Tests/test_image_putpalette.py index 665e08a7e..376553344 100644 --- a/Tests/test_image_putpalette.py +++ b/Tests/test_image_putpalette.py @@ -84,3 +84,14 @@ def test_rgba_palette(mode, palette): im.putpalette(palette, mode) assert im.getpalette() == [1, 2, 3] assert im.palette.colors == {(1, 2, 3, 4): 0} + + +def test_empty_palette(): + im = Image.new("P", (1, 1)) + assert im.getpalette() == [] + + +def test_undefined_palette_index(): + im = Image.new("P", (1, 1), 3) + im.putpalette((1, 2, 3)) + assert im.convert("RGB").getpixel((0, 0)) == (0, 0, 0) diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index 31373a532..398696d5c 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -419,9 +419,11 @@ class BLPEncoder(ImageFile.PyEncoder): def _write_palette(self): data = b"" palette = self.im.getpalette("RGBA", "RGBA") - for i in range(256): + for i in range(len(palette) // 4): r, g, b, a = palette[i * 4 : (i + 1) * 4] data += struct.pack("<4B", b, g, r, a) + while len(data) < 256 * 4: + data += b"\x00" * 4 return data def encode(self, bufsize): diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 244d2e435..69c7c506b 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1074,7 +1074,7 @@ class Image: if mode == "P" and palette != Palette.ADAPTIVE: from . import ImagePalette - new_im.palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) + new_im.palette = ImagePalette.ImagePalette("RGB", im.getpalette("RGB")) if delete_trns: # crash fail if we leave a bytes transparency in an rgb/l mode. del new_im.info["transparency"] diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index 7fe24a639..7677a81f7 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -1295,7 +1295,6 @@ topalette( int alpha; int x, y; ImagingPalette palette = inpalette; - ; /* Map L or RGB/RGBX/RGBA to palette image */ if (strcmp(imIn->mode, "L") != 0 && strncmp(imIn->mode, "RGB", 3) != 0) { @@ -1307,7 +1306,14 @@ topalette( if (palette == NULL) { /* FIXME: make user configurable */ if (imIn->bands == 1) { - palette = ImagingPaletteNew("RGB"); /* Initialised to grey ramp */ + palette = ImagingPaletteNew("RGB"); + + palette->size = 256; + int i; + for (i = 0; i < 256; i++) { + palette->palette[i * 4] = palette->palette[i * 4 + 1] = + palette->palette[i * 4 + 2] = (UINT8)i; + } } else { palette = ImagingPaletteNewBrowser(); /* Standard colour cube */ } diff --git a/src/libImaging/Palette.c b/src/libImaging/Palette.c index 71a095c2c..059d7b72a 100644 --- a/src/libImaging/Palette.c +++ b/src/libImaging/Palette.c @@ -39,11 +39,8 @@ ImagingPaletteNew(const char *mode) { strncpy(palette->mode, mode, IMAGING_MODE_LENGTH - 1); palette->mode[IMAGING_MODE_LENGTH - 1] = 0; - /* Initialize to ramp */ - palette->size = 256; + palette->size = 0; for (i = 0; i < 256; i++) { - palette->palette[i * 4 + 0] = palette->palette[i * 4 + 1] = - palette->palette[i * 4 + 2] = (UINT8)i; palette->palette[i * 4 + 3] = 255; /* opaque */ } @@ -62,16 +59,10 @@ ImagingPaletteNewBrowser(void) { return NULL; } - /* Blank out unused entries */ /* FIXME: Add 10-level windows palette here? */ - for (i = 0; i < 10; i++) { - palette->palette[i * 4 + 0] = palette->palette[i * 4 + 1] = - palette->palette[i * 4 + 2] = 0; - } - /* Simple 6x6x6 colour cube */ - + i = 10; for (b = 0; b < 256; b += 51) { for (g = 0; g < 256; g += 51) { for (r = 0; r < 256; r += 51) { @@ -82,15 +73,10 @@ ImagingPaletteNewBrowser(void) { } } } + palette->size = i; - /* Blank out unused entries */ /* FIXME: add 30-level greyscale wedge here? */ - for (; i < 256; i++) { - palette->palette[i * 4 + 0] = palette->palette[i * 4 + 1] = - palette->palette[i * 4 + 2] = 0; - } - return palette; } diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c index 02a4a5c76..c84acb998 100644 --- a/src/libImaging/Quant.c +++ b/src/libImaging/Quant.c @@ -1825,6 +1825,7 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) { free(newData); + imOut->palette->size = (int)paletteLength; pp = imOut->palette->palette; for (i = j = 0; i < (int)paletteLength; i++) { @@ -1832,16 +1833,9 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) { *pp++ = palette[i].c.g; *pp++ = palette[i].c.b; if (withAlpha) { - *pp++ = palette[i].c.a; - } else { - *pp++ = 255; + *pp = palette[i].c.a; } - } - for (; i < 256; i++) { - *pp++ = 0; - *pp++ = 0; - *pp++ = 0; - *pp++ = 255; + pp++; } if (withAlpha) {