Skip to content

Commit

Permalink
Merge pull request #6787 from radarhere/gif_disposal
Browse files Browse the repository at this point in the history
Resolves #6785
  • Loading branch information
hugovk committed Dec 23, 2022
2 parents f9c88c9 + 921c466 commit 7a19251
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
18 changes: 18 additions & 0 deletions Tests/test_file_gif.py
Expand Up @@ -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:
Expand Down
32 changes: 17 additions & 15 deletions src/PIL/GifImagePlugin.py
Expand Up @@ -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")
Expand Down Expand Up @@ -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 encoderinfo.get("duration"):
previous["encoderinfo"]["duration"] += encoderinfo["duration"]
continue
if encoderinfo.get("disposal") == 2:
if background_im is None:
color = im.encoderinfo.get(
Expand All @@ -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 encoderinfo.get("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})
Expand Down

0 comments on commit 7a19251

Please sign in to comment.