我正在使用 matplotlib 的 Adobe 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 y
是thismax = 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