Странное поведение, вычисляющее ограничивающую рамку текста с символом градусов
Я использую интерфейс Adobe Font Metrics от matplotlib, чтобы вычислять ограничивающую рамку для различных строк. Расчет ограничивающих рамок для "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 - это Юникод для °)
Результаты
(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)
РЕДАКТИРОВАТЬ:
Проверяя класс AFM в matplotlib.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