测量文本宽度(Python/PIL)

31

我正在使用以下两种方法来计算设置字体和大小的样本字符串的渲染宽度


font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 14)
sample = "Lorem ipsum dolor sit amet, partem periculis an duo, eum lorem paulo an, mazim feugiat lobortis sea ut. In est error eirmod vituperata, prima iudicabit rationibus mel et. Paulo accumsan ad sit, et modus assueverit eum. Quod homero adversarium vel ne, mel noster dolorum te, qui ea senserit argumentum complectitur. Duo at laudem explicari deterruisset, eu quo hinc mnesarchum. Vel autem insolens atomorum at, dolorum suavitate voluptatum duo ex."
#METHOD 1
draw_txt = ImageDraw.Draw(img)
width, height = draw_txt.textsize(sample, font=font)
print width
#METHOD 2
width = 0
for c in sample:
    width += font.getsize(c)[0]
print width

METHOD 1 的宽度为 3236,而 METHOD 2 的值为 3270。为什么会有差异?此外,我还注意到样本文本越短,这两种方法之间的差异就越小。

内部发生了什么?哪个宽度可以被认为是呈现句子的真实宽度?最后,是否有一种微调方法可以使这两种方法报告的宽度大致相同?

注意:样本文本长度为445个字符

1个回答

52

字距

这里有两件不同的事情:

  • 获取长文本的宽度。
  • 获取所有字符的宽度,并盲目地将它们加在一起。

如果您使用等宽字体,情况可能会有所不同,但通常字体使用一种叫做 字距 的东西使文本更加平滑和紧密。

维基百科 上写道:

在印刷排版中,字距 是指调整比例字体中字符之间的间距,通常是为了获得视觉上令人愉悦的结果。 字距调整单个字母形式之间的空间,而跟踪(字间距)则在一系列字符上均匀调整间距。 在良好的字距字体中,每对字符之间的二维空白区域都具有视觉上相似的面积。

Kerning brings A and V closer with their serifs over each other

这里有一些 DejaVuSans 字体的字距示例

font kerning showing different char widths

工作原理

在底层,Pillow 对于您的两种方法并没有做太大的不同。只是您以不同的方式调用它们。

如果您添加第三种方法使用与第二种方法相同的函数获取整个句子的宽度,则也将获得与获取整个句子与第一种方法相同的宽度:

# METHOD 3
width = font.getsize(sample)[0]
print width

以下是Pillow的 ImageDraw.textsize(来自方法一和方法三):

def textsize(self, text, font=None, *args, **kwargs):
    """Get the size of a given string, in pixels."""
    if self._multiline_check(text):
        return self.multiline_textsize(text, font, *args, **kwargs)

    if font is None:
        font = self.getfont()
    return font.getsize(text)

对于单行文本,这只是返回font.getsize,与方法二相同。(对于多行文本,它只是将其分成几行并返回几个font.getsize调用的总和。)


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