Pillow ImageFont 模块

下面给你一个 Pillow(PIL Fork)中 ImageFont 模块 的完整入门指南,包含常用功能、代码示例以及常见坑点。
(所有示例均基于 Pillow ≥ 9.0,Python 3.8+)


1. 安装 Pillow

pip install --upgrade pillow

2. 基本导入

from PIL import Image, ImageDraw, ImageFont

3. 加载字体

3.1 使用系统自带字体(推荐)

# Windows 示例
font = ImageFont.truetype("C:/Windows/Fonts/Arial.ttf", size=48)

# macOS 示例
font = ImageFont.truetype("/System/Library/Fonts/Arial.ttf", size=48)

# Linux 示例(常见路径)
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", size=48)

3.2 使用自定义 TTF/OTF 文件

font = ImageFont.truetype("myfont.ttf", size=36)   # 放在当前工作目录或给出绝对路径

3.3 默认字体(不推荐,仅用于调试)

font = ImageFont.load_default()   # 极小的位图字体,质量差

4. 绘制文字

# 创建空白画布
img = Image.new("RGB", (400, 200), "white")
draw = ImageDraw.Draw(img)

text = "Hello Pillow!"
font = ImageFont.truetype("arial.ttf", 48)

# 文字尺寸(用于居中)
text_bbox = draw.textbbox((0, 0), text, font=font)   # (left, top, right, bottom)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]

x = (img.width - text_width) // 2
y = (img.height - text_height) // 2

draw.text((x, y), text, font=font, fill="black")
img.save("output.png")

关键 API

  • draw.textbbox(xy, text, font=...) → 返回文字的外接矩形(Pillow 8.0+)
  • draw.textlength(text, font=...) → 只返回宽度(Pillow 9.0+)

5. 常用属性 & 方法

方法/属性说明
font.getbbox(text)draw.textbbox,直接在字体对象上获取
font.getlength(text)draw.textlength
font.getmask(text)返回文字的位图 mask(可用于自定义渲染)
font.getmetrics()返回 (ascent, descent),即文字上沿和下沿距离基线的高度
font.fontvariant某些字体支持的变体(较少使用)

6. 高级技巧

6.1 多行文字(自动换行)

def draw_multiline(draw, text, max_width, font, fill, start_xy):
    words = text.split()
    lines = []
    line = ""

    for word in words:
        test_line = line + word + " "
        if draw.textlength(test_line, font=font) <= max_width:
            line = test_line
        else:
            lines.append(line.strip())
            line = word + " "
    if line:
        lines.append(line.strip())

    x, y = start_xy
    line_height = font.getbbox("hg")[3] - font.getbbox("hg")[1]  # 近似行高
    for i, l in enumerate(lines):
        draw.text((x, y + i * line_height), l, font=font, fill=fill)

6.2 文字轮廓 / 描边

def draw_outline(draw, xy, text, font, fill, outline_color, width=2):
    x, y = xy
    # 8方向描边
    for dx in range(-width, width+1):
        for dy in range(-width, width+1):
            if dx or dy:
                draw.text((x+dx, y+dy), text, font=font, fill=outline_color)
    draw.text(xy, text, font=font, fill=fill)

6.3 垂直文字(从上到下)

def draw_vertical(draw, xy, text, font, fill):
    x, y = xy
    for ch in text:
        draw.text((x, y), ch, font=font, fill=fill)
        y += font.getbbox(ch)[3] - font.getbbox(ch)[1] + 2  # 行间距

7. 常见问题 & 解决方案

问题原因解决办法
OSError: cannot open resource字体路径错误或系统未安装确认路径、权限,或使用 fontconfig 查找
文字显示为方块字体不支持对应字符(尤其是中文)使用支持 Unicode 的字体,如 Noto Sans CJKMicrosoft YaHei
文字模糊图片放大后未开启抗锯齿绘制时使用 Image.LANCZOS 缩放,或在高分辨率画布上绘制
行高不一致不同字体 ascent/descent 不同统一使用 font.getmetrics() 计算行高

8. 中文示例(完整代码)

from PIL import Image, ImageDraw, ImageFont

img = Image.new("RGB", (600, 300), "#f0f0f0")
draw = ImageDraw.Draw(img)

# 推荐中文字体
font_path = "msyh.ttc"          # Windows: C:/Windows/Fonts/msyh.ttc
# font_path = "NotoSansSC-Regular.otf"  # 跨平台
font = ImageFont.truetype(font_path, 56)

text = "你好,Pillow!"
bbox = draw.textbbox((0, 0), text, font=font)
w = bbox[2] - bbox[0]
h = bbox[3] - bbox[1]

x = (img.width - w) // 2
y = (img.height - h) // 2

# 描边
draw_outline(draw, (x, y), text, font, fill="red", outline_color="black", width=3)

img.save("中文示例.png")

9. 参考文档

  • 官方文档:https://pillow.readthedocs.io/en/stable/reference/ImageFont.html
  • textbbox / textlength:https://pillow.readthedocs.io/en/stable/releasenotes.html#textbbox-and-textlength

有任何具体需求(比如 生成验证码、动态水印、艺术字),直接告诉我,我可以给你定制代码!

类似文章

发表回复

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