diff --git a/Tests/images/no_palette.gif b/Tests/images/no_palette.gif new file mode 100644 index 000000000..0432ebcb6 Binary files /dev/null and b/Tests/images/no_palette.gif differ diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 924adad9e..ba277a776 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -59,7 +59,15 @@ def test_invalid_file(): GifImagePlugin.GifImageFile(invalid_file) -def test_l_mode_transparency(): +def test_l_mode_subsequent_frames(): + with Image.open("Tests/images/no_palette.gif") as im: + assert im.mode == "L" + assert im.load()[0, 0] == 0 + + im.seek(1) + assert im.mode == "L" + assert im.load()[0, 0] == 0 + with Image.open("Tests/images/no_palette_with_transparency.gif") as im: assert im.mode == "L" assert im.load()[0, 0] == 0 diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 08af189da..5db1b8c7d 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -106,8 +106,9 @@ writes run-length encoded files in GIF87a by default, unless GIF89a features are used or GIF89a is already in use. GIF files are initially read as grayscale (``L``) or palette mode (``P``) -images, but seeking to later frames in an image will change the mode to either -``RGB`` or ``RGBA``, depending on whether the first frame had transparency. +images. Seeking to later frames in a ``P`` image will change the image to +``RGB`` (or ``RGBA`` if the first frame had transparency). ``L`` images will +stay in ``L`` mode (or change to ``LA`` if the first frame had transparency). The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 9cf27b026..764eda6ee 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -174,21 +174,22 @@ class GifImageFile(ImageFile.ImageFile): if update_image: if self.__frame == 1: self.pyaccess = None - if "transparency" in self.info: - if self.mode == "P": + if self.mode == "P": + if "transparency" in self.info: self.im.putpalettealpha(self.info["transparency"], 0) self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG) self.mode = "RGBA" + del self.info["transparency"] else: - self.im = self.im.convert_transparent( - "LA", self.info["transparency"] - ) - self.mode = "LA" - + self.mode = "RGB" + self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG) + elif "transparency" in self.info: + self.im = self.im.convert_transparent( + "LA", self.info["transparency"] + ) + self.mode = "LA" del self.info["transparency"] - else: - self.mode = "RGB" - self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG) + if self.dispose: self.im.paste(self.dispose, self.dispose_extent) @@ -387,14 +388,17 @@ class GifImageFile(ImageFile.ImageFile): def load_end(self): if self.__frame == 0: return - if self._frame_transparency is not None: - if self.mode == "P": + if self.mode == "P": + if self._frame_transparency is not None: self.im.putpalettealpha(self._frame_transparency, 0) frame_im = self.im.convert("RGBA") else: - frame_im = self.im.convert_transparent("LA", self._frame_transparency) + frame_im = self.im.convert("RGB") else: - frame_im = self.im.convert("RGB") + if self._frame_transparency is not None: + frame_im = self.im.convert_transparent("LA", self._frame_transparency) + else: + frame_im = self.im frame_im = self._crop(frame_im, self.dispose_extent) self.im = self._prev_im