类似于这个问题,我不是问如何查找字符串中的字符数。 我想确定渲染时字符串的视觉长度或将其与另一个字符串进行比较。
例如,“iiii”和“WWWW”都有四个字符。 然而,“iiii”在视觉上更短。 我知道这是由字体决定的,并且我不使用等宽字体。 因此,为了解决这个问题,我将使用 Arial 10pt。
是否有任何内置模块可以提供给定字体的字符串的视觉尺寸?
您可以直接使用字体度量来计算宽度,而不是渲染到图像缓冲区并计算像素。似乎没有随核心Python一起分发的字体API,但有很多第三方的各种套餐。这是 Adobe 字体指标的非常完整的解决方案,使用 matplotlib
:
>>> from matplotlib import rcParams
>>> import os.path
>>> afm_filename = os.path.join(rcParams['datapath'], 'fonts', 'afm', 'ptmr8a.afm')
>>>
>>> from matplotlib.afm import AFM
>>> afm = AFM(open(afm_filename, "rb"))
>>> afm.string_width_height('What the heck?')
(6220.0, 694)
指标以所使用字体的比例因子(点大小)的 1/1000 为单位报告。 (感谢@JacobLee 挖掘了这个
信息。)
另一种可能性是tkFont
的
tkinter
模块。此页面记录了功能
tkFont.Font.measure("some string")
,但似乎您需要一个Tk窗口才能使用它;所以我不知道它有多实用:
# Python 3 names -- see Note below
import tkinter
from tkinter import font as tkFont
tkinter.Frame().destroy() # Enough to initialize resources
arial36b = tkFont.Font(family='Arial', size=36, weight='bold')
width = arial36b.measure("How wide is this?")
print(width) # Prints: 404
注意:在python 2中(以及我上面提到的
page中),tkinter
被称为
Tkinter
,
tkinter.font
是顶级模块,
tkFont
:
import Tkinter
import tkFont
它使用当前屏幕作为输出上下文,并计算以给定点大小显示给定字体所需的尺寸。它返回一个包含文本宽度和文本高度的元组:
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)
for text, font in [
('....', 'Arial'),
('WWWW', 'Arial'),
('WWWW', 'Arial Narrow'),
('....', 'Courier New'),
('WWWW', 'Courier New'),
("Test", "Unknown font"),
('Test', 'Calibri')]:
print '{:8} {:20} {}'.format(text, font, GetTextDimensions(text, 12, font))
这将显示以下输出:
.... Arial (12, 15)
WWWW Arial (44, 15)
WWWW Arial Narrow (36, 16)
.... Courier New (28, 15)
WWWW Courier New (28, 15)
Test Unknown font (24, 15)
Test Calibri (23, 14)
Arial
是比例字体,显示
....
和
WWWW
不同的尺寸,但
Courier New
是固定宽度,给出相同的结果。与
Arial Narrow
的
36
相比,
44
给出
Arial
。在
Unknown font
的情况下,Windows 字体映射器已自动选择默认字体。在 Python 2.x 上测试。
Python 3.x 的注意事项
由于这是在 Windows 中调用GetTextExtentPoint32A()
,因此需要将 ANSI 文本传递给它,因此可以按如下方式更改调用来解决此问题:
ctypes.windll.gdi32.GetTextExtentPoint32A(hdc, text.encode('cp1252'), len(text), ctypes.byref(size))
或者,切换代码以使用宽版本,替换为这两个:
hfont = ctypes.windll.gdi32.CreateFontW(-points, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, font)
ctypes.windll.gdi32.GetTextExtentPoint32W(hdc, text, len(text), ctypes.byref(size))
ImageFont。 绘制字符串,然后使用 getsize 获取宽度。
请注意,由于
from tkinter import Tk
from tkinter.font import Font
def get_text_size(text: str, font_family: str = 'Arial', font_size: int = 10, bold: bool = False) -> int:
"""Get the screen width of a text based on Font Type, Font Size and Font Weight
Args:
text (str): Text for which to calculate the screen width
font_family (str, optional): Font family. Defaults to 'Arial'.
font_size (int, optional): Font size. Defaults to 10.
bold (bool, optional): If bold or not. Defaults to False.
Returns:
int: Screen width of the text
"""
root = Tk() # Needed to estimate the width.
font_weight = 'bold' if bold else 'normal'
font_var = Font(family=font_family, size=font_size, weight=font_weight)
width = font_var.measure(text)
root.destroy() # Destroy the created window
return width
PIL.ImageFont
有一个函数
getLength()
可以获取字符串的长度(以像素为单位)。
import PIL
PIL.ImageFont.truetype('Arial.ttf', 10)
textLength = font.getlength("My string to measure")
请注意,这会为您提供以像素为单位的渲染大小,因此,如果您不使用 PIL 来绘制字体,那么我建议选择一个较大的高度值(以最大限度地减少矢量字体形状光栅化产生的错误),并计算得出结果像素与您在使用它的应用程序中关心的任何单位的比率。这是我发现的测量渲染字符串尺寸长度的最简单方法。