4

我正在使用 matplotlib 的 Adob​​e Font Metrics 接口来计算各种字符串的边界框。计算“12”和“°”的边界框效果很好,但是在计算“12°”的边界框时,框的大小似乎太大了。

我知道由于字距调整等原因,边界框的尺寸不一定等于其部分边界框的总和,但这似乎很荒谬。(它似乎也没有反映渲染时此类文本的大小)。

编码:

import os.path
from matplotlib import rcParams
from matplotlib.afm import AFM

afm_fname = os.path.join(rcParams['datapath'],
                         'fonts', 'afm', 'ptmr8a.afm')
with open(afm_fname, 'rb') as fh:
    afm = AFM(fh)

print(afm.get_str_bbox('12'))
print(afm.get_str_bbox('\u00B0'))
print(afm.get_str_bbox('12\u00B0'))

(\u00B0 是° 的 unicode)

结果

(0, 0, 1000.0, 676)
(0, 390, 400.0, 676)
(0, 0, 1400.0, 1066)

第三个结果的高度显然太大了。1066是676 + 390,不知道是不是巧合但是我不明白

问题

为什么边界框如此之大/是什么导致了这种行为?

有没有办法“解决”这个问题,以便我得到一个更具代表性的 bbox,文本实际看起来像什么?

(有关边界框的更多信息,请参见:https ://wwwimages2.adobe.com/content/dam/acom/en/devnet/font/pdfs/5004.AFM_Spec.pdf )

编辑:

检查 matplotlib.afm 中的 AFM 类,我想我发现了违规行。下面# find the max ythismax = b + h. 我不明白为什么b+h应该在那里使用,而不仅仅是h????

def get_str_bbox_and_descent(self, s):
    """
    Return the string bounding box
    """
    if not len(s):
        return 0, 0, 0, 0
    totalw = 0
    namelast = None
    miny = 1e9
    maxy = 0
    left = 0
    if not isinstance(s, six.text_type):
        s = _to_str(s)
    for c in s:
        if c == '\n':
            continue
        name = uni2type1.get(ord(c), 'question')
        try:
            wx, bbox = self._metrics_by_name[name]
        except KeyError:
            name = 'question'
            wx, bbox = self._metrics_by_name[name]
        l, b, w, h = bbox
        if l < left:
            left = l
        # find the width with kerning
        try:
            kp = self._kern[(namelast, name)]
        except KeyError:
            kp = 0
        totalw += wx + kp

        # find the max y
        thismax = b + h
        if thismax > maxy:
            maxy = thismax

        # find the min y
        thismin = b
        if thismin < miny:
            miny = thismin
        namelast = name

    return left, miny, totalw, maxy - miny, -miny
4

0 回答 0