diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index a9789a99cfb..d48fc144205 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -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: diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index b1d842cef70..c64a465d656 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -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 encoderinfo.get("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 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})