Python Pillow加载ttf字体在图片上写字教程

小鹿同学
小鹿同学
发布时间:2026-10-31 | 7人浏览过
原创

本教程详细讲解在 Python 中使用 Pillow 库加载 TTF/OTF 矢量字体并在图片上绘制中文文字的完整方法,包含环境准备、标准调用链路、坐标与 anchor 对齐机制、长文本换行与常见问题排查。

Pillow 实用开发 阅读时长:约 8 分钟 环境要求:Python 3.8+ / Pillow 9.0+
Python Pillow加载ttf字体在图片上写字教程
图 0:Pillow 矢量文字绘制架构概览
在 Python 中使用 Pillow 库在图片上添加文字时,默认字体仅支持微缩英文字符且无法调整大小。要绘制清晰、抗锯齿且包含中文的文字,核心路径是通过 PIL.ImageFont.truetype(font, size) 加载外部 TTF 或 OTF 矢量字体文件,再结合 ImageDraw.Draw.text() 进行栅格化渲染。本文提供可立即执行的完整步骤、坐标度量技巧及常见排坑说明。

一、准备工作与环境依赖

Pillow 是 Python 原生图像处理库 PIL 的现代分支。处理文字需要依赖系统已构建好的 FreeType 字体引擎支持。通常通过标准包管理器安装的 Pillow 预编译轮子(Wheels)已默认静态编译包含 FreeType 模块,无需手动安装底层 C 库。

终端执行命令 BASH
pip install Pillow

执行验证命令确认模块安装正常:

环境检查示例 PYTHON
import PIL from PIL import Image, ImageDraw, ImageFont print("Pillow 版本:", PIL.__version__)

准备一个可用的中文字体文件(.ttf 或 .otf)。如果是在 Windows 环境下,系统目录 C:/Windows/Fonts/msyh.ttc(微软雅黑)或 simhei.ttf(黑体)可直接作为字体路径;在 Linux 或跨平台服务器端,建议将字体文件(例如开源免费商用的“阿里巴巴普惠体”或“思源黑体”)与代码存放在同一工程目录中。

二、核心操作流程与标准代码

向图片写入文字的标准生命周期包含 5 个明确步骤:建立画布对象、载入 TTF 字体规格、实例化绘图图层、测定排版边界、执行文字像素栅格化并写出。

Python Pillow加载ttf字体在图片上写字教程
图 1:Pillow 加载 TTF 并在图片写字的 5 步标准操作流水线

以下为完整的端到端示范脚本。脚本将在内存中新建一张暖灰底色的画布,加载指定 TTF 字体并写入标题及正文:

完整示例脚本:render_text.py PYTHON
import os from PIL import Image, ImageDraw, ImageFont # 1. 创建画布:新建一张 800x400、RGB 色彩模式、底色为浅暖灰的图像 width, height = 800, 400 canvas_color = (245, 244, 240) # #F5F4F0 image = Image.new("RGB", (width, height), color=canvas_color) # 2. 绑定绘图句柄:所有在 image 上的绘图与写字均通过 draw 操作完成 draw = ImageDraw.Draw(image) # 3. 加载外部 TTF 字体 # 这里指定字体文件路径;若工程目录下有名为 "AlibabaPuHuiTi.ttf" 的字体即可直接填写 font_file = "AlibabaPuHuiTi.ttf" # 防御性判断:若本地无此测试文件,自动回退到系统常见宋体/黑体,确保能够直接运行 if not os.path.exists(font_file): # Linux 常见路径: /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf # macOS 常见路径: /System/Library/Fonts/PingFang.ttc # Windows 常见路径: C:/Windows/Fonts/simhei.ttf candidate_fonts = [ "/System/Library/Fonts/PingFang.ttc", "C:/Windows/Fonts/msyh.ttc", "C:/Windows/Fonts/simhei.ttf", "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc" ] for candidate in candidate_fonts: if os.path.exists(candidate): font_file = candidate break title_font = ImageFont.truetype(font_file, size=32) sub_font = ImageFont.truetype(font_file, size=18) # 4. 写入文字:指定左上角绝对坐标、文本内容、字体对象与 RGBA/RGB 颜色值 title_text = "Python Pillow 字体绘制实践" sub_text = "基于 TrueType 矢量字体引擎实现抗锯齿文字排版" # 绘制标题(深灰墨色) draw.text((60, 120), title_text, font=title_font, fill=(45, 55, 72)) # 绘制副标题(灰蓝色) draw.text((60, 180), sub_text, font=sub_font, fill=(104, 125, 141)) # 5. 保存生成的图像 output_path = "output_pillow_text.png" image.save(output_path, quality=95) print(f"图像生成完毕,保存至: {output_path}")
执行输出示例
图像生成完毕,保存至: output_pillow_text.png

打开生成的图片后,即可看到清晰无锯齿的中文文字整齐排列在设定坐标处。

三、排版控制:文本边界测距与 Anchor 锚点对齐

在实际生产场景中(如自动生成宣发海报、照片打水印或生成证书),文字往往需要居中、居右或在限定宽度内排版,直接写死绝对坐标会导致不同长度的文字位置偏移。

Python Pillow加载ttf字体在图片上写字教程
图 2:Pillow 文本度量边界线与 Anchor 锚点对齐参数解析

1. 使用 textbbox 准确计算文字宽高

在较早的 Pillow 版本中,开发者习惯使用 draw.textsize() 或 font.getsize()。从 Pillow 10.0.0 起,这些旧接口已被正式移除,统一采用 draw.textbbox()。该方法接收起始参考坐标、文本及字体对象,返回一个四元组 (left, top, right, bottom):

文字尺寸精确测量 PYTHON
# 测量以 (0, 0) 为原点时的包围盒 bbox = draw.textbbox((0, 0), title_text, font=title_font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] # 计算水平居中时所需的 X 坐标(画布宽度为 width) center_x = (width - text_width) // 2 draw.text((center_x, 80), title_text, font=title_font, fill=(45, 55, 72))

2. 使用 anchor 参数一行代码实现对齐

Pillow 内部提供了 anchor(锚点)机制。参数由两个英文字母组成:第一个代表水平对齐(l=左, m=居中, r=右),第二个代表垂直对齐(a=升部顶端, m=垂直居中, b=降部底端, s=基线)。

若要将文字精准放置在画布的正中心点 (width // 2, height // 2),无需人工测算宽高做减法,只需指定 anchor="mm":

居中锚点极简调用 PYTHON
# 直接以 (400, 200) 为几何中心点居中渲染 draw.text((width // 2, height // 2), "全图正中心对齐文字", font=title_font, fill=(135, 155, 136), anchor="mm")

四、方案对比:ImageFont 两种载入模式的关键差异

初学者在使用 Pillow 时常疑惑为什么存在 load_default() 和 truetype() 两种获取字体的方式。下表对比了两者的本质技术特征与能力范围:

Python Pillow加载ttf字体在图片上写字教程
图 3:load_default() 简易位图与 truetype() 矢量字体的渲染差异
对比维度 ImageFont.load_default() ImageFont.truetype(font, size)
字符编码覆盖 仅包含基础 ASCII 字符,中文全部输出为空格或乱码问号 完整支持 Unicode/CJK 汉字、标点与日韩等多国语言
字号无级缩放 固定位图点阵尺寸(约 10px),无法任意放大或缩小 无级矢量缩放,从 8px 到 1000px 均保持矢量平滑
边缘渲染质量 点阵硬边缘,带有明显颗粒感和锯齿 基于 FreeType 子像素平滑渲染,抗锯齿过渡柔和自然
外部资源依赖 无任何外部依赖,Pillow 内部硬编码集成 必须指定系统或本地存在的物理 TTF/OTF 文件路径

差异的关键在于:load_default() 的设计定位是无环境依赖下的代码测试占位,而任何包含非英文字符或具有视觉要求的图形合成任务,都必须使用 truetype()。

五、生产实践与长文本自动折行

Pillow 的底层渲染引擎将换行符( )视作换行依据,但它不会自动根据图片宽度进行段落自动换行。如果传入的一行文本过长,超出图片边界的部分将直接被截断。

在批量处理业务文案时,需要编写一个轻量级的文本切分函数,利用 font.getlength() 逐字计算宽度,在达到最大宽度上限时主动切行:

多行自动折行与间距控制 PYTHON
def wrap_text(text: str, font: ImageFont.FreeTypeFont, max_width: int) -> str: lines = [] current_line = "" for char in text: # 测试追加该字符后的总宽度 test_line = current_line + char if font.getlength(test_line) <= max_width: current_line = test_line else: lines.append(current_line) current_line = char if current_line: lines.append(current_line) return "\n".join(lines) # 使用示例 long_paragraph = "Python 是一门语法优美、易于阅读的脚本语言。结合 Pillow 库,我们可以非常方便地构建出自动化报表封面与内容合成服务。" wrapped_content = wrap_text(long_paragraph, sub_font, max_width=420) # 使用 multiline_text 写入,并设定行间距 spacing=8 draw.multiline_text((60, 240), wrapped_content, font=sub_font, fill=(74, 85, 104), spacing=8)

六、高频报错与排坑清单

加载 TTF 字体操作涉及操作系统文件系统访问、字体字形表解析与图像混合,在工程化部署中容易遇到以下典型问题:

Python Pillow加载ttf字体在图片上写字教程
图 4:Pillow 字体加载核心排坑要点与避雷指南
  1. 报错 OSError: cannot open resource:
    原因:Pillow 无法在指定路径找到该字体文件。请避免使用不稳定的相对路径(如直接写 "font.ttf"),推荐使用 os.path.join(os.path.dirname(__file__), "fonts/myfont.ttf") 构建绝对路径,并在载入前通过 os.path.isfile() 确认文件存在。
  2. 中文字符显示为白色方块(“豆腐块” □):
    原因:加载的字体文件中缺少中文字符的字形轮廓(Glyph)。例如西方系统自带的 arial.ttf 或 times.ttf 仅包含西文字符,遇到汉字时没有对应点阵或贝塞尔数据,FreeType 只能以未定义方块代替。解决办法是明确引入涵盖 GB2312/GBK 或通用中文字库的字体文件。
  3. 批量产图性能迟缓:
    原因:在批量循环(例如处理上万张图片)中,每次迭代都重复执行 ImageFont.truetype()。解析 TTF 二进制字形表存在磁盘 I/O 与内存解析成本,应在循环体外部预先完成字体实例加载,循环内部复用同一 font 实例。
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表