You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pillow中使用truetype函数如何设置精确的像素字号?

解决Pillow中truetype字体实际高度与设定字号不符的问题

当使用Pillow的ImageFont.truetype()指定字号时,文本实际绘制高度常和设定值差异明显——这是因为该方法的第二个参数是字体的em尺寸,并非文本的实际像素高度。字体的ascent(基线到字符顶部的像素数)和descent(基线到字符底部的像素数)共同决定了文本的实际绘制高度,不同字体的这两个值比例差异很大。

要实现精确的文本像素高度,可通过以下步骤计算正确字号:

核心思路

  1. 用一个临时字号创建字体,获取该字号下的实际文本高度(ascent + descent)
  2. 根据目标高度和临时字号的实际高度,计算缩放比例,反推所需的精确字号
  3. 用计算出的字号创建字体,完成绘制

代码实现

from PIL import Image, ImageDraw, ImageFont

# 目标文本高度(单位:像素)
target_height = 20
# 临时字号(选较大值可减少计算误差)
temp_font_size = 100
# 自定义字体路径
font_path = r'devangiri.ttf'

# 1. 创建临时字体,获取字体度量信息
temp_font = ImageFont.truetype(font_path, temp_font_size)
ascent, descent = temp_font.getmetrics()
temp_actual_height = ascent + descent

# 2. 计算所需的精确字号
required_font_size = (target_height / temp_actual_height) * temp_font_size

# 3. 创建最终字体并绘制文本
font = ImageFont.truetype(font_path, required_font_size)

# 测试绘制与验证
image = Image.new('RGB', (250, 50), 'white')
draw = ImageDraw.Draw(image)
draw.text((10, 10), 'SOMEWORDS', font=font, fill='black')

# 用textbbox验证实际高度(Pillow 9.1.0+ 支持)
bbox = draw.textbbox((0, 0), 'SOMEWORDS', font=font)
actual_text_height = bbox[3] - bbox[1]
print(f"实际文本高度:{actual_text_height:.1f} 像素(目标:{target_height})")

image.save('test_text.png')

注意事项

  • 临时字号的选择:使用较大的临时字号(如100)可以减少字体像素对齐带来的计算误差,让最终字号更精确。
  • 边界框验证:Pillow 9.1.0及以上版本推荐用textbbox()获取文本的精确边界框,旧版本可使用已弃用的font.getsize()方法,但textbbox的结果更准确。
  • 字体差异:不同字体的ascent和descent比例不同,因此该计算需要针对每个字体单独执行。
  • 可视高度调整:如果需要的是字符的可视高度(而非包含字体空白的总高度),可以直接用textbbox返回的高度来计算比例,替换上述代码中的ascent + descent。

内容的提问来源于stack exchange,提问作者Arnav Mehta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 16:10:21