Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for Pillow Image Object in toga #2154

Closed
wants to merge 11 commits into from
45 changes: 45 additions & 0 deletions changes/2142.feature.rst
dr-gavitron marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
Added Pillow support in toga
============================
toga.Image
----------
`toga.Image` can now take Pillow Image Object. simply set pil_image parameter to the Pillow Object
code-block::python
from PIL import Image as PIL_Image
import toga
myimg = PIL_Image.open("path/to/image.png")
image = toga.Image(pil_image=myimg)

Also to convert a `toga.Image` object as Pillow Object
code-block::python
pil_image = image.as_format(PIL_Image.Image)
#or
pil_image = image.as_format(format=PIL_Image.Image)

toga.ImageView
--------------
pass a Pillow Object in `toga.ImageView` and it will show the image
code-block::python
from PIL import Image as PIL_Image
import toga
myimg = PIL_Image.open("path/to/image.png")
imageview = toga.ImageView(myimg)

Aslo to extract image as Pillow Object from the `imageview`
code-block::python
pil_img = imageview.as_image(PIL_Image.Image)
#or
pil_img = imageview.as_image(format=PIL_Image.Image)

toga.Canvas
-----------
`Canvas.as_image` now can return Pillow object if PIL.Image.Image set in the format parameter
code-block::python
from PIL import Image as PIL_Image
pil_img = canvas.as_image(PIL_Image.Image)
#or
pil_img = canvas.as_image(format=PIL_Image.Image)

When conversion format is `None`
------------------------------
Also when `format` is `None` in `Image.as_format` or `ImageView.as_image` or `Canvas.as_image`
it will return a `toga.Image` object by default
20 changes: 20 additions & 0 deletions core/tests/test_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,23 @@ def test_image_save():

image.save(save_path)
assert_action_performed_with(image, "save", path=save_path)

def test_pil_support():
from PIL import Image as PIL_Image

pil_img = PIL_Image.open("resources/toga.png")
toga_img = toga.Image("resources/toga.png")
toga_img_from_pil_img = toga.Image(pil_image = pil_img)
dr-gavitron marked this conversation as resolved.
Show resolved Hide resolved

assert toga_img.width == toga_img_from_pil_img.width, "PIL support is faulty"
dr-gavitron marked this conversation as resolved.
Show resolved Hide resolved
assert toga_img.height == toga_img_from_pil_img.height, "PIL support is faulty"

pil_img2 = toga_img_from_pil_img.as_format(PIL_Image.Image)

assert type(pil_img2) == type(pil_img), "Image.as_format(PIL_Image.Image) is faulty"
assert pil_img2.size == pil_img.size, "Image.as_format(PIL_Image.Image) is faulty"

def test_as_format_none():
img = toga.Image("resources/toga.png")
img2 = img.as_format()
assert img == img2, "Image.as_format should return self when nothing is provided as arg, but failed"
dr-gavitron marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions core/tests/widgets/canvas/test_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ def test_as_image(widget):
assert image is not None
assert_action_performed(widget, "get image data")

from PIL import Image as PIL_Image
image = widget.as_image(format=PIL_Image.Image)
assert type(image) == PIL_Image.Image
assert_action_performed(widget, "get image data as Pillow Image Object")
dr-gavitron marked this conversation as resolved.
Show resolved Hide resolved


def test_deprecated_drawing_operations(widget):
"""Deprecated simple drawing operations raise a warning"""
Expand Down
18 changes: 18 additions & 0 deletions core/tests/widgets/test_imageview.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,21 @@ def test_rehint_empty_image(params):
assert width == 0
assert height == 0
assert aspect_ratio is None

def test_pil_support():
from PIL import Image as PIL_Image
pil_img = PIL_Image.open("resources/toga.png")
toga_img = PIL_Image.open("resources/toga.png")

imageview = toga.ImageView(pil_img)
assert type(imageview.image) == toga.Image, "Internal conversion from PIL_Image.Image to toga.Image is faulty"
assert (imageview.image.width, imageview.image.height) == (toga_img.width,toga_img.height) == pil_img.size, "PIL support for imageview is faulty"
dr-gavitron marked this conversation as resolved.
Show resolved Hide resolved

pil_img2 = imageview.as_image(PIL_Image.Image)
assert pil_img2.size == pil_img2.size, "ImageView.as_image(PIL_Image.Image) is faulty"

def test_as_image_format_is_none():
img = toga.Image("resources/toga.png")
imageview = toga.ImageView(image=img)
img2 = imageview.as_image()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with Image, this should be an argument error.

assert (img2.width, img2.height) == (img.width, img.height), "ImageView.as_image should return toga.Image when nothing is provided as parameter, but failed"