Repository: python-pillow/Pillow

Issue:
GIF files with comments must be GIF89a
<!--
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?
Ran the GIF tests in Pillow-9.1.0, looked at output from `test_comment_over_255(tmp_path)` test.

### What did you expect to happen?
The output GIF file should be GIF89a because it contains a comment.

### What actually happened?
The file temp.gif has a signature of GIF87a.

### What are your OS, Python and Pillow versions?

* OS: Windows 10
* Python: 3.10.4
* Pillow: 9.1.0

<!--
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. If you are using a framework such as Plone, Django, or Buildout, try to replicate the issue just using Pillow.
-->

For code, see `def test_comment_over_255(tmp_path):` in `Tests\test_file_gif.py`.

The generated image file is:

![temp](https://user-images.githubusercontent.com/24783736/168376611-d6f37688-eeb3-4312-a763-2659aec4919f.gif)

Discussion:

This is due to an obsolete line in `_get_global_header(im, info)` in `GifImagePlugin.py`:
```python
                extensionKey == "comment" and not (1 <= len(info[extensionKey]) <= 255)
```

The `len(info[extensionKey])` should be simply tested for 0 to indicate no comment is wanted.
Suggested change is
```python
                extensionKey == "comment" and len(info[extensionKey]) == 0
```

I have created a pull request #6292 for this.

As a side note, I think the entire feature test for GIF 87a vs. 89a can be changed from:

```python
    version = b"87a"
    for extensionKey in ["transparency", "duration", "loop", "comment"]:
        if info and extensionKey in info:
            if (extensionKey == "duration" and info[extensionKey] == 0) or (
                extensionKey == "comment" and len(info[extensionKey]) == 0
            ):
                continue
            version = b"89a"
            break
    else:
        if im.info.get("version") == b"89a":
            version = b"89a"
```

to:

```python
    version = b"87a"
    if (im.info.get("version") == b"89a") or info and (
            "transparency" in info or
            "loop" in info or
            ("duration" in info and info["duration"] != 0) or
            ("comment" in info and len(info["comment"]) != 0)):
        version = b"89a"
```

I think that's correct but would be happy for someone to look it over.


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
@@ -912,17 +912,16 @@ def _get_global_header(im, info):
     # https://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
 
     version = b"87a"
-    for extensionKey in ["transparency", "duration", "loop", "comment"]:
-        if info and extensionKey in info:
-            if (extensionKey == "duration" and info[extensionKey] == 0) or (
-                extensionKey == "comment" and not (1 <= len(info[extensionKey]) <= 255)
-            ):
-                continue
-            version = b"89a"
-            break
-    else:
-        if im.info.get("version") == b"89a":
-            version = b"89a"
+    if im.info.get("version") == b"89a" or (
+        info
+        and (
+            "transparency" in info
+            or "loop" in info
+            or info.get("duration")
+            or info.get("comment")
+        )
+    ):
+        version = b"89a"
 
     background = _get_background(im, info.get("background"))
 


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
@@ -794,6 +794,9 @@ def test_comment(tmp_path):
     with Image.open(out) as reread:
         assert reread.info["comment"] == im.info["comment"].encode()
 
+        # Test that GIF89a is used for comments
+        assert reread.info["version"] == b"GIF89a"
+
 
 def test_comment_over_255(tmp_path):
     out = str(tmp_path / "temp.gif")
@@ -804,9 +807,11 @@ def test_comment_over_255(tmp_path):
     im.info["comment"] = comment
     im.save(out)
     with Image.open(out) as reread:
-
         assert reread.info["comment"] == comment
 
+        # Test that GIF89a is used for comments
+        assert reread.info["version"] == b"GIF89a"
+
 
 def test_zero_comment_subblocks():
     with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: