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

Set C palette to be empty by default #7289

Merged
merged 3 commits into from Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 12 additions & 13 deletions Tests/test_file_gif.py
Expand Up @@ -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

Expand Down Expand Up @@ -1172,18 +1172,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):
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_image.py
Expand Up @@ -632,8 +632,8 @@ def test_remap_palette(self):
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])
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_image_convert.py
Expand Up @@ -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)


Expand Down
11 changes: 11 additions & 0 deletions Tests/test_image_putpalette.py
Expand Up @@ -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)
4 changes: 3 additions & 1 deletion src/PIL/BlpImagePlugin.py
Expand Up @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/Image.py
Expand Up @@ -1069,7 +1069,7 @@ def convert_transparency(m, v):
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"]
Expand Down
10 changes: 8 additions & 2 deletions src/libImaging/Convert.c
Expand Up @@ -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) {
Expand All @@ -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 */
}
Expand Down
19 changes: 3 additions & 16 deletions src/libImaging/Palette.c
Expand Up @@ -40,10 +40,8 @@ ImagingPaletteNew(const char *mode) {
palette->mode[IMAGING_MODE_LENGTH - 1] = 0;

/* Initialize to ramp */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is now outdated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've pushed a commit to remove it.

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 */
}

Expand All @@ -62,16 +60,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) {
Expand All @@ -82,15 +74,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;
}

Expand Down
12 changes: 3 additions & 9 deletions src/libImaging/Quant.c
Expand Up @@ -1825,23 +1825,17 @@ 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++) {
*pp++ = palette[i].c.r;
*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) {
Expand Down