Getting Started with Python Image Processing: Get Started Quickly with Pillow

1. Pillow Introduction

In daily development, whether it is generating website thumbnails, making random verification codes, or cropping image sizes in batches, there is no need to resort to complex Photoshop scripts or third-party APIs - Python's Pillow library can easily do it.

Pillow is the modern branch of the old Python Imaging Library (PIL): while retaining PIL's simple API, it is fully compatible with Python 3, and has added new format support, performance optimization and other features. It is currently the most popular lightweight image processing tool in the Python ecosystem.

Core Highlights

  • Supports over 40 image formats (JPEG, PNG, BMP, GIF, TIFF, WebP, etc.)
  • Covers common image processing needs from basic to advanced
  • The code logic is clear and novice-friendly
  • Active community, stable version iterations

2. Quick installation

Standard pip installation

pip install pillow

Anaconda/Miniconda environment

conda install pillow

When installing as a normal user on Linux/macOS, it is recommended to add--userParameters to avoid modifying the system environment:

pip install --user pillow

3. Basic image operations

3.1 Open, view and save

This is the core first step of Pillow, and the code is almost as intuitive as "opening Notepad":

from PIL import Image

# 使用 with 语句自动管理文件句柄(推荐的最佳实践)
with Image.open("test.jpg") as im:
    # 打印图像元信息
    print(f"📄 格式: {im.format}")
    print(f"📐 尺寸(宽×高): {im.size[0]}×{im.size[1]}")
    print(f"🎨 色彩模式: {im.mode}")  # RGB / RGBA / L(灰度) / P(索引色) 等

    # 根据扩展名自动转换格式并保存
    im.save("output.png")

3.2 Resizing

Pillow provides two common methods:

  • thumbnail(): Reduce proportionally and modify the image in place to ensure that the image does not exceed the specified size.
  • resize(): Force stretching or scaling, returning a new image with fully controllable size.
with Image.open("test.jpg") as im:
    w, h = im.size  # 解包元组更方便

    # 方式1:生成宽不超过800的缩略图(保持纵横比)
    im.thumbnail((800, 800))
    im.save("thumbnail_800w.jpg", quality=95)  # JPEG 质量 1-100,推荐 85-95

    # 方式2:强制调整为 600×400(会变形,适合需要固定尺寸的场景)
    fixed_size_im = im.resize((600, 400))
    fixed_size_im.save("fixed_600x400.jpg")

💡 Note:thumbnail()will directly modify the original image, whileresize()Return a brand new image. If you need to use the original size later, please make a copy first.

3.3 Rotation and flipping

Rotation and flipping are both out-of-place operations that return a new image:

with Image.open("test.jpg") as im:
    # 逆时针旋转45度,expand=True 会自动扩大画布以容纳旋转后的图像
    rotated_45 = im.rotate(45, expand=True)

    # 水平 / 垂直翻转
    flip_h = im.transpose(Image.FLIP_LEFT_RIGHT)
    flip_v = im.transpose(Image.FLIP_TOP_BOTTOM)

    rotated_45.save("rotated_45_expanded.png")

4. Apply built-in filters with one click

Pillow has more than a dozen commonly used filters built-in, eliminating the need to write complex image processing algorithms by hand:

from PIL import Image, ImageFilter

with Image.open("test.jpg") as im:
    # 挑选几个常用滤镜演示
    filters = [
        ("blur", ImageFilter.BLUR),       # 模糊
        ("contour", ImageFilter.CONTOUR), # 轮廓提取
        ("emboss", ImageFilter.EMBOSS),   # 浮雕
        ("sharpen", ImageFilter.SHARPEN), # 锐化
    ]

    # 批量应用滤镜并保存
    for name, f in filters:
        filtered = im.filter(f)
        filtered.save(f"filtered_{name}.jpg")

5. Simple image drawing

combineImageDrawandImageFont, you can easily generate verification codes, text watermarks, simple charts, etc.

5.1 Basic graphics drawing

from PIL import Image, ImageDraw

# 创建一张白色 RGB 画布 (400×300)
canvas = Image.new("RGB", (400, 300), color="white")
draw = ImageDraw.Draw(canvas)

