Repository: python-pillow/Pillow

Issue:
GIF error for multiple duration values
### What did you do?
Using same images  and a list of durations to produce a gif

### What did you expect to happen?
produce the gif the specified durations

### What actually happened?
 failed when saving

### What are your OS, Python and Pillow versions?

* OS: win10
* Python: 3.6
* Pillow: 6.1.0


to reproduce, add following testcase to `Tests/test_file_gif.py`, then run `pytest Tests/test_file_gif.py`
```python
    def test_totally_identical_frames(self):
        duration_list = [1000, 1500, 2000, 4000]

        out = self.tempfile("temp.gif")

        image_path = "Tests/images/bc7-argb-8bpp_MipMaps-1.png"
        im_list = [
            Image.open(image_path),
            Image.open(image_path),
            Image.open(image_path),
            Image.open(image_path),
        ]
        mask = Image.new("RGBA", im_list[0].size, (255, 255, 255, 0))

        frames = []
        for image in im_list:
            frames.append(Image.alpha_composite(mask, image))

        # duration as list
        frames[0].save(out,
                       save_all=True, append_images=frames[1:], optimize=False, duration=duration_list, loop=0,
                       transparency=0)

        reread = Image.open(out)

        # Assert that the first three frames were combined
        self.assertEqual(reread.n_frames, 1)

        # Assert that the new duration is the total of the identical frames
        self.assertEqual(reread.info["duration"], 8500)

```

err info is:

        if "duration" in im.encoderinfo:
            duration = int(im.encoderinfo["duration"] / 10)
            TypeError: unsupported operand type(s) for /: 'list' and 'int' 

https://github.com/python-pillow/Pillow/blob/f3f45cfec50a44970f325e6ef1a2e4eaf2caa89e/src/PIL/GifImagePlugin.py#L473-L477

seems like we should copy duration info from `im_frames[0]` to `im` when `len(im_frames) == 1`


Discussion:

Resolving patch:
diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py
--- a/src/PIL/GifImagePlugin.py
+++ b/src/PIL/GifImagePlugin.py
@@ -489,6 +489,11 @@ def _write_multiple_frames(im, fp, palette):
                 offset = frame_data["bbox"][:2]
             _write_frame_data(fp, im_frame, offset, frame_data["encoderinfo"])
         return True
+    elif "duration" in im.encoderinfo and isinstance(
+        im.encoderinfo["duration"], (list, tuple)
+    ):
+        # Since multiple frames will not be written, add together the frame durations
+        im.encoderinfo["duration"] = sum(im.encoderinfo["duration"])
 
 
 def _save_all(im, fp, filename):


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
@@ -495,6 +495,26 @@ def test_identical_frames(self):
         # Assert that the new duration is the total of the identical frames
         self.assertEqual(reread.info["duration"], 4500)
 
+    def test_identical_frames_to_single_frame(self):
+        for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500):
+            out = self.tempfile("temp.gif")
+            im_list = [
+                Image.new("L", (100, 100), "#000"),
+                Image.new("L", (100, 100), "#000"),
+                Image.new("L", (100, 100), "#000"),
+            ]
+
+            im_list[0].save(
+                out, save_all=True, append_images=im_list[1:], duration=duration
+            )
+            reread = Image.open(out)
+
+            # Assert that all frames were combined
+            self.assertEqual(reread.n_frames, 1)
+
+            # Assert that the new duration is the total of the identical frames
+            self.assertEqual(reread.info["duration"], 8500)
+
     def test_number_of_loops(self):
         number_of_loops = 2