Skip to content

Commit 302b63f

Browse files
authored
Merge pull request #8366 from radarhere/gif_rgba
2 parents 8d50840 + d522e0a commit 302b63f

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

Tests/test_file_gif.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,3 +1429,21 @@ def test_saving_rgba(tmp_path: Path) -> None:
14291429
with Image.open(out) as reloaded:
14301430
reloaded_rgba = reloaded.convert("RGBA")
14311431
assert reloaded_rgba.load()[0, 0][3] == 0
1432+
1433+
1434+
def test_optimizing_p_rgba(tmp_path: Path) -> None:
1435+
out = str(tmp_path / "temp.gif")
1436+
1437+
im1 = Image.new("P", (100, 100))
1438+
d = ImageDraw.Draw(im1)
1439+
d.ellipse([(40, 40), (60, 60)], fill=1)
1440+
data = [0, 0, 0, 0, 0, 0, 0, 255] + [0, 0, 0, 0] * 254
1441+
im1.putpalette(data, "RGBA")
1442+
1443+
im2 = Image.new("P", (100, 100))
1444+
im2.putpalette(data, "RGBA")
1445+
1446+
im1.save(out, save_all=True, append_images=[im2])
1447+
1448+
with Image.open(out) as reloaded:
1449+
assert reloaded.n_frames == 2

src/PIL/GifImagePlugin.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,9 @@ def _normalize_palette(
553553

554554
if im.mode == "P":
555555
if not source_palette:
556-
source_palette = im.im.getpalette("RGB")[:768]
556+
im_palette = im.getpalette(None)
557+
assert im_palette is not None
558+
source_palette = bytearray(im_palette)
557559
else: # L-mode
558560
if not source_palette:
559561
source_palette = bytearray(i // 3 for i in range(768))
@@ -629,7 +631,10 @@ def _write_single_frame(
629631
def _getbbox(
630632
base_im: Image.Image, im_frame: Image.Image
631633
) -> tuple[Image.Image, tuple[int, int, int, int] | None]:
632-
if _get_palette_bytes(im_frame) != _get_palette_bytes(base_im):
634+
palette_bytes = [
635+
bytes(im.palette.palette) if im.palette else b"" for im in (base_im, im_frame)
636+
]
637+
if palette_bytes[0] != palette_bytes[1]:
633638
im_frame = im_frame.convert("RGBA")
634639
base_im = base_im.convert("RGBA")
635640
delta = ImageChops.subtract_modulo(im_frame, base_im)
@@ -984,7 +989,13 @@ def _get_palette_bytes(im: Image.Image) -> bytes:
984989
:param im: Image object
985990
:returns: Bytes, len<=768 suitable for inclusion in gif header
986991
"""
987-
return bytes(im.palette.palette) if im.palette else b""
992+
if not im.palette:
993+
return b""
994+
995+
palette = bytes(im.palette.palette)
996+
if im.palette.mode == "RGBA":
997+
palette = b"".join(palette[i * 4 : i * 4 + 3] for i in range(len(palette) // 3))
998+
return palette
988999

9891000

9901001
def _get_background(

src/PIL/Image.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ def convert_transparency(
10671067
trns_im = new(self.mode, (1, 1))
10681068
if self.mode == "P":
10691069
assert self.palette is not None
1070-
trns_im.putpalette(self.palette)
1070+
trns_im.putpalette(self.palette, self.palette.mode)
10711071
if isinstance(t, tuple):
10721072
err = "Couldn't allocate a palette color for transparency"
10731073
assert trns_im.palette is not None
@@ -2179,6 +2179,9 @@ def remap_palette(
21792179
source_palette = self.im.getpalette(palette_mode, palette_mode)
21802180
else: # L-mode
21812181
source_palette = bytearray(i // 3 for i in range(768))
2182+
elif len(source_palette) > 768:
2183+
bands = 4
2184+
palette_mode = "RGBA"
21822185

21832186
palette_bytes = b""
21842187
new_positions = [0] * 256

0 commit comments

Comments
 (0)