Pillow中使用truetype函数如何设置精确的像素字号?
解决Pillow中
truetype字体实际高度与设定字号不符的问题 当使用Pillow的ImageFont.truetype()指定字号时,文本实际绘制高度常和设定值差异明显——这是因为该方法的第二个参数是字体的em尺寸,并非文本的实际像素高度。字体的ascent(基线到字符顶部的像素数)和descent(基线到字符底部的像素数)共同决定了文本的实际绘制高度,不同字体的这两个值比例差异很大。
要实现精确的文本像素高度,可通过以下步骤计算正确字号:
核心思路
- 用一个临时字号创建字体,获取该字号下的实际文本高度(
ascent + descent) - 根据目标高度和临时字号的实际高度,计算缩放比例,反推所需的精确字号
- 用计算出的字号创建字体,完成绘制
代码实现
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
相关产品推荐
相关产品推荐