# 画红色对角线(坐标:x1, y1, x2, y2)
draw.line((0, 0, 400, 300), fill="red", width=3)

# 画绿色填充、蓝色边框的矩形(坐标:左, 上, 右, 下)
draw.rectangle((100, 100, 300, 200), fill="#00FF00", outline="#0000FF", width=2)

# 画蓝色圆形(实际上是宽高相等的椭圆)
draw.ellipse((150, 50, 250, 150), fill="blue")

canvas.save("basic_drawing.png")

5.2 Useful gadget: generate 4-digit verification code

The verification code logic of many websites can be implemented using this simplified version:

from PIL import Image, ImageDraw, ImageFont, ImageFilter
import random

def gen_captcha(width=240, height=60, char_len=4):
    # 1. 创建浅灰色背景画布
    bg_color = (240, 240, 240)
    img = Image.new("RGB", (width, height), bg_color)
    draw = ImageDraw.Draw(img)

    # 2. 加载字体(找不到系统字体时会回退到默认位图字体)
    try:
        # Windows 路径示例:C:/Windows/Fonts/arial.ttf
        # macOS 路径示例:/Library/Fonts/Arial.ttf
        # Linux 路径示例:/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf
        font = ImageFont.truetype("arial.ttf", size=40)
    except IOError:
        font = ImageFont.load_default()

    # 3. 生成随机大写字母
    captcha_text = "".join([chr(random.randint(65, 90)) for _ in range(char_len)])

    # 4. 计算文本尺寸并居中绘制(每个字母带轻微随机偏移)
    #    使用 textbbox 兼容 Pillow 8.0+
    bbox = draw.textbbox((0, 0), captcha_text, font=font)
    text_w, text_h = bbox[2] - bbox[0], bbox[3] - bbox[1]
    start_x = (width - text_w) // 2
    start_y = (height - text_h) // 2

    for i, char in enumerate(captcha_text):
        x_offset = random.randint(-5, 5)
        y_offset = random.randint(-3, 3)
        draw.text(
            (start_x + i * (text_w // char_len) + x_offset, start_y + y_offset),
            char,
            font=font,
            fill=(random.randint(0, 100), random.randint(0, 100), random.randint(0, 100))
        )

    # 5. 轻微模糊,增加识别难度
    img = img.filter(ImageFilter.GaussianBlur(radius=1.2))

    return img, captcha_text

# 调用示例
if __name__ == "__main__":
    captcha_img, code = gen_captcha()
    captcha_img.save("my_captcha.jpg")
    print(f"✅ 验证码已生成,内容为:{code}")

6. Advanced small functions

6.1 Image synthesis with transparency

Overlay a PNG watermark with a transparent channel onto a photo, often used to add branding in batches:

from PIL import Image

with Image.open("photo.jpg") as bg, Image.open("watermark.png") as wm:
    # 确保水印为 RGBA 模式(拥有透明通道)
    if wm.mode != "RGBA":
        wm = wm.convert("RGBA")

    # 将水印缩小为照片宽度的 1/4,放置在右下角
    bg_w, bg_h = bg.size
    wm.thumbnail((bg_w // 4, bg_h // 4))

    # 计算右下角坐标(留出 20px 边距)
    paste_x = bg_w - wm.size[0] - 20
    paste_y = bg_h - wm.size[1] - 20

    # 带透明度叠加:第三个参数传入水印自身,利用其 alpha 通道遮罩
    bg.paste(wm, (paste_x, paste_y), wm)
    bg.save("photo_with_watermark.jpg")

7. Quick FAQ

  1. System font loading failed Replace the font path with the real absolute path of the corresponding system, or use it directlyImageFont.load_default()Loads the default bitmap font.

  2. An error occurs when RGBA images are saved directly as JPEG The JPEG format does not support transparency and needs to be converted to RGB mode first:

    if im.mode == "RGBA":
        im = im.convert("RGB")
  3. Memory overflow when processing large images priority usethumbnail()Reduce the image proportionally to avoid direct calls to oversized imagesresize()

8. Learning resources

Through this tutorial, you have mastered 80% of Pillow's core usage scenarios, and the remaining details can be explored on demand according to the official documentation!