Repository: python-pillow/Pillow

Issue:
Error on saving APNG
<!--
Thank you for reporting an issue.

Follow these guidelines to ensure your issue is handled properly.

If you have a ...

1.  General question: consider asking the question on Stack Overflow
    with the python-imaging-library tag:

    * https://stackoverflow.com/questions/tagged/python-imaging-library

    Do not ask a question in both places.

    If you think you have found a bug or have an unexplained exception
    then file a bug report here.

2.  Bug report: 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.

3.  Feature request: do a quick search of existing issues
    to make sure this has not been asked before.

We know asking good questions takes effort, and we appreciate your time.
Thank you.
-->

### What did you do?
I opened a PNG image that behaves sort of like a GIF , then I tried to save.

### What did you expect to happen?
No error, image saved normally.

### What actually happened?

`Traceback (most recent call last):                                                                                        File "<stdin>", line 1, in <module>                                                                                     File "C:\Python38\lib\site-packages\PIL\Image.py", line 2100, in save                                                     self._ensure_mutable()                                                                                                File "C:\Python38\lib\site-packages\PIL\Image.py", line 617, in _ensure_mutable                                           self._copy()                                                                                                          File "C:\Python38\lib\site-packages\PIL\Image.py", line 610, in _copy                                                     self.load()                                                                                                           File "C:\Python38\lib\site-packages\PIL\ImageFile.py", line 262, in load                                                  self.load_end()                                                                                                       File "C:\Python38\lib\site-packages\PIL\PngImagePlugin.py", line 921, in load_end                                         self._prev_im.paste(dispose, self.dispose_extent)                                                                   ValueError: images do not match  `

### What are your OS, Python and Pillow versions?


* OS: Windows 10
* Python: 3.8.3
* Pillow: 7.1.2

```python
from PIL import Image
im = Image.open('problem.png')
im.save('out.png')

```
![problem](https://user-images.githubusercontent.com/28062763/85478800-4b844100-b593-11ea-8662-478de5d8c41b.png)



Discussion:
A quick check: it's coming from `PngImageFile.load_end` because `dispose.mode` is RGBA and `self._prev_im.mode` is P here:


```python
            if dispose:
                self._prev_im.paste(dispose, self.dispose_extent)
```
And they must match in `ImagingPaste` in `Paste.c` (the x and y sizes all match, mode is `pixelsize`):
```c
    if (xsize != imIn->xsize || ysize != imIn->ysize ||
        pixelsize != imIn->pixelsize) {
        (void) ImagingError_Mismatch();
        return -1;
    }
```


ping @pmrowla


I'll look into this when I get a chance, but probably won't be until this weekend at the earliest

Resolving patch:
diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py
--- a/src/PIL/PngImagePlugin.py
+++ b/src/PIL/PngImagePlugin.py
@@ -904,7 +904,7 @@ def load_end(self):
                 dispose = self._prev_im.copy()
                 dispose = self._crop(dispose, self.dispose_extent)
             elif self.dispose_op == APNG_DISPOSE_OP_BACKGROUND:
-                dispose = Image.core.fill("RGBA", self.size, (0, 0, 0, 0))
+                dispose = Image.core.fill(self.im.mode, self.size)
                 dispose = self._crop(dispose, self.dispose_extent)
             else:
                 dispose = None


Test patch:
diff --git a/Tests/images/apng/dispose_op_background_p_mode.png b/Tests/images/apng/dispose_op_background_p_mode.png
new file mode 100644
Binary files /dev/null and b/Tests/images/apng/dispose_op_background_p_mode.png differ
diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py
--- a/Tests/test_file_apng.py
+++ b/Tests/test_file_apng.py
@@ -104,6 +104,13 @@ def test_apng_dispose_region():
         assert im.getpixel((64, 32)) == (0, 255, 0, 255)
 
 
+def test_apng_dispose_op_background_p_mode():
+    with Image.open("Tests/images/apng/dispose_op_background_p_mode.png") as im:
+        im.seek(1)
+        im.load()
+        assert im.size == (128, 64)
+
+
 def test_apng_blend():
     with Image.open("Tests/images/apng/blend_op_source_solid.png") as im:
         im.seek(im.n_frames - 1)