How do I generate circular image thumbnails using PIL? The space outside the circle should be transparent.
Snippets would be highly appreciated, thank you in advance.
How do I generate circular image thumbnails using PIL? The space outside the circle should be transparent.
Snippets would be highly appreciated, thank you in advance.
The easiest way to do it is by using masks. Create a black and white mask with any shape you want. And use putalpha
to put that shape as an alpha layer:
from PIL import Image, ImageOps
mask = Image.open('mask.png').convert('L')
im = Image.open('image.png')
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.putalpha(mask)
output.save('output.png')
Here is the mask I used:
If you want the thumbnail size to be variable you can use ImageDraw
and draw the mask:
from PIL import Image, ImageOps, ImageDraw
size = (128, 128)
mask = Image.new('L', size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + size, fill=255)
im = Image.open('image.jpg')
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.putalpha(mask)
output.save('output.png')
If you want the output in GIF then you need to use the paste function instead of putalpha
:
from PIL import Image, ImageOps, ImageDraw
size = (128, 128)
mask = Image.new('L', size, 255)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + size, fill=0)
im = Image.open('image.jpg')
output = ImageOps.fit(im, mask.size, centering=(0.5, 0.5))
output.paste(0, mask=mask)
output.convert('P', palette=Image.ADAPTIVE)
output.save('output.gif', transparency=0)
Note that I did the following changes:
Please note: There is a big issue with this approach. If the GIF image contained black parts, all of them will become transparent as well. You can work around this by choosing another color for the transparency. I would strongly advise you to use PNG format for this. But if you can't then that is the best you could do.
I would like to add to the already accepted answer a solution to antialias the resulting circle, the trick is to produce a bigger mask and then scale it down using an ANTIALIAS filter: here is the code
from PIL import Image, ImageOps, ImageDraw
im = Image.open('image.jpg')
bigsize = (im.size[0] * 3, im.size[1] * 3)
mask = Image.new('L', bigsize, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0) + bigsize, fill=255)
mask = mask.resize(im.size, Image.ANTIALIAS)
im.putalpha(mask)
this produces a far better result in my opinion.
resample=Image.ANTIALIAS
. –
Arv Slight modification on @DRC's solution to also support images which already have transparency. He sets the alpha channel to 0 (invisible) outside the circle and to 255 inside (opaque), so I use darker
which takes the min of the mask and the original alpha channel (which can be anywhere betwen 0-255) :-)
from PIL import Image, ImageChops, ImageDraw
def crop_to_circle(im):
bigsize = (im.size[0] * 3, im.size[1] * 3)
mask = Image.new('L', bigsize, 0)
ImageDraw.Draw(mask).ellipse((0, 0) + bigsize, fill=255)
mask = mask.resize(im.size, Image.ANTIALIAS)
mask = ImageChops.darker(mask, im.split()[-1])
im.putalpha(mask)
im = Image.open('0.png').convert('RGBA')
crop_to_circle(im)
im.save('cropped.png')
Image.paste()
and add a mask –
Whipple Thank you very much. I was looking for hours and your idea does the trick.
Together with this other script from there. PIL round edges and add border it works perfectly for me.
from PIL import Image
from PIL import ImageDraw, ImageChops
def add_corners( 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))
alpha = ImageChops.darker(alpha, im.split()[-1])
im.putalpha(alpha)
return im
im = Image.open ('AceOfSpades.png').convert('RGBA')
im = add_corners (im, 24)
im.show()
im.save("perfect.png")
from PIL import Image, ImageDraw, ImageFont
import requests
import io
# get a random image
image_response = requests.get('https://source.unsplash.com/random/300x200')
image = Image.open(io.BytesIO(image_response.content))
# decorate the image
padding = 80
border_radius = 15
# get container size
container_size = (image.width + padding, image.height + padding *3)
# create a new image
container = Image.new('RGBA', container_size, (0, 0, 0, 0))
# create a draw object
draw = ImageDraw.Draw(container)
# draw a rounded rectangle
draw.rounded_rectangle((0, 0 ) + container_size, radius=border_radius, fill="green", outline=(0, 0, 0, 0))
# paste image in container at the center
container_width, container_height = container.size
image_width, image_height = image.size
x = (container_width - image_width) // 2
y = 30 # or any desired y-coordinate
container.paste(image,(x,y))
# add text
draw = ImageDraw.Draw(container)
text = "This is your #7 drive with RHA."
font = ImageFont.truetype("arial.ttf", 15)
# get text box size
text_box = draw.textbbox((0, 0), text, font=font)
text_width, text_height = (text_box[2] - text_box[0]), (text_box[3] - text_box[1])
text_position = ((container.width - text_width) / 2, image.height + padding*2)
draw.text(text_position, text, font=font, fill="white", align='center')
# save the image
container.save('rounded_rect.png')
© 2022 - 2024 — McMap. All rights reserved.