diff --git a/src/PIL/Image.py b/src/PIL/Image.py
--- a/src/PIL/Image.py
+++ b/src/PIL/Image.py
@@ -644,6 +644,22 @@ def __repr__(self):
             id(self),
         )
 
+    def _repr_pretty_(self, p, cycle):
+        """IPython plain text display support"""
+
+        # Same as __repr__ but without unpredicatable id(self),
+        # to keep Jupyter notebook `text/plain` output stable.
+        p.text(
+            "<%s.%s image mode=%s size=%dx%d>"
+            % (
+                self.__class__.__module__,
+                self.__class__.__name__,
+                self.mode,
+                self.size[0],
+                self.size[1],
+            )
+        )
+
     def _repr_png_(self):
         """iPython display hook support
 

diff --git a/Tests/test_image.py b/Tests/test_image.py
--- a/Tests/test_image.py
+++ b/Tests/test_image.py
@@ -88,6 +88,17 @@ def test_sanity(self):
         # with pytest.raises(MemoryError):
         #   Image.new("L", (1000000, 1000000))
 
+    def test_repr_pretty(self):
+        class Pretty:
+            def text(self, text):
+                self.pretty_output = text
+
+        im = Image.new("L", (100, 100))
+
+        p = Pretty()
+        im._repr_pretty_(p, None)
+        assert p.pretty_output == "<PIL.Image.Image image mode=L size=100x100>"
+
     def test_open_formats(self):
         PNGFILE = "Tests/images/hopper.png"
         JPGFILE = "Tests/images/hopper.jpg"

Changing Jupyter plain text output on every cell run
### What did you do?

I'm using Pillow to generate simple images in Jupyter environment:

```python
from PIL import Image
Image.frombuffer('RGB', (16,16), bytes([100]*(16*16)))
```

It works nicely!

![image](https://user-images.githubusercontent.com/510678/146259055-bff41a14-b40d-452e-a354-11c05ce78b58.png)

### What did you expect to happen?

I expect every run of the cell produce the same output in the notebook file, to avoid needless changes in Git.

### What actually happened?

Every run produces different hash in text representation of the output. For example: `at 0x1075D8370`.

```diff
$ git diff test.ipynb 
diff --git a/test.ipynb b/test.ipynb
index f769d4b..a4dd8af 100644
--- a/test.ipynb
+++ b/test.ipynb
@@ -9,7 +9,7 @@
      "data": {
       "image/png": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGUlEQVR4nGPc62fCQApgIkn1qIZRDUNKAwADRwFfBBwAnwAAAABJRU5ErkJggg==",
       "text/plain": [
-       "<PIL.Image.Image image mode=RGB size=16x16 at 0x1075D8370>"
+       "<PIL.Image.Image image mode=RGB size=16x16 at 0x108C50160>"
       ]
      },
      "execution_count": 1,
```

Compare with Matplotlib output:

```json
     "data": {
      "image/png": "...",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     }
```

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

* OS: Mac OS 10.15.6
* Python: 3.9.8
* Pillow: 8.4.0
