mountwebs
mountwebs

Reputation: 13

How to draw a transparent ellipse in Python with Pillow without outline

I am trying to draw multiple transparent ellipses with Pillow, and I want to draw them without outlines. I can't seem to make it work without outlines.

Here is some test code:

from PIL import Image, ImageDraw
w,h = 100,100
img = Image.new('RGB', (w,h),(255,255,255))
drw = ImageDraw.Draw(img,"RGBA")
drw.polygon([(50, 0), (100, 100), (0, 100)], (255, 0, 0, 125))
drw.polygon([(50,100), (100, 0), (0, 0)], (0, 255, 0, 125))
drw.ellipse([(40, 40), (w - 10, h - 10)], fill=(0,0,255,125), outline=None)
img.save('out.png', 'PNG')

(from here, with some modifications)

Output

Only the ellipse gets an outline. Why? How can I avoid this?

Upvotes: 1

Views: 3179

Answers (1)

HansHirse
HansHirse

Reputation: 18925

After playing around with some codes, looking at the documentation and some source codes, I'm quite sure, that most likely there's some issue with the functions like arc, chord, ellipse, that all share the same code under the hood.

I created the following example:

from matplotlib import pyplot as plt
from PIL import Image, ImageDraw


def example(outline_alpha=None, width=None):
    if outline_alpha is None:
        outline = None
    else:
        outline = (255, 255, 0, outline_alpha)
    if width is None:
        width = 0
    img = Image.new('RGB', (100, 100), (255, 255, 255))
    drw = ImageDraw.Draw(img, 'RGBA')
    drw.line([(0, 40), (100, 40)], (0, 0, 0, 255))
    drw.line([(50, 100), (100, 0)], (0, 0, 0, 255))
    drw.polygon([(50, 100), (100, 0), (0, 0)], (0, 255, 0, 128), outline)
    drw.ellipse([(40, 40), (90, 90)], (0, 0, 255, 128), outline, width)
    return img


plt.figure(1, figsize=(15, 10))
plt.subplot(2, 3, 1), plt.imshow(example()), plt.title('No outlines specified, width = 0')
plt.subplot(2, 3, 2), plt.imshow(example(255)), plt.title('Opaque outlines specified, width = 0')
plt.subplot(2, 3, 3), plt.imshow(example(128)), plt.title('Semi-transparent outlines specified, width = 0')
plt.subplot(2, 3, 4), plt.imshow(example(None, 5)), plt.title('No outlines specified, width = 5')
plt.subplot(2, 3, 5), plt.imshow(example(255, 5)), plt.title('Opaque outlines specified, width = 5')
plt.subplot(2, 3, 6), plt.imshow(example(20, 5)), plt.title('Semi-transparent outlines specified, width = 5')
plt.tight_layout()
plt.show()

The output is the following:

Output

Looking at the polygon, if no outline is specified (top left image), we see that the black line is visible, which is one of the polygon's borders. Specifying an opaque outline (top center image), the black line's no longer visible. Setting a semi-transparent outline (top right image) reveals, that the outline is identical to the polygon's border.

Now, the same for the ellipse: If no outline is set (top left), an outline is shown nevertheless, most likely the same color as used for the fill parameter, but without incorporating an alpha value. Setting an opaque outline (top center) "overwrites" the unexpected existent outline, but when setting a semi-transparent outline, we see that the unexpected outline is still there.

This effect becomes even more obvious, when setting width > 1 in ellipse, see the bottom row. The unexpected outline still seems to have width = 1, whereas the explicitly set outline has width = 5.

Again, I'm quite sure, that this behavior isn't intended – and I will open an issue in their GitHub issue tracker. EDIT: I just opened this issue. ANOTHER EDIT: It's fixed.

Hope that helps – somehow...

Upvotes: 1

Related Questions