mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-20 20:24:45 +03:00
src/PIL/GifImagePlugin.py: only convert image if palettes actually change
This commit is contained in:
parent
82541b6dec
commit
15c58dd1d2
|
@ -366,16 +366,12 @@ def test_dispose_background():
|
||||||
def test_dispose_background_transparency():
|
def test_dispose_background_transparency():
|
||||||
with Image.open("Tests/images/dispose_bgnd_transparency.gif") as img:
|
with Image.open("Tests/images/dispose_bgnd_transparency.gif") as img:
|
||||||
img.seek(2)
|
img.seek(2)
|
||||||
px = img.load()
|
px = img.convert("RGBA").load()
|
||||||
assert px[35, 30][3] == 0
|
assert px[35, 30][3] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_transparent_dispose():
|
def test_transparent_dispose():
|
||||||
expected_colors = [
|
expected_colors = [(2, 1, 2), (0, 1, 0), (2, 1, 2)]
|
||||||
(2, 1, 2),
|
|
||||||
((0, 255, 24, 255), (0, 0, 255, 255), (0, 255, 24, 255)),
|
|
||||||
((0, 0, 0, 0), (0, 0, 255, 255), (0, 0, 0, 0)),
|
|
||||||
]
|
|
||||||
with Image.open("Tests/images/transparent_dispose.gif") as img:
|
with Image.open("Tests/images/transparent_dispose.gif") as img:
|
||||||
for frame in range(3):
|
for frame in range(3):
|
||||||
img.seek(frame)
|
img.seek(frame)
|
||||||
|
@ -956,7 +952,9 @@ def test_missing_background():
|
||||||
# but the disposal method is "Restore to background color"
|
# but the disposal method is "Restore to background color"
|
||||||
with Image.open("Tests/images/missing_background.gif") as im:
|
with Image.open("Tests/images/missing_background.gif") as im:
|
||||||
im.seek(1)
|
im.seek(1)
|
||||||
assert_image_equal_tofile(im, "Tests/images/missing_background_first_frame.png")
|
assert_image_equal_tofile(
|
||||||
|
im.convert("RGBA"), "Tests/images/missing_background_first_frame.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_saving_rgba(tmp_path):
|
def test_saving_rgba(tmp_path):
|
||||||
|
|
|
@ -55,6 +55,9 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
global_palette = None
|
global_palette = None
|
||||||
|
|
||||||
|
constant_palette = True
|
||||||
|
last_palette = None
|
||||||
|
|
||||||
def data(self):
|
def data(self):
|
||||||
s = self.fp.read(1)
|
s = self.fp.read(1)
|
||||||
if s and s[0]:
|
if s and s[0]:
|
||||||
|
@ -82,7 +85,7 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
for i in range(0, len(p), 3):
|
for i in range(0, len(p), 3):
|
||||||
if not (i // 3 == p[i] == p[i + 1] == p[i + 2]):
|
if not (i // 3 == p[i] == p[i + 1] == p[i + 2]):
|
||||||
p = ImagePalette.raw("RGB", p)
|
p = ImagePalette.raw("RGB", p)
|
||||||
self.global_palette = self.palette = p
|
self.global_palette = self.last_palette = self.palette = p
|
||||||
break
|
break
|
||||||
|
|
||||||
self.__fp = self.fp # FIXME: hack
|
self.__fp = self.fp # FIXME: hack
|
||||||
|
@ -164,25 +167,12 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
pass
|
pass
|
||||||
self.__offset = 0
|
self.__offset = 0
|
||||||
|
|
||||||
if self.__frame == 1:
|
|
||||||
self.pyaccess = None
|
|
||||||
if "transparency" in self.info:
|
|
||||||
self.mode = "RGBA"
|
|
||||||
self.im.putpalettealpha(self.info["transparency"], 0)
|
|
||||||
self.im = self.im.convert("RGBA", Image.FLOYDSTEINBERG)
|
|
||||||
|
|
||||||
del self.info["transparency"]
|
|
||||||
else:
|
|
||||||
self.mode = "RGB"
|
|
||||||
self.im = self.im.convert("RGB", Image.FLOYDSTEINBERG)
|
|
||||||
if self.dispose:
|
|
||||||
self.im.paste(self.dispose, self.dispose_extent)
|
|
||||||
|
|
||||||
palette = None
|
palette = None
|
||||||
|
|
||||||
info = {}
|
info = {}
|
||||||
frame_transparency = None
|
frame_transparency = None
|
||||||
interlace = None
|
interlace = None
|
||||||
|
tmp_dispose_extent = None
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
s = self.fp.read(1)
|
s = self.fp.read(1)
|
||||||
|
@ -247,7 +237,7 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
x1, y1 = x0 + i16(s, 4), y0 + i16(s, 6)
|
x1, y1 = x0 + i16(s, 4), y0 + i16(s, 6)
|
||||||
if x1 > self.size[0] or y1 > self.size[1]:
|
if x1 > self.size[0] or y1 > self.size[1]:
|
||||||
self._size = max(x1, self.size[0]), max(y1, self.size[1])
|
self._size = max(x1, self.size[0]), max(y1, self.size[1])
|
||||||
self.dispose_extent = x0, y0, x1, y1
|
tmp_dispose_extent = x0, y0, x1, y1
|
||||||
flags = s[8]
|
flags = s[8]
|
||||||
|
|
||||||
interlace = (flags & 64) != 0
|
interlace = (flags & 64) != 0
|
||||||
|
@ -267,6 +257,41 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
frame_palette = palette or self.global_palette
|
frame_palette = palette or self.global_palette
|
||||||
|
|
||||||
|
# as long as we have a constant palette, we check whether this frame
|
||||||
|
# still has the same palette
|
||||||
|
if self.constant_palette:
|
||||||
|
if self.last_palette is None:
|
||||||
|
self.last_palette = palette
|
||||||
|
else:
|
||||||
|
if self.last_palette != frame_palette:
|
||||||
|
self.constant_palette = False
|
||||||
|
|
||||||
|
if self.__frame > 0:
|
||||||
|
# for every frame after the first frame, we check whether the
|
||||||
|
# palette is still constant and convert to RGB or RGBA if not
|
||||||
|
self.pyaccess = None
|
||||||
|
if not self.constant_palette and self.mode not in ("RGB", "RGBA"):
|
||||||
|
if "transparency" in self.info:
|
||||||
|
self.mode = "RGBA"
|
||||||
|
self.im.putpalettealpha(self.info["transparency"], 0)
|
||||||
|
self.im = self.im.convert("RGBA", Image.FLOYDSTEINBERG)
|
||||||
|
if self.dispose:
|
||||||
|
self.dispose = self.dispose.convert(
|
||||||
|
"RGBA", Image.FLOYDSTEINBERG
|
||||||
|
)
|
||||||
|
|
||||||
|
del self.info["transparency"]
|
||||||
|
else:
|
||||||
|
self.mode = "RGB"
|
||||||
|
self.im = self.im.convert("RGB", Image.FLOYDSTEINBERG)
|
||||||
|
if self.dispose:
|
||||||
|
self.dispose = self.dispose.convert("RGB", Image.FLOYDSTEINBERG)
|
||||||
|
if self.dispose:
|
||||||
|
self.im.paste(self.dispose, self.dispose_extent)
|
||||||
|
|
||||||
|
if tmp_dispose_extent is not None:
|
||||||
|
self.dispose_extent = tmp_dispose_extent
|
||||||
|
|
||||||
def _rgb(color):
|
def _rgb(color):
|
||||||
if frame_palette:
|
if frame_palette:
|
||||||
color = tuple(frame_palette.palette[color * 3 : color * 3 + 3])
|
color = tuple(frame_palette.palette[color * 3 : color * 3 + 3])
|
||||||
|
@ -289,6 +314,11 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# by convention, attempt to use transparency first
|
# by convention, attempt to use transparency first
|
||||||
color = self.info.get("transparency", frame_transparency)
|
color = self.info.get("transparency", frame_transparency)
|
||||||
|
if self.constant_palette:
|
||||||
|
if color is None:
|
||||||
|
color = self.info.get("background", 0)
|
||||||
|
self.dispose = Image.core.fill("P", dispose_size, color)
|
||||||
|
else:
|
||||||
if color is not None:
|
if color is not None:
|
||||||
dispose_mode = "RGBA"
|
dispose_mode = "RGBA"
|
||||||
color = _rgb(color) + (0,)
|
color = _rgb(color) + (0,)
|
||||||
|
@ -307,7 +337,11 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
Image._decompression_bomb_check(dispose_size)
|
Image._decompression_bomb_check(dispose_size)
|
||||||
self.dispose = Image.core.fill(
|
self.dispose = Image.core.fill(
|
||||||
"RGBA", dispose_size, _rgb(frame_transparency) + (0,)
|
"P" if self.constant_palette else "RGBA",
|
||||||
|
dispose_size,
|
||||||
|
frame_transparency
|
||||||
|
if self.constant_palette
|
||||||
|
else _rgb(frame_transparency) + (0,),
|
||||||
)
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
@ -367,6 +401,8 @@ class GifImageFile(ImageFile.ImageFile):
|
||||||
def load_end(self):
|
def load_end(self):
|
||||||
if self.__frame == 0:
|
if self.__frame == 0:
|
||||||
return
|
return
|
||||||
|
frame_im = self.im
|
||||||
|
if self._prev_im.mode != self.im.mode:
|
||||||
if self._frame_transparency is not None:
|
if self._frame_transparency is not None:
|
||||||
self.im.putpalettealpha(self._frame_transparency, 0)
|
self.im.putpalettealpha(self._frame_transparency, 0)
|
||||||
frame_im = self.im.convert("RGBA")
|
frame_im = self.im.convert("RGBA")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user