PIL round edges and add border
Asked Answered
V

1

5

I'm currently using this method to round the edges on images for my users:

def _add_corners(self, im, rad=100):
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
    alpha = Image.new('L', im.size, "white")
    w, h = im.size
    alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
    alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
    alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
    alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
    im.putalpha(alpha)
    return im

The rounding works perfectly fine and i'm happy with it. However, I would like to also draw a border around the image within the constraints of the edges. Most of what I'm reading online shows how to draw border on the image itself (not the rounded border i'm doing). Is there a way to do that? I have read the below:

how to round_corner a logo without white background(transparent?) on it using pil?

Python Imaging Library (PIL) Drawing--Rounded rectangle with gradient

Any way to make nice antialiased round corners for images in python?

Vivi answered 23/7, 2016 at 7:23 Comment(3)
You could create a function that draws the four straight lines and the four corners separately, the latter one using the method PIL.ImageDraw.Draw.arc(xy, start, end, fill=None).Ambages
I did something that may be useful here... https://mcmap.net/q/357456/-how-to-add-a-round-border-around-an-imageHals
Nice solution for adding edges! To make the edges the same size (bottom right is the smallest), you need to add offsets because the radius is added to an 1px wide axis. So make the circle-mask 1px wider and add offsets when cropping, e.g. for bottom right: alpha.paste(circle.crop((rad+1, rad+1, rad*2+1, rad*2+1)), (w-rad, h-rad)). Another note: PIL version 8.2.0 added the method rounded_rectanglewhich should make this even easier.Mcchesney
A
0

This is a rather late response, but you can essentially use the same method twice, once applied to your image and then again to a new, slightly larger background image. You then simply paste the foreground onto the background. I've updated the function you provided to do so below:

def add_corners(im, rad=50, bg=True, bgCol='white', bgPix=5):
    bg_im = Image.new('RGB', tuple(x+(bgPix*2) for x in im.size), bgCol)
    ims = [im if not bg else im, bg_im]
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2, rad * 2), fill=255)
    for i in ims:
        alpha = Image.new('L', i.size, 'white')
        w, h = i.size
        alpha.paste(circle.crop((0, 0, rad, rad)), (0, 0))
        alpha.paste(circle.crop((0, rad, rad, rad * 2)), (0, h - rad))
        alpha.paste(circle.crop((rad, 0, rad * 2, rad)), (w - rad, 0))
        alpha.paste(circle.crop((rad, rad, rad * 2, rad * 2)), (w - rad, h - rad))
        i.putalpha(alpha)
    bg_im.paste(im, (bgPix, bgPix), im)
    return im if not bg else bg_im
Anallise answered 12/2, 2023 at 16:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.