如何在Python中获取文本字符串的视觉长度

问题描述 投票:0回答:5

类似于这个问题,我不是问如何查找字符串中的字符数。 我想确定渲染时字符串的视觉长度或将其与另一个字符串进行比较。

例如,“iiii”和“WWWW”都有四个字符。 然而,“iiii”在视觉上更短。 我知道这是由字体决定的,并且我不使用等宽字体。 因此,为了解决这个问题,我将使用 Arial 10pt。

是否有任何内置模块可以提供给定字体的字符串的视觉尺寸?

python string
5个回答
10
投票

您可以直接使用字体度量来计算宽度,而不是渲染到图像缓冲区并计算像素。似乎没有随核心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
    

5
投票
如果您使用的是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) 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))
    


0
投票
只是对 @alexis 的答案与 tkinter 的一个小改进。 我发现该方法简单可靠,只是它会打开一个 tkinter 窗口,您必须手动关闭该窗口。 我修改了代码,这样你就不再有窗口了,并创建了一个带有更多选项的函数。

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
    

0
投票
从版本 9.2.0 开始,

PIL.ImageFont

 有一个函数 
getLength()
 可以获取字符串的长度(以像素为单位)。

import PIL PIL.ImageFont.truetype('Arial.ttf', 10) textLength = font.getlength("My string to measure")
请注意,这会为您提供以像素为单位的渲染大小,因此,如果您不使用 PIL 来绘制字体,那么我建议选择一个较大的高度值(以最大限度地减少矢量字体形状光栅化产生的错误),并计算得出结果像素与您在使用它的应用程序中关心的任何单位的比率。

这是我发现的测量渲染字符串尺寸长度的最简单方法。

© www.soinside.com 2019 - 2024. All rights reserved.