Added setting to convert first GIF frame to RGB

This commit is contained in:
Andrew Murray 2022-03-20 16:28:31 +11:00
parent 7928e944cb
commit 66bb2bd5e8
3 changed files with 39 additions and 6 deletions

View File

@ -78,6 +78,18 @@ def test_l_mode_subsequent_frames():
assert im.load()[0, 0] == (0, 255)
def test_strategy():
with Image.open(TEST_GIF) as im:
expected = im.convert("RGB")
GifImagePlugin.PALETTE_TO_RGB = GifImagePlugin.ModeStrategy.ALWAYS
with Image.open(TEST_GIF) as im:
assert im.mode == "RGB"
assert_image_equal(im, expected)
GifImagePlugin.PALETTE_TO_RGB = GifImagePlugin.ModeStrategy.AFTER_FIRST
def test_optimize():
def test_grayscale(optimize):
im = Image.new("L", (1, 1), 0)

View File

@ -110,6 +110,13 @@ 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).
If you would prefer the first ``P`` image frame to be ``RGB``, so that ``P``
frames are always converted to ``RGB`` or ``RGBA`` mode, there is a setting
available::
from PIL import GifImagePlugin
GifImagePlugin.PALETTE_TO_RGB = GifImagePlugin.ModeStrategy.ALWAYS
The :py:meth:`~PIL.Image.open` method sets the following
:py:attr:`~PIL.Image.Image.info` properties:

View File

@ -28,12 +28,21 @@ import itertools
import math
import os
import subprocess
from enum import IntEnum
from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence
from ._binary import i16le as i16
from ._binary import o8
from ._binary import o16le as o16
class ModeStrategy(IntEnum):
AFTER_FIRST = 0
ALWAYS = 1
PALETTE_TO_RGB = ModeStrategy.AFTER_FIRST
# --------------------------------------------------------------------
# Identify/read GIF files
@ -355,18 +364,22 @@ class GifImageFile(ImageFile.ImageFile):
del self.info[k]
if frame == 0:
self.mode = "P" if frame_palette else "L"
if frame_palette:
self.mode = "RGB" if PALETTE_TO_RGB == ModeStrategy.ALWAYS else "P"
else:
self.mode = "L"
if self.mode == "P" and not palette:
if not palette and self.global_palette:
from copy import copy
palette = copy(self.global_palette)
self.palette = palette
else:
self._frame_palette = frame_palette
self._frame_transparency = frame_transparency
self._frame_palette = frame_palette
def load_prepare(self):
self.mode = "P" if self._frame_palette else "L"
if self.__frame == 0:
if "transparency" in self.info:
self.im = Image.core.fill(
@ -375,18 +388,19 @@ class GifImageFile(ImageFile.ImageFile):
else:
self._prev_im = self.im
if self._frame_palette:
self.mode = "P"
self.im = Image.core.fill("P", self.size, self._frame_transparency or 0)
self.im.putpalette(*self._frame_palette.getdata())
self._frame_palette = None
else:
self.mode = "L"
self.im = None
self._frame_palette = None
super().load_prepare()
def load_end(self):
if self.__frame == 0:
if self.mode == "P" and PALETTE_TO_RGB == ModeStrategy.ALWAYS:
self.mode = "RGB"
self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG)
return
if self.mode == "P":
if self._frame_transparency is not None: