Generate square or circular thumbnail images with Python, Pillow
You can create square or circular thumbnail images using Python's image processing library Pillow (PIL).
Although there is a method called thumbnail()
in the Pillow's Image
module, it just resizes the image to fit within the specified size.
This article describes the following contents.
- How to make a rectangular image square
- Crop a square from a rectangular image
- Add padding to make a rectangle square
- Crop a square image into a circle
- Make the background a solid color
- Make the background transparent
- Sample code for batch processing
See the following articles for the installation and basic usage of Pillow (PIL).
Import Image
, ImageDraw
, and ImageFilter
from PIL
. ImageDraw
and ImageFilter
are used to draw and process circles. When creating a square thumbnail image, they may be omitted.
For batch processing, import os
and glob
.
Read the image used in the following examples, and decide the width (= height) of the thumbnail image you want to obtain finally.
import os
import glob
from PIL import Image, ImageDraw, ImageFilter
im = Image.open('data/src/astronaut_rect.bmp')
thumb_width = 200
How to make a rectangular image square
Because resizing a rectangular image to a square with resize()
of Image
module changes the aspect ratio, use one of the following methods.
- Crop a square from a rectangular image
- Add padding to make a rectangle square
Crop a square from a rectangular image
Crop an area of an image with crop()
.
Define a function to crop the central area of the image.
def crop_center(pil_img, crop_width, crop_height):
img_width, img_height = pil_img.size
return pil_img.crop(((img_width - crop_width) // 2,
(img_height - crop_height) // 2,
(img_width + crop_width) // 2,
(img_height + crop_height) // 2))
Usage example:
im_thumb = crop_center(im, thumb_width, thumb_width)
im_thumb.save('data/dst/astronaut_thumbnail_center_square.jpg', quality=95)
Instead of cropping the area of the thumbnail size, you can crop the largest size square (= rectangular short side square) and then resize it.
Define a function to crop the largest sized square. It uses a function to crop the center area of the image.
def crop_max_square(pil_img):
return crop_center(pil_img, min(pil_img.size), min(pil_img.size))
Usage example:
After making the rectangular image into a square, it is resized by resize()
to the size of the desired thumbnail image.
im_thumb = crop_max_square(im).resize((thumb_width, thumb_width), Image.LANCZOS)
im_thumb.save('data/dst/astronaut_thumbnail_max_square.jpg', quality=95)
Add padding to make a rectangle square
If you want to keep the entire original rectangular image, add padding at the top, bottom, left, or right to make it square.
new()
can be used to generate a solid image and paste it with paste()
.
Define a function that adds padding to eventually become a square with the size of the long side of the rectangle.
def expand2square(pil_img, background_color):
width, height = pil_img.size
if width == height:
return pil_img
elif width > height:
result = Image.new(pil_img.mode, (width, width), background_color)
result.paste(pil_img, (0, (width - height) // 2))
return result
else:
result = Image.new(pil_img.mode, (height, height), background_color)
result.paste(pil_img, ((height - width) // 2, 0))
return result
Usage example:
After making the rectangular image into a square, it is reduced by resize()
to the size of the desired thumbnail image.
im_thumb = expand2square(im, (0, 0, 0)).resize((thumb_width, thumb_width), Image.LANCZOS)
im_thumb.save('data/dst/astronaut_thumbnail_expand.jpg', quality=95)
Crop a square image into a circle
If you want to generate a circular thumbnail image, you need to crop a square image into a circle.
There are two ways:
- make the background a solid color (white, black, etc.)
- make the background transparent (= make transparent png)
Make the background a solid color
Use composite()
to composite two images according to the mask image.
Draw a circle and use it as a mask image. For details on drawing, see the following article.
Create a single color plain image of the desired background color with new()
and composite it with the square image with a circular mask.
The border is smoothed by blurring the mask image with ImageFilter
. Since the area of the circle spreads when it blurs, it is necessary to draw a smaller circle first.
Define the following function. Specify the background color background_color
, the size of the blur blur_radius
, and the offset offset
. No blur with blur_radius=0
.
def mask_circle_solid(pil_img, background_color, blur_radius, offset=0):
background = Image.new(pil_img.mode, pil_img.size, background_color)
offset = blur_radius * 2 + offset
mask = Image.new("L", pil_img.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((offset, offset, pil_img.size[0] - offset, pil_img.size[1] - offset), fill=255)
mask = mask.filter(ImageFilter.GaussianBlur(blur_radius))
return Image.composite(pil_img, background, mask)
Usage example:
im_square = crop_max_square(im).resize((thumb_width, thumb_width), Image.LANCZOS)
im_thumb = mask_circle_solid(im_square, (0, 0, 0), 4)
im_thumb.save('data/dst/astronaut_thumbnail_mask_circle_solid.jpg', quality=95)
Make the background transparent
Use putalpha()
, which adds an alpha channel to the image.
The flow is the same as when using a single color plain background.
def mask_circle_transparent(pil_img, blur_radius, offset=0):
offset = blur_radius * 2 + offset
mask = Image.new("L", pil_img.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((offset, offset, pil_img.size[0] - offset, pil_img.size[1] - offset), fill=255)
mask = mask.filter(ImageFilter.GaussianBlur(blur_radius))
result = pil_img.copy()
result.putalpha(mask)
return result
Transparent images are saved with png
.
im_square = crop_max_square(im).resize((thumb_width, thumb_width), Image.LANCZOS)
im_thumb = mask_circle_transparent(im_square, 4)
im_thumb.save('data/dst/astronaut_thumbnail_mask_circle_transparent.png')
Sample code for batch processing
Create thumbnail images collectively from image files in any directory (folder).
It can be done in the same way as batch resizing.
Generate thumbnail images of image files in src_dir
and save them in dst_dir
.
src_dir = 'data/temp/src'
dst_dir = 'data/temp/dst'
files = glob.glob(os.path.join(src_dir, '*.jpg'))
for f in files:
im = Image.open(f)
im_thumb = crop_max_square(im).resize((thumb_width, thumb_width), Image.LANCZOS)
ftitle, fext = os.path.splitext(os.path.basename(f))
im_thumb.save(os.path.join(dst_dir, ftitle + '_thumbnail' + fext), quality=95)