Repository: python-pillow/Pillow

Issue:
Displaying images in Google Colab
<!--
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?
`Image.show()`

### What did you expect to happen?
Display the Image

### What actually happened?
<PIL.PngImagePlugin.PngImageFile image mode=RGB size=450x253 at 0x7FFB7B401C50>

### What are your OS, Python and Pillow versions?

* OS: Windows
* Python: 3.9
* Pillow: 7.0.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.
-->

```python
display(image)
```


Discussion:
At the moment, this is somewhat confusing.

For one thing, you can't simply call `Image.show()` - unless `Image` is the name of your variable.
You could
```python
from PIL import Image
im = Image.new("RGB", (100, 100))
im.show()
```

For another, where does the `display()` method come from? That's not a part of Pillow.

Would you be able to provide a more complete example?
![Capture](https://user-images.githubusercontent.com/62174033/109224355-e3929400-77cc-11eb-946c-3bc765c2971d.PNG)
So I tried `im.show()` and couldn't print anything. I tried `display(im)` and it worked for me.
@radarhere I am using Colab.
@radarhere I have tried `im.show()` using my terminal and it works fine. I do not know why it's not working on https://colab.research.google.com
From https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.show:

> Displays this image. This method is mainly intended for debugging purposes.
>
> This method calls PIL.ImageShow.show() internally. You can use PIL.ImageShow.register() to override its default behaviour.
>
> The image is first saved to a temporary file. By default, it will be in PNG format.
>
> On Unix, the image is then opened using the display, eog or xv utility, depending on which one can be found.
>
> On macOS, the image is opened with the native Preview application.
>
> On Windows, the image is opened with the standard PNG display utility.

The display, eog and xv utilities require a display; Google Colab doesn't give you access to the display, only a terminal.
@nulano  Other libraries like those for visualization are displaying their images on Colab well. Does this mean it cannot be done with Pillow?
I've created PR #5289 to suggest adding this functionality to Pillow. Even if it is merged though, it might take a while to get bundled into Google Colab, since the current version in Colab is Pillow 7.0, a bit behind the current version of 8.1.0.
@radarhere and @nulano  will this make me a contributor or I must write code?
No, 'Contributors' isn't a manual list that we add you to, it's an automatic one - you must write a commit, and have that commit be merged in.
@radarhere so how can I contribute ? I see almost everything is pretty much done.
If you're asking what the next step is to the change being accepted, this is the review stage. So anyone, yourself included, can take a look at it and make comments for how it could be improved, or create a pull request in my Pillow fork with commits that they would like to be added to it.

After that, one of the Pillow members needs to decide to merge it, and then it will be part of the next Pillow release. So the soonest it could be released is April 1.
@radarhere I really wanted to contribute to that functionality. Guess I should probably look out for other improvements and Create a PR myself.
A good place to start is with documentation. 

You could add https://github.com/python-pillow/Pillow/pull/5289 to the release notes, perhaps in the API Additions section? 

https://github.com/python-pillow/Pillow/blob/master/docs/releasenotes/8.2.0.rst

And does it also belong elsewhere in docs? 
@hugovk  Where exactly, I am new in contributing to open source, 49/50 checks has already been passed. Does this mean #5289 has already been updated in the release notes?
No, the checks are unrelated. That PR doesn't have release notes. If you'd like to contribute them, you can edit https://github.com/python-pillow/Pillow/blob/master/docs/releasenotes/8.2.0.rst and create a new pull request. 
It's also apparent that https://pillow--5289.org.readthedocs.build/en/5289/reference/ImageShow.html doesn't mention IPythonViewer at all. If you'd like to fix that, you can modify https://github.com/python-pillow/Pillow/blob/master/docs/reference/ImageShow.rst.

Once your change is ready, you can go to https://github.com/radarhere/Pillow/compare/ipythonviewer...Kipkurui-mutai:master to create a pull request for #5289 specifically.

Resolving patch:
diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py
--- a/src/PIL/ImageShow.py
+++ b/src/PIL/ImageShow.py
@@ -225,6 +225,23 @@ def get_command_ex(self, file, title=None, **options):
     if shutil.which("xv"):
         register(XVViewer)
 
+
+class IPythonViewer(Viewer):
+    """The viewer for IPython frontends."""
+
+    def show_image(self, image, **options):
+        ipython_display(image)
+        return 1
+
+
+try:
+    from IPython.display import display as ipython_display
+except ImportError:
+    pass
+else:
+    register(IPythonViewer)
+
+
 if __name__ == "__main__":
 
     if len(sys.argv) < 2:


Test patch:
diff --git a/Tests/test_imageshow.py b/Tests/test_imageshow.py
--- a/Tests/test_imageshow.py
+++ b/Tests/test_imageshow.py
@@ -62,4 +62,20 @@ def test_viewer():
 
 def test_viewers():
     for viewer in ImageShow._viewers:
-        viewer.get_command("test.jpg")
+        try:
+            viewer.get_command("test.jpg")
+        except NotImplementedError:
+            pass
+
+
+def test_ipythonviewer():
+    pytest.importorskip("IPython", reason="IPython not installed")
+    for viewer in ImageShow._viewers:
+        if isinstance(viewer, ImageShow.IPythonViewer):
+            test_viewer = viewer
+            break
+    else:
+        assert False
+
+    im = hopper()
+    assert test_viewer.show(im) == 1