Repository: python-pillow/Pillow

Issue:
ValueError: images do not match
Without changing code, only upgrading from 10.1.0 to 10.2.0, started getting this error when generating animated GIFs:

```pytb
  File "wakatime/insights/utils.py", line 481, in get_animated_insight
    images[0].save(out, format="gif", append_images=images[1:-1], save_all=True, duration=80, loop=0)
  File "venv/lib/python3.10/site-packages/PIL/Image.py", line 2439, in save
    save_handler(self, fp, filename)
  File "venv/lib/python3.10/site-packages/PIL/GifImagePlugin.py", line 704, in _save_all
    _save(im, fp, filename, save_all=True)
  File "venv/lib/python3.10/site-packages/PIL/GifImagePlugin.py", line 715, in _save
    if not save_all or not _write_multiple_frames(im, fp, palette):
  File "venv/lib/python3.10/site-packages/PIL/GifImagePlugin.py", line 671, in _write_multiple_frames
    diff_frame.paste(fill, mask=ImageOps.invert(mask))
  File "venv/lib/python3.10/site-packages/PIL/Image.py", line 1738, in paste
    self.im.paste(im, box, mask.im)
ValueError: images do not match
```

* OS: Linux
* Python: Python 3.10.12
* Pillow: pillow==10.2.0



Discussion:
Thank you for reporting an issue.

Please include a self-contained, copy-pastable example that generates the issue if possible. Be concise with code posted. Guidelines on how to provide a good bug report:

* https://stackoverflow.com/help/mcve

Bug reports which follow these guidelines are easier to diagnose, and are often handled much more quickly.

Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.

The best reproductions are self-contained scripts with minimal dependencies.
Looks like this commit is the culprit: 55c5587437669389bd7b0044753b47ca43afe59e
Yes, that would be the cause - but rather than just undoing that change, it would be better to adjust it, to both reduce filesize and to fix your problem. The quickest way of understanding how to do that would be for you to post a self-contained example of your problem.
Here's a repo to reproduce the bug:
https://github.com/alanhamlett/pillow-issue-7777
Thanks.

0.png, 4.png and 5.png are 120px wide.
1.png, 2.png and 3.png are 108px wide.

The images you are using to create your GIF are not all the same size. So, as error says, the images do not match.

If you change them to all be the same size, the error goes away.
Got it, so it should have raised that exception in previous versions too. Thanks!
Actually, looks like animated GIF format supports images of different sizes. Should Pillow also?

Resolving patch:
diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py
--- a/src/PIL/GifImagePlugin.py
+++ b/src/PIL/GifImagePlugin.py
@@ -649,9 +649,7 @@ def _write_multiple_frames(im, fp, palette):
                     if "transparency" in encoderinfo:
                         # When the delta is zero, fill the image with transparency
                         diff_frame = im_frame.copy()
-                        fill = Image.new(
-                            "P", diff_frame.size, encoderinfo["transparency"]
-                        )
+                        fill = Image.new("P", delta.size, encoderinfo["transparency"])
                         if delta.mode == "RGBA":
                             r, g, b, a = delta.split()
                             mask = ImageMath.eval(


Test patch:
diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py
--- a/Tests/test_file_gif.py
+++ b/Tests/test_file_gif.py
@@ -1105,6 +1105,21 @@ def im_generator(ims):
         assert reread.n_frames == 10
 
 
+def test_append_different_size_image(tmp_path: Path) -> None:
+    out = str(tmp_path / "temp.gif")
+
+    im = Image.new("RGB", (100, 100))
+    bigger_im = Image.new("RGB", (200, 200), "#f00")
+
+    im.save(out, save_all=True, append_images=[bigger_im])
+
+    with Image.open(out) as reread:
+        assert reread.size == (100, 100)
+
+        reread.seek(1)
+        assert reread.size == (100, 100)
+
+
 def test_transparent_optimize(tmp_path: Path) -> None:
     # From issue #2195, if the transparent color is incorrectly optimized out, GIF loses
     # transparency.