Pillow ImagePath 模块

下面给你一个 Pillow(PIL Fork)中 ImagePath 模块 的完整入门指南,包含路径绘制、矢量图形生成、多边形填充、坐标变换、SVG 路径解析、性能优化及高级应用。
(基于 Pillow ≥ 9.0,Python 3.8+)


1. 安装 Pillow

pip install --upgrade pillow

2. 基本导入

from PIL import Image, ImageDraw, ImagePath

3. ImagePath 模块概述

ImagePath.Path 是 Pillow 中用于矢量路径操作的底层模块,主要用于:

  • 创建任意多边形路径
  • 填充或描边复杂形状
  • 坐标变换(平移、缩放、旋转)
  • ImageDraw 配合绘制矢量图形
  • 解析 SVG 路径字符串(d 属性)

核心用途

  • 生成验证码背景
  • 艺术字路径
  • 地图多边形填充
  • 自定义图形特效

4. 核心类:ImagePath.Path

4.1 创建路径

# 方法1:从坐标列表创建
coords = [(50, 50), (150, 50), (100, 150), (50, 50)]  # 闭合三角形
path = ImagePath.Path(coords)

# 方法2:空路径 + 追加
path = ImagePath.Path()
path.moveto(100, 100)
path.lineto(200, 100)
path.lineto(150, 200)
path.closepath()  # 闭合

5. 路径方法详解

方法作用
moveto(x, y)移动到点(不绘制)
lineto(x, y)绘制直线到点
curveto(x1,y1, x2,y2, x3,y3)三次贝塞尔曲线
closepath()闭合路径
getbbox()返回路径边界 (left, top, right, bottom)
tolist(flat=False)转为坐标列表
compact()移除冗余点
transform(matrix)应用 2D 变换矩阵

6. 与 ImageDraw 配合使用

img = Image.new("RGB", (300, 300), "white")
draw = ImageDraw.Draw(img)

# 创建五角星路径
import math
def star_path(cx, cy, r, points=5):
    path = ImagePath.Path()
    for i in range(points * 2):
        angle = i * math.pi / points
        radius = r if i % 2 == 0 else r * 0.4
        x = cx + radius * math.cos(angle - math.pi/2)
        y = cy + radius * math.sin(angle - math.pi/2)
        if i == 0:
            path.moveto(x, y)
        else:
            path.lineto(x, y)
    path.closepath()
    return path

star = star_path(150, 150, 80)
draw.polygon(star, fill="gold", outline="black", width=3)
img.save("star.png")

7. 路径变换(平移、缩放、旋转)

from PIL import ImagePath
import math

path = ImagePath.Path([(0,0), (100,0), (50,100), (0,0)])

# 平移
path.transform((1, 0, 0, 1, 50, 30))  # [a,b,c,d,tx,ty]

# 缩放
path.transform((2, 0, 0, 2, 0, 0))    # 2倍放大

# 旋转 45°(围绕原点)
angle = math.radians(45)
c, s = math.cos(angle), math.sin(angle)
path.transform((c, s, -s, c, 0, 0))

# 绘制
img = Image.new("RGB", (300, 300), "white")
draw = ImageDraw.Draw(img)
draw.polygon(path, fill="lightblue")
img.save("transformed.png")

8. 解析 SVG 路径字符串

def svg_path_to_pil(d, scale=1.0):
    """将 SVG path 的 d 属性转为 ImagePath.Path"""
    import re
    path = ImagePath.Path()
    commands = re.findall(r'[MLHVCSQTAZmlhvcsqtaz][^MLHVCSQTAZmlhvcsqtaz]*', d)

    x = y = 0
    for cmd in commands:
        cmd_type = cmd[0]
        nums = [float(n) for n in re.findall(r'-?\d+\.?\d*', cmd)]
        i = 0
        while i < len(nums):
            if cmd_type in 'Mm':
                x, y = nums[i], nums[i+1]
                path.moveto(x * scale, y * scale) if cmd_type.isupper() else path.lineto(x * scale, y * scale)
                i += 2
            elif cmd_type in 'Ll':
                x, y = nums[i], nums[i+1]
                path.lineto(x * scale, y * scale)
                i += 2
            # 更多命令可扩展...
    return path

# 示例:SVG 心形
svg_d = "M10,30 A20,20 0,0,1 50,30 A20,20 0,0,1 90,30 Q90,60 50,90 Q10,60 10,30 z"
heart = svg_path_to_pil(svg_d, scale=3)

img = Image.new("RGB", (300, 300), "white")
draw = ImageDraw.Draw(img)
draw.polygon(heart, fill="red")
img.save("heart.svg_path.png")

9. 高级应用

9.1 扭曲文字路径(艺术字)

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

def wavy_text(text, font_path, size=(600, 200)):
    img = Image.new("RGB", size, "white")
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype(font_path, 72)

    # 获取文字边界
    left, top, right, bottom = draw.textbbox((0,0), text, font=font)
    w, h = right - left, bottom - top

    # 创建波浪路径
    path = ImagePath.Path()
    y_base = size[1] // 2
    for x in range(left, right + 1):
        offset = 20 * math.sin(x * 0.05)
        y = y_base + offset
        if x == left:
            path.moveto(x, y)
        else:
            path.lineto(x, y)

    # 绘制文字沿路径(近似)
    for i, ch in enumerate(text):
        char_img = Image.new("RGBA", (w//len(text)+10, h+40), (0,0,0,0))
        char_draw = ImageDraw.Draw(char_img)
        char_draw.text((5, 20), ch, font=font, fill="black")
        # 粘贴到波浪位置
        x_pos = left + i * (w//len(text))
        y_offset = 20 * math.sin(x_pos * 0.05)
        img.paste(char_img, (x_pos, int(y_base + y_offset - h//2)), char_img)

    return img

wavy_text("WAVE", "arial.ttf").save("wavy_text.png")

9.2 生成验证码背景(随机多边形)

def captcha_background(size=(300, 100)):
    img = Image.new("RGB", size, "white")
    draw = ImageDraw.Draw(img)

    for _ in range(5):
        points = [(random.randint(0, size[0]), random.randint(0, size[1])) for _ in range(4)]
        path = ImagePath.Path(points)
        path.closepath()
        color = (random.randint(100, 255), random.randint(100, 255), random.randint(100, 255))
        draw.polygon(path, fill=color, outline=None)

    return img

captcha_background().save("captcha_bg.png")

10. 性能优化

场景建议
大量路径使用 path.compact() 压缩
重复变换缓存变换矩阵
复杂 SVG预解析 + 缓存路径
高分辨率先低分辨率绘制,再 resize

11. 常见问题

问题解决
路径不闭合调用 path.closepath()
坐标超出画布使用 getbbox() 检查并平移
变换后变形确保矩阵顺序正确
SVG 解析失败仅支持 M L Z 等基本命令

12. 官方文档

  • https://pillow.readthedocs.io/en/stable/reference/ImagePath.html

一键工具脚本:path_tool.py

#!/usr/bin/env python3
import argparse
from PIL import Image, ImageDraw, ImagePath
import math

def main():
    parser = argparse.ArgumentParser(description="ImagePath 路径生成器")
    parser.add_argument("-t", "--type", choices=["star", "heart", "wave"], default="star")
    parser.add_argument("-o", "--output", default="path.png")

    args = parser.parse_args()
    img = Image.new("RGB", (400, 400), "white")
    draw = ImageDraw.Draw(img)

    if args.type == "star":
        path = ImagePath.Path()
        cx, cy, r = 200, 200, 100
        for i in range(10):
            angle = i * math.pi / 5
            radius = r if i % 2 == 0 else r * 0.4
            x = cx + radius * math.cos(angle - math.pi/2)
            y = cy + radius * math.sin(angle - math.pi/2)
            (path.moveto if i == 0 else path.lineto)(x, y)
        path.closepath()
        draw.polygon(path, fill="gold", outline="black")

    img.save(args.output)
    print(f"已生成: {args.output}")

if __name__ == "__main__":
    main()

使用

python path_tool.py -t star -o my_star.png

需要我帮你实现 SVG 转 PNG 批量工具、路径动画帧生成、地图行政区填充、自定义字体路径 等功能吗?直接说需求,我给你完整代码!

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注