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

Question:

I got a square logo and I need to round_corner it, searched for a while and got the follow code “working”:

def round_corner_jpg(image, radius):
    """generate round corner for image"""
    mask = Image.new('RGB', image.size)
    #mask = Image.new('RGB', (image.size[0] - radius, image.size[1] - radius))
    #mask = Image.new('L', image.size, 255)
    draw = aggdraw.Draw(mask)
    brush = aggdraw.Brush('black')
    width, height = mask.size
    draw.rectangle((0,0,width,height), aggdraw.Brush('white'))
    #upper-left corner
    draw.pieslice((0,0,radius*2, radius*2), 90, 180, None, brush)
    #upper-right corner
    draw.pieslice((width - radius*2, 0, width, radius*2), 0, 90, None, brush)
    #bottom-left corner
    draw.pieslice((0, height - radius * 2, radius*2, height),180, 270, None, brush)
    #bottom-right corner
    draw.pieslice((width - radius * 2, height - radius * 2, width, height), 270, 360, None, brush)
    #center rectangle
    draw.rectangle((radius, radius, width - radius, height - radius), brush)
    #four edge rectangle
    draw.rectangle((radius, 0, width - radius, radius), brush)
    draw.rectangle((0, radius, radius, height-radius), brush)
    draw.rectangle((radius, height-radius, width-radius, height), brush)
    draw.rectangle((width-radius, radius, width, height-radius), brush)
    draw.flush()
    del draw
    return ImageChops.add(mask, image)

then I saved the returned image object,however it has white background in the corner
like this
How can i get rid of the white background or make it invisible?
Thanks in advance~

EDIT:
here is the code by fraxel,thanks~

def add_corners(im, rad):
    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


if __name__ == '__main__':
    im = Image.open('1.jpg')
    im = add_corners(im, 100)
    im.save('out.png')`

I am so sorry..I need the image shape to be ellipse not rectangle,I.E. the write stuff off the pic,and @fraxel, I still can see the white corner in the pic you processed for me

Asked By: bdictator

||

Answers:

Have you tried something like image.putalpha(mask) to replace the image’s alpha channel with the mask? This seems like it should do what you want. mask might have to be in ‘L’ mode for this to work correctly, and image should probaby be ‘RGBA’, but might be automatically converted for you.

The top answer here provides some good examples:
How do I generate circular thumbnails with PIL?

Your mask image looks fine, but I think you want to swap ‘white’ and ‘black’, so you have a white rounded rectangle exactly the shape you want your final image to be, on a black background. You will probably also need to use the ‘L’ mode (greyscale) one.

Once you have this image, you can replace the return ImageChops.add(mask, image) by image.putalpha(mask); return image and this should cause the image to be transparent in only the black areas of the mask.

You might need to convert the image first with image.convert('RGBA') but I think this is unnecessary in later versions of PIL, it does it automatically.

Something like: (sorry can’t test this right now)

def round_corner_jpg(image, radius):
    """generate round corner for image"""
    mask = Image.new('L', image.size) # filled with black by default
    draw = aggdraw.Draw(mask)
    brush = aggdraw.Brush('white')
    width, height = mask.size
    #upper-left corner
    draw.pieslice((0,0,radius*2, radius*2), 90, 180, None, brush)
    #upper-right corner
    draw.pieslice((width - radius*2, 0, width, radius*2), 0, 90, None, brush)
    #bottom-left corner
    draw.pieslice((0, height - radius * 2, radius*2, height),180, 270, None, brush)
    #bottom-right corner
    draw.pieslice((width - radius * 2, height - radius * 2, width, height), 270, 360, None, brush)
    #center rectangle
    draw.rectangle((radius, radius, width - radius, height - radius), brush)
    #four edge rectangle
    draw.rectangle((radius, 0, width - radius, radius), brush)
    draw.rectangle((0, radius, radius, height-radius), brush)
    draw.rectangle((radius, height-radius, width-radius, height), brush)
    draw.rectangle((width-radius, radius, width, height-radius), brush)
    draw.flush()
    image = image.convert('RGBA')
    image.putalpha(mask)
    return image
Answered By: mesilliac

First off, make sure you are saving your image in a format that supports transparency. PNG does, JPG does not… Below is some pretty nice code that will add transparent corners. It works like this:

  1. Draws a circle with radius, rad, using draw.ellipse()
  2. Create an image for the alpha channel the same size as your image
  3. Chop our circle into four pieces (the rounded corners), and place them in the correct corners of the alpha image
  4. Put the alpha channel into your image using putalpha()
  5. Save as a png, thus preserving transparency.

Here is the code:

import Image, ImageDraw

def add_corners(im, rad):
    circle = Image.new('L', (rad * 2, rad * 2), 0)
    draw = ImageDraw.Draw(circle)
    draw.ellipse((0, 0, rad * 2 - 1, rad * 2 - 1), fill=255)
    alpha = Image.new('L', im.size, 255)
    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

im = Image.open('tiger.jpg')
im = add_corners(im, 100)
im.save('tiger.png')

example curved edge tiger:

enter image description here

here is your image, processed with this code, giving transparent corners:

enter image description here

Answered By: fraxel

Here is another option using NumPy only:

import numpy as np
import matplotlib.pyplot as plt

test_img = plt.imread("logo.png") # reads rgba image

radius = 155
shape = (2 * radius, 2 * radius)
x, y = np.indices(shape)
circ = (x - radius) ** 2 + (y - radius) ** 2 <= radius**2
array = np.zeros(shape)
array[circ] = 255
array = np.insert(array, obj=radius, values=np.full((test_img.shape[0] - 2 * radius, array.shape[1]), 255),axis=0)
array = np.insert(array, obj=radius, values=np.full((test_img.shape[1] - 2 * radius, array.shape[0]), 255), axis=1)

plt.imshow(array)
plt.axis("off")
plt.show()

test_img[:, :, 3] = array
plt.imshow(test_img)
plt.axis("off")

enter image description here
enter image description here

Answered By: Kolibril