mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Improved handling of RGBA palettes when saving GIF images
This commit is contained in:
parent
22c333289e
commit
d522e0a5c0
|
@ -1429,3 +1429,21 @@ def test_saving_rgba(tmp_path: Path) -> None:
|
|||
with Image.open(out) as reloaded:
|
||||
reloaded_rgba = reloaded.convert("RGBA")
|
||||
assert reloaded_rgba.load()[0, 0][3] == 0
|
||||
|
||||
|
||||
def test_optimizing_p_rgba(tmp_path: Path) -> None:
|
||||
out = str(tmp_path / "temp.gif")
|
||||
|
||||
im1 = Image.new("P", (100, 100))
|
||||
d = ImageDraw.Draw(im1)
|
||||
d.ellipse([(40, 40), (60, 60)], fill=1)
|
||||
data = [0, 0, 0, 0, 0, 0, 0, 255] + [0, 0, 0, 0] * 254
|
||||
im1.putpalette(data, "RGBA")
|
||||
|
||||
im2 = Image.new("P", (100, 100))
|
||||
im2.putpalette(data, "RGBA")
|
||||
|
||||
im1.save(out, save_all=True, append_images=[im2])
|
||||
|
||||
with Image.open(out) as reloaded:
|
||||
assert reloaded.n_frames == 2
|
||||
|
|
|
@ -553,7 +553,9 @@ def _normalize_palette(
|
|||
|
||||
if im.mode == "P":
|
||||
if not source_palette:
|
||||
source_palette = im.im.getpalette("RGB")[:768]
|
||||
im_palette = im.getpalette(None)
|
||||
assert im_palette is not None
|
||||
source_palette = bytearray(im_palette)
|
||||
else: # L-mode
|
||||
if not source_palette:
|
||||
source_palette = bytearray(i // 3 for i in range(768))
|
||||
|
@ -629,7 +631,10 @@ def _write_single_frame(
|
|||
def _getbbox(
|
||||
base_im: Image.Image, im_frame: Image.Image
|
||||
) -> tuple[Image.Image, tuple[int, int, int, int] | None]:
|
||||
if _get_palette_bytes(im_frame) != _get_palette_bytes(base_im):
|
||||
palette_bytes = [
|
||||
bytes(im.palette.palette) if im.palette else b"" for im in (base_im, im_frame)
|
||||
]
|
||||
if palette_bytes[0] != palette_bytes[1]:
|
||||
im_frame = im_frame.convert("RGBA")
|
||||
base_im = base_im.convert("RGBA")
|
||||
delta = ImageChops.subtract_modulo(im_frame, base_im)
|
||||
|
@ -984,7 +989,13 @@ def _get_palette_bytes(im: Image.Image) -> bytes:
|
|||
:param im: Image object
|
||||
:returns: Bytes, len<=768 suitable for inclusion in gif header
|
||||
"""
|
||||
return bytes(im.palette.palette) if im.palette else b""
|
||||
if not im.palette:
|
||||
return b""
|
||||
|
||||
palette = bytes(im.palette.palette)
|
||||
if im.palette.mode == "RGBA":
|
||||
palette = b"".join(palette[i * 4 : i * 4 + 3] for i in range(len(palette) // 3))
|
||||
return palette
|
||||
|
||||
|
||||
def _get_background(
|
||||
|
|
|
@ -1066,7 +1066,7 @@ class Image:
|
|||
trns_im = new(self.mode, (1, 1))
|
||||
if self.mode == "P":
|
||||
assert self.palette is not None
|
||||
trns_im.putpalette(self.palette)
|
||||
trns_im.putpalette(self.palette, self.palette.mode)
|
||||
if isinstance(t, tuple):
|
||||
err = "Couldn't allocate a palette color for transparency"
|
||||
assert trns_im.palette is not None
|
||||
|
@ -2182,6 +2182,9 @@ class Image:
|
|||
source_palette = self.im.getpalette(palette_mode, palette_mode)
|
||||
else: # L-mode
|
||||
source_palette = bytearray(i // 3 for i in range(768))
|
||||
elif len(source_palette) > 768:
|
||||
bands = 4
|
||||
palette_mode = "RGBA"
|
||||
|
||||
palette_bytes = b""
|
||||
new_positions = [0] * 256
|
||||
|
|
Loading…
Reference in New Issue
Block a user