Как получить ширину шрифта истинного шрифта в 1200-х дюйма с помощью Python? - PullRequest
3 голосов
/ 16 ноября 2010

Я могу получить высоту и ширину символа в пикселях с PIL (см. Ниже), но (если я не ошибаюсь) размер пикселя зависит от DPI экрана, который может варьироваться.Вместо этого я хотел бы рассчитать ширину символа в абсолютных единицах, например, дюймах или 1200-х дюймах («единицах идеального слова»).создать функцию переноса слов для написания двоичных документов Word Perfect.Word Perfect требует, чтобы мягкие коды разрывов строк вставлялись в допустимые точки по всему тексту, иначе файл будет поврежден и недоступен для открытия.Вопрос в том, где их добавить для шрифтов переменной ширины.

Я понимаю, что не до конца понимаю взаимосвязь между пикселями, разрешением экрана и размерами шрифтов.Я все об этом ошибаюсь?

1 Ответ

4 голосов
/ 20 января 2018

Ширина необработанного текста обычно рассчитывается в точках типографа , но, поскольку точка для определения шрифта определена как 1/72 дюйма, вы можете легко преобразовать ее в любую другую единицу.

Чтобы получить дизайн ширины символа (выраженный в em единицах), вам необходим доступ к низкоуровневым данным шрифта. Самый простой способ - pip install fonttools, в котором есть все для работы на минимально возможном уровне определений шрифтов.

С установленным fontTools вы можете:

  1. загрузить данные шрифта - для этого требуется путь к фактическому файлу шрифта;
  2. ширина символов сохраняется как glyph width, что означает, что вы должны получить отображение «символ-глиф»; это в cmap таблице шрифтов:

    а. загрузите cmap для вашего шрифта. Наиболее полезной является карта Unicode - шрифт может содержать другие. б. загрузите набор глифов для вашего шрифта. Это список имен для глифов этого шрифта.

  3. Затем для каждого символа Unicode сначала найдите его имя, а затем используйте имя для получения его ширины в единицах проектирования.

  4. Не забывайте, что «единицы дизайна» основаны на общей «ширине дизайна» шрифта. Это может быть стандартное значение 1000 (типично для шрифтов типа 1), 2048 (типично для шрифтов TrueType) или любое другое значение.

Что приводит к этой функции:

from fontTools.ttLib import TTFont
from fontTools.ttLib.tables._c_m_a_p import CmapSubtable

font = TTFont('/Library/Fonts/Arial.ttf')
cmap = font['cmap']
t = cmap.getcmap(3,1).cmap
s = font.getGlyphSet()
units_per_em = font['head'].unitsPerEm

def getTextWidth(text,pointSize):
    total = 0
    for c in text:
        if ord(c) in t and t[ord(c)] in s:
            total += s[t[ord(c)]].width
        else:
            total += s['.notdef'].width
    total = total*float(pointSize)/units_per_em;
    return total

text = 'This is a test'

width = getTextWidth(text,12)

print ('Text: "%s"' % text)
print ('Width in points: %f' % width)
print ('Width in inches: %f' % (width/72))
print ('Width in cm: %f' % (width*2.54/72))
print ('Width in WP Units: %f' % (width*1200/72))

Результат:

Text: "This is a test"
Width in points: 67.353516
Width in inches: 0.935465
Width in cm: 2.376082
Width in WP Units: 1122.558594

и является правильным при сравнении с отчетами Adobe InDesign. (Обратите внимание, что символьный кернинг здесь не применяется! Для этого потребуется намного больше кода.)

Символы, которые не определены в шрифте, игнорируются, и, как обычно это делается, используется ширина для символа .notdef. Если вы хотите, чтобы это сообщалось как об ошибке, удалите тест if в функции.

Приведение к float в функции getTextWidth таково, что это работает как в Python 2.7, так и в 3.5, но учтите, что если вы используете символы Unicode Python 2.7 и более (не простые ASCII), вам нужно переписать функция для правильного использования символов UTF8.

...