Only compare to previous when checking for duplicate frames while saving

This commit is contained in:
Andrew Murray 2022-12-08 11:35:48 +11:00
parent 4c9ed122f3
commit 4ab837ae23
2 changed files with 35 additions and 15 deletions

View File

@ -677,6 +677,24 @@ def test_dispose2_background(tmp_path):
assert im.getpixel((0, 0)) == (255, 0, 0)
def test_dispose2_background_frame(tmp_path):
out = str(tmp_path / "temp.gif")
im_list = [Image.new("RGBA", (1, 20))]
different_frame = Image.new("RGBA", (1, 20))
different_frame.putpixel((0, 10), (255, 0, 0, 255))
im_list.append(different_frame)
# Frame that matches the background
im_list.append(Image.new("RGBA", (1, 20)))
im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=2)
with Image.open(out) as im:
assert im.n_frames == 3
def test_transparency_in_second_frame(tmp_path):
out = str(tmp_path / "temp.gif")
with Image.open("Tests/images/different_transparency.gif") as im:

View File

@ -565,6 +565,16 @@ def _write_single_frame(im, fp, palette):
fp.write(b"\0") # end of image data
def _getbbox(base_im, im_frame):
if _get_palette_bytes(im_frame) == _get_palette_bytes(base_im):
delta = ImageChops.subtract_modulo(im_frame, base_im)
else:
delta = ImageChops.subtract_modulo(
im_frame.convert("RGB"), base_im.convert("RGB")
)
return delta.getbbox()
def _write_multiple_frames(im, fp, palette):
duration = im.encoderinfo.get("duration")
@ -598,6 +608,12 @@ def _write_multiple_frames(im, fp, palette):
if im_frames:
# delta frame
previous = im_frames[-1]
bbox = _getbbox(previous["im"], im_frame)
if not bbox:
# This frame is identical to the previous frame
if duration:
previous["encoderinfo"]["duration"] += encoderinfo["duration"]
continue
if encoderinfo.get("disposal") == 2:
if background_im is None:
color = im.encoderinfo.get(
@ -606,21 +622,7 @@ def _write_multiple_frames(im, fp, palette):
background = _get_background(im_frame, color)
background_im = Image.new("P", im_frame.size, background)
background_im.putpalette(im_frames[0]["im"].palette)
base_im = background_im
else:
base_im = previous["im"]
if _get_palette_bytes(im_frame) == _get_palette_bytes(base_im):
delta = ImageChops.subtract_modulo(im_frame, base_im)
else:
delta = ImageChops.subtract_modulo(
im_frame.convert("RGB"), base_im.convert("RGB")
)
bbox = delta.getbbox()
if not bbox:
# This frame is identical to the previous frame
if duration:
previous["encoderinfo"]["duration"] += encoderinfo["duration"]
continue
bbox = _getbbox(background_im, im_frame)
else:
bbox = None
im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo})