note.nkmk.me

Generate square or circular thumbnail images with Python, Pillow

Date: 2019-05-14 / tags: Python, Pillow, Image Processing

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. Here I define my own function as an example.

The following contents will be described.

  • How to make rectangular image square
    • Crop a square from a rectangular image
    • Add margins to make rectangle square
  • Crop a square image into a circle
    • Make the background a solid color
    • Make the background transparent
  • Sample code for batch processing

Please refer to 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 to be used in the following example, and decide the width (= height) of the thumbnail image you want to finally obtain.

import os
import glob

from PIL import Image, ImageDraw, ImageFilter

im = Image.open('data/src/lena.jpg')
thumb_width = 150

lena

Sponsored Link

How to make 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 margins to make 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))
source: imagelib.py

Use as follows.

im_thumb = crop_center(im, thumb_width, thumb_width)
im_thumb.save('data/dst/lena_thumbnail_center_square.jpg', quality=95)

Pillow thumbnail center square

Instead of cropping the area of the thumbnail size, it is possible to 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))
source: imagelib.py

Use as follows. After making the rectangular image into a square, it is reduced 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/lena_thumbnail_max_square.jpg', quality=95)

Pillow thumbnail max square

Add margins to make rectangle square

If you want to keep the entire original rectangular image, add margins 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 a margin so that it will 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
source: imagelib.py

Use as follows. 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/lena_thumbnail_expand.jpg', quality=95)

Pillow thumbnail expand square

Crop a square image into a circle

If you want to generate a circular thumbnail image, crop from square to circle.

There are two ways, one is to make the background cropped into a circle a solid color (white, black etc), and the other is to make it transparent (to make it 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 post.

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)
source: imagelib.py

Use as follows.

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/lena_thumbnail_mask_circle_solid.jpg', quality=95)

Pillow thumbnail circle solid

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
source: imagelib.py

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/lena_thumbnail_mask_circle_transparent.png')

Pillow thumbnail circle transparent

Sponsored Link

Sample code for batch processing

Create thumbnail images collectively from image files in any directory (folder).

Generate thumbnail images of image files in src_dir and save them in dst_dir.

src_dir = 'data/src'
dst_dir = 'data/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)
Sponsored Link
Share

Related Categories

Related Posts