Repository: python-pillow/Pillow

Issue:
Change in behavior with JPEG Images in 11.2.0
It looks like something in Pillow 11.2 introduced an issue similar to this: https://github.com/python-pillow/Pillow/issues/8472. This time with the `filename` attribute.

<!--
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?

```python
import pickle

from io import BytesIO

from PIL import Image

im = Image.open("anyimage.jpg")

p = pickle.dumps(im)
im = pickle.loads(p)

# Fails in 11.2, works in 11.1
output = BytesIO()
im.save(output, format=im.format, quality="keep")
```

### What did you expect to happen?

The code above to work.

### What actually happened?

```pytb
Traceback (most recent call last):
  File "test.py", line 14, in <module>
    im.save(output, format=im.format, quality="keep")
  File "/local/lib64/python3.9/site-packages/PIL/Image.py", line 2546, in save
    if isinstance(self, ImageFile.ImageFile) and filename == self.filename:
  File "/local/lib64/python3.9/site-packages/PIL/JpegImagePlugin.py", line 400, in __getattr__
    raise AttributeError(name)
AttributeError: filename
```

### What are your OS, Python and Pillow versions?

* OS: Linux
* Python: Python 3.9
* Pillow: 11.2

Hints from issue comments:
@hugovk: Please edit and fill in the issue template:

https://github.com/python-pillow/Pillow/blob/main/.github/ISSUE_TEMPLATE/ISSUE_REPORT.md?plain=1 @davidmezzetti: Done. @radarhere: I've created https://github.com/python-pillow/Pillow/pull/8859@davidmezzetti: Thank you for the rapid response and fix! I appreciate it. @radarhere: Pillow 11.2.1 has now been released with the fix.

Solution patch:
diff --git a/src/PIL/Image.py b/src/PIL/Image.py
index c62d7a8a3..807814c02 100644
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -2543,7 +2543,9 @@ class Image:
         from . import ImageFile
 
         # may mutate self!
-        if isinstance(self, ImageFile.ImageFile) and filename == self.filename:
+        if isinstance(self, ImageFile.ImageFile) and os.path.abspath(
+            filename
+        ) == os.path.abspath(self.filename):
             self._ensure_mutable()
         else:
             self.load()
diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py
index c5d6383a5..bcb7d462e 100644
--- a/src/PIL/ImageFile.py
+++ b/src/PIL/ImageFile.py
@@ -252,8 +252,12 @@ class ImageFile(Image.Image):
             return Image.MIME.get(self.format.upper())
         return None
 
+    def __getstate__(self) -> list[Any]:
+        return super().__getstate__() + [self.filename]
+
     def __setstate__(self, state: list[Any]) -> None:
         self.tile = []
+        self.filename = state[5]
         super().__setstate__(state)
 
     def verify(self) -> None:
diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py
index cc1d54b93..969528841 100644
--- a/src/PIL/JpegImagePlugin.py
+++ b/src/PIL/JpegImagePlugin.py
@@ -403,8 +403,8 @@ class JpegImageFile(ImageFile.ImageFile):
         return super().__getstate__() + [self.layers, self.layer]
 
     def __setstate__(self, state: list[Any]) -> None:
+        self.layers, self.layer = state[6:]
         super().__setstate__(state)
-        self.layers, self.layer = state[5:]
 
     def load_read(self, read_bytes: int) -> bytes:
         """


Test patch:
diff --git a/Tests/test_pickle.py b/Tests/test_pickle.py
index 70661ecc1..1c48cb743 100644
--- a/Tests/test_pickle.py
+++ b/Tests/test_pickle.py
@@ -81,6 +81,7 @@ def test_pickle_jpeg() -> None:
         unpickled_image = pickle.loads(pickle.dumps(image))
 
     # Assert
+    assert unpickled_image.filename == "Tests/images/hopper.jpg"
     assert len(unpickled_image.layer) == 3
     assert unpickled_image.layers == 3