Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Tests/test_file_gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def test_l_mode_transparency_after_rgb() -> None:
def test_palette_not_needed_for_second_frame() -> None:
with Image.open("Tests/images/palette_not_needed_for_second_frame.gif") as im:
im.seek(1)
assert im.palette is None
assert_image_similar(im, hopper("L").convert("RGB"), 8)


Expand All @@ -131,10 +132,12 @@ def test_strategy(monkeypatch: pytest.MonkeyPatch) -> None:
)
with Image.open("Tests/images/iss634.gif") as im:
assert im.mode == "RGB"
assert im.palette is None
assert_image_equal(im, expected_rgb_always)

with Image.open("Tests/images/chi.gif") as im:
assert im.mode == "RGBA"
assert im.palette is None
assert_image_equal(im, expected_rgb_always_rgba)

monkeypatch.setattr(
Expand Down Expand Up @@ -1375,16 +1378,15 @@ def test_palette_save_all_P(tmp_path: Path) -> None:
)

with Image.open(out) as im:
# Assert that the frames are correct, and each frame has the same palette
# Assert that the frames are correct
assert isinstance(im, GifImagePlugin.GifImageFile)
assert_image_equal(im.convert("RGB"), frames[0].convert("RGB"))
assert im.palette is not None
assert im.global_palette is not None
assert im.palette.palette == im.global_palette.palette

im.seek(1)
assert_image_equal(im.convert("RGB"), frames[1].convert("RGB"))
assert im.palette.palette == im.global_palette.palette
assert_image_equal(im, frames[1].convert("RGB"))


def test_palette_save_ImagePalette(tmp_path: Path) -> None:
Expand Down
43 changes: 22 additions & 21 deletions src/PIL/GifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def _open(self) -> None:
p = self.fp.read(3 << bits)
if self._is_palette_needed(p):
palette = ImagePalette.raw("RGB", p)
self.global_palette = self.palette = palette
self.global_palette = palette

self._fp = self.fp # FIXME: hack
self.__rewind = self.fp.tell()
Expand Down Expand Up @@ -319,22 +319,20 @@ def _seek(self, frame: int, update_image: bool = True) -> None:
self._frame_palette = palette if palette is not None else self.global_palette
self._frame_transparency = frame_transparency
if frame == 0:
self.palette = None
if self._frame_palette:
if LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS:
self._mode = "RGBA" if frame_transparency is not None else "RGB"
else:
self._mode = "P"
else:
self._mode = "L"
if palette:
self.palette = palette
elif self.global_palette:
from copy import copy

if palette:
self.palette = palette
elif self.global_palette:
from copy import copy

self.palette = copy(self.global_palette)
self.palette = copy(self.global_palette)
else:
self.palette = None
self._mode = "L"
elif self.mode == "P" and (
LOADING_STRATEGY != LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY
or palette
Expand All @@ -347,6 +345,7 @@ def _seek(self, frame: int, update_image: bool = True) -> None:
else:
self._mode = "RGB"
self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG)
self.palette = None

def _rgb(color: int) -> tuple[int, int, int]:
if self._frame_palette:
Expand Down Expand Up @@ -376,12 +375,12 @@ def _rgb(color: int) -> tuple[int, int, int]:
dispose_mode = "P"
color = self.info.get("transparency", frame_transparency)
if color is not None:
if self.mode in ("RGB", "RGBA"):
if self.mode in {"RGB", "RGBA"}:
dispose_mode = "RGBA"
color = _rgb(color) + (0,)
else:
color = self.info.get("background", 0)
if self.mode in ("RGB", "RGBA"):
if self.mode in {"RGB", "RGBA"}:
dispose_mode = "RGB"
color = _rgb(color)
self.dispose = Image.core.fill(dispose_mode, dispose_size, color)
Expand All @@ -397,7 +396,7 @@ def _rgb(color: int) -> tuple[int, int, int]:
Image._decompression_bomb_check(dispose_size)
dispose_mode = "P"
color = frame_transparency
if self.mode in ("RGB", "RGBA"):
if self.mode in {"RGB", "RGBA"}:
dispose_mode = "RGBA"
color = _rgb(frame_transparency) + (0,)
self.dispose = Image.core.fill(
Expand All @@ -412,7 +411,7 @@ def _rgb(color: int) -> tuple[int, int, int]:
if frame == 0:
if LOADING_STRATEGY != LoadingStrategy.RGB_ALWAYS:
self.info["transparency"] = frame_transparency
elif self.mode not in ("RGB", "RGBA"):
elif self.mode not in {"RGB", "RGBA"}:
transparency = frame_transparency
self.tile = [
ImageFile._Tile(
Expand All @@ -435,11 +434,13 @@ def load_prepare(self) -> None:
temp_mode = "P" if self._frame_palette else "L"
self._prev_im = None
if self.__frame == 0:
if self._frame_transparency is not None:
self.im = Image.core.fill(
temp_mode, self.size, self._frame_transparency
)
elif self.mode in ("RGB", "RGBA"):
self.im = Image.core.fill(
temp_mode, self.size, self._frame_transparency or 0
)
if temp_mode == "P":
assert self._frame_palette
self.im.putpalette("RGB", *self._frame_palette.getdata())
elif self.mode in {"RGB", "RGBA"}:
self._prev_im = self.im
if self._frame_palette:
self.im = Image.core.fill("P", self.size, self._frame_transparency or 0)
Expand Down Expand Up @@ -495,7 +496,7 @@ def load_end(self) -> None:

self.im = self._prev_im
self._mode = self.im.mode
if frame_im.mode in ("LA", "RGBA"):
if frame_im.mode in {"LA", "RGBA"}:
self.im.paste(frame_im, self.dispose_extent, frame_im)
else:
self.im.paste(frame_im, self.dispose_extent)
Expand Down Expand Up @@ -870,7 +871,7 @@ def _get_optimize(im: Image.Image, info: dict[str, Any]) -> list[int] | None:
:returns: list of indexes of palette entries in use, or None
"""
if (
im.mode in ("P", "L")
im.mode in {"L", "P"}
and info
and info.get("optimize")
and im.width != 0
Expand Down
Loading