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

Function for Rounded Rectangle #4765

Closed
Luc1412 opened this issue Jul 7, 2020 · 8 comments · Fixed by #5208
Closed

Function for Rounded Rectangle #4765

Luc1412 opened this issue Jul 7, 2020 · 8 comments · Fixed by #5208

Comments

@Luc1412
Copy link

Luc1412 commented Jul 7, 2020

Feature Request

I got a feature request for the ImageDraw module.
For more modern design, it's very useful to create a rectangle with rounded corners. Currently, it requires a higher effort to create such a rounded rectangle.

My Code:

def create_rounded_rectangle_mask(size, radius, alpha=255):
    factor = 5  # Factor to increase the image size that I can later antialiaze the corners
    radius = radius * factor
    image = Image.new('RGBA', (size[0] * factor, size[1] * factor), (0, 0, 0, 0))

    # create corner
    corner = Image.new('RGBA', (radius, radius), (0, 0, 0, 0))
    draw = ImageDraw.Draw(corner)
    # added the fill = .. you only drew a line, no fill
    draw.pieslice((0, 0, radius * 2, radius * 2), 180, 270, fill=(50, 50, 50, alpha + 55))

    # max_x, max_y
    mx, my = (size[0] * factor, size[1] * factor)

    # paste corner rotated as needed
    # use corners alpha channel as mask
    image.paste(corner, (0, 0), corner)
    image.paste(corner.rotate(90), (0, my - radius), corner.rotate(90))
    image.paste(corner.rotate(180), (mx - radius, my - radius), corner.rotate(180))
    image.paste(corner.rotate(270), (mx - radius, 0), corner.rotate(270))

    # draw both inner rects
    draw = ImageDraw.Draw(image)
    draw.rectangle([(radius, 0), (mx - radius, my)], fill=(50, 50, 50, alpha))
    draw.rectangle([(0, radius), (mx, my - radius)], fill=(50, 50, 50, alpha))
    image = image.resize(size, Image.ANTIALIAS)  # Smooth the corners

    return image

This mask will be used to paste with a normal rectangle.

@radarhere
Copy link
Member

So to be clear, you can already achieve the desired outcome with Pillow, you're just suggesting that this code become a part of Pillow?

@Luc1412
Copy link
Author

Luc1412 commented Jul 9, 2020

Yeah I think there will be several ppl. which might use such function. I also found those functions in other image libraries (other languages) so might be worth considering to implement. My implementation also won't be the best, so you or other ppl. find ways to improve it.

@radarhere
Copy link
Member

I don't understand what you were trying to achieve with the alpha argument.
Using your code, 255 is normal.

create_rounded_rectangle_mask((200, 100), 30, 255).show()

255

But 127 and 0 just don't seem like they would be helpful.

create_rounded_rectangle_mask((200, 100), 30, 127).show()

127

create_rounded_rectangle_mask((200, 100), 30, 0).show()

0

@radarhere
Copy link
Member

I've created PR #5208. See what you think

@Luc1412
Copy link
Author

Luc1412 commented Jan 15, 2021

I don't understand what you were trying to achieve with the alpha argument.
Using your code, 255 is normal.

@radarhere Am not fully aware of how to use this value right. I encountered an issue if I create a rounded rectangle with alpha lower than 255.
Eg. I created a translucent bar background with Alpha set to 30:
DiscordPTB_kGBwbpMnIK

This happens when you not adjusting alpha:
DiscordPTB_i9mppapcT4

My version of just using the same alpha as the image is imperfect too. If you zoom in, you'll see that the corners got a different alpha.

@radarhere
Copy link
Member

Ok, sure. Using my PR, you should be able to just set fill to a color with an alpha value.

from PIL import Image, ImageDraw
im = Image.new("RGB", (500, 100), (0, 0, 100))
draw = ImageDraw.Draw(im, "RGBA")
draw.rounded_rectangle((20, 20, 480, 80), 30, fill=(255,255,255,50))
draw.rounded_rectangle((20, 20, 280, 80), 30, fill=(255,0,0,100))
im.show()

out

@Luc1412
Copy link
Author

Luc1412 commented Jan 16, 2021

@radarhere Sounds great! Looking forward to use this function in a future version.
But I think it might be helpful to either implement corner smoothing or provide help how to do it in docs.

@radarhere
Copy link
Member

Your idea of using antialiasing to create a smoother result doesn't purely apply to rounded rectangles - it might equally be applied to other shapes.

While I acknowledge that it might be useful, I'm reluctant to officially endorse it as a strategy - if there is a need for it, my personal feeling is that it is more of a workaround than a proper solution. Feel free to create a PR yourself, or if you'd like to continue talking about smoothing, would you be able to open a new issue? It would be nice to keep this issue specifically about rounded rectangles.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants