如何根据指定的字体和大小计算字符串的像素长度?

17
如果字体(例如:Times New Roman)和大小(例如:12pt)已知,如何计算字符串的长度(例如:“Hello world”)的像素数,可能只是大概的?我需要这个来对在Windows应用程序中显示的文本进行手动右对齐,因此我需要调整空格的数量以获得对齐。

2
请参阅 https://pillow.readthedocs.org/en/3.0.0/reference/ImageFont.html#PIL.ImageFont.PIL.ImageFont.ImageFont.getsize。 - Selcuk
3个回答

31

Pillow v9.2.0 开始,.getsize 已被弃用,并将在 2023-07-01 的 Pillow v10 中删除。请改用 getbboxgetlength

已在 python 3.11.2pillow v9.4.0 中测试通过

from PIL import ImageFont
font = ImageFont.truetype('times.ttf', 12)

left, top, right, bottom = font.getbbox('Hello world')
width = font.getlength('Hello world')

print(f'left: {left}, top: {top}, right: {right}, bottom: {bottom}, width: {width}')
[out]:
left: 0, top: 2, right: 58, bottom: 11, width: 57.0

根据@Selcuk的评论,我找到了答案:

from PIL import ImageFont
font = ImageFont.truetype('times.ttf', 12)
size = font.getsize('Hello world')
print(size)

这是一个打印(x, y)尺寸的函数:

(58, 11)

以下是函数的代码:

from PIL import ImageFont

def get_pil_text_size(text, font_size, font_name):
    font = ImageFont.truetype(font_name, font_size)
    size = font.getsize(text)
    return size

get_pil_text_size('Hello world', 12, 'times.ttf')

根据该网站的说明,PIL模块尚未在Python 3中得到支持http://www.pythonware.com/products/pil/。因此我无法让上述内容正常工作。 - bobsmith76
3
在Python3上,我使用安装了Pillow的方法使其工作(这是PIL的现代更新版本)。https://pillow.readthedocs.io提供安装说明(“pip install Pillow”)。 - mcherm
1
在安装了 Pillow 模块后,Visual Studio 2019 上也可以运行,谢谢大家! - Xiokraze
2
适用于Python 3.7.3。 - JayJay123

13

另一种方法是按如下方式向Windows询问:

import ctypes

def GetTextDimensions(text, points, font):
    class SIZE(ctypes.Structure):
        _fields_ = [("cx", ctypes.c_long), ("cy", ctypes.c_long)]

    hdc = ctypes.windll.user32.GetDC(0)
    hfont = ctypes.windll.gdi32.CreateFontA(points, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, font)
    hfont_old = ctypes.windll.gdi32.SelectObject(hdc, hfont)

    size = SIZE(0, 0)
    ctypes.windll.gdi32.GetTextExtentPoint32A(hdc, text, len(text), ctypes.byref(size))

    ctypes.windll.gdi32.SelectObject(hdc, hfont_old)
    ctypes.windll.gdi32.DeleteObject(hfont)

    return (size.cx, size.cy)

print(GetTextDimensions("Hello world", 12, "Times New Roman"))
print(GetTextDimensions("Hello world", 12, "Arial"))

这将显示:

(47, 12)
(45, 12)

谢谢;在Python 3中,必须添加()才能使用print,但除此之外它可以工作。但是两种方法之间存在显着的x大小差异,这有点奇怪。 - EquipDev
1
给定的字体可以有很多维度,所以我猜测 getsize() 使用的是另一个维度。 - Martin Evans
我遇到了AttributeError: module 'ctypes' has no attribute 'windll'的错误。这很奇怪,因为当我在ctypes后输入“w”时,Python会在弹出框中显示该方法。 - bobsmith76
你正在使用哪个版本的Python?它在2.7.12版本中可以很好地工作。请注意,它仅适用于Windows操作系统。 - Martin Evans

0
除了已经提供的答案之外:如果您有一个包含多行文本的文本(例如'第一行\r\n第二行')- 可能有几种方法可以获得文本的宽度和高度。
“手动方式”是通过行来分割文本,并获取行的最大宽度以及行高的总和:
from PIL import ImageFont
multiline_string = 'Quick test of multiline text\r\nNew line\nAnother new line here'
font = ImageFont.truetype('arial.ttf', 8)
bboxes = [font.getbbox(k) for k in multiline_string.splitlines()]
width = max([(b[2]-b[0]) for b in bboxes])
height = sum([(b[3]) for b in bboxes])
print('width=' + str(width) + ', height=' + str(height))

另一种方法是使用ImageDraw.multiline_textbbox()函数:
from PIL import Image, ImageFont, ImageDraw
multiline_test = 'Quick test of multiline text\r\nNew line\nAnother new line here'
img = Image.new("RGB", (1000, 1000), (255, 255, 255)) # create an image filled with white color
curr_font = ImageFont.truetype("arial.ttf", 8) # get a font "Arial" with size = 8
curr_context = ImageDraw.Draw(img) # get drawing context of the image
result_box = curr_context.multiline_textbbox((0,0), multiline_test, font=curr_font, font_size=8) # get resulting boundry-box for multiline text with curr_font and font-size = 8
print(result_box) # print the result-box (the width and height could be retrieved there)
# Useful to see the result text:
# curr_context.multiline_text((0, 0), multiline_test, font=curr_font, fill=(0, 0, 0))
# img.show()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接