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 CJK、Microsoft 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
有任何具体需求(比如 生成验证码、动态水印、艺术字),直接告诉我,我可以给你定制代码!