Как найти подходящий шрифт для отображения кодовых точек Unicode?
gnome-terminal
нахожу, что такие персонажи, как «
решение1
Используя fontconfig,
> fc-list ':charset=<hex_code1> <hex_code2>'
например
> fc-list ':charset=2713 2717'
отобразит все имена файлов шрифтов, содержащие ✓ и ✗.
Чтобы получить кодовую точку, соответствующую символу, используйте (например)
> printf "%x" \'✓
2713>
Это используетнесколько неясная особенность
принадлежащийprintf
Утилита POSIX:
Если начальный символ представляет собой одинарную или двойную кавычку, значение должно быть числовым значением в базовом кодовом наборе символа, следующего за одинарной или двойной кавычкой.
Взяты вместе,
> printf '%x' \'✓ | xargs -I{} fc-list ":charset={}"
Здесь используется xargs
-I
флаг для замены {}
именами из stdin
. Так что это фактически сводится к следующему:
> fc-list ":charset=2713"
решение2
Это не обязательно лучший метод, и он, конечно, неудобен для пользователя, но его легко реализовать: вот скрипт на Python, который это делает.
УстановитьPython-fontconfigбиблиотека. Либо возьмите ее из вашего дистрибутива (например, sudo apt-get install python-fontconfig
в Debian и производных), либо установите в свой домашний каталог ( pip install --user python-fontconfig)
. Затем вы можете запустить этот скрипт (сохраните его как fc-search-codepoint
в каталоге на вашем PATH
, например, usual ~/bin
, и сделайте его исполняемым):
#!/usr/bin/env python2
import re, sys
import fontconfig
if len(sys.argv) < 1:
print('''Usage: ''' + sys.argv[0] + '''CHARS [REGEX]
Print the names of available fonts containing the code point(s) CHARS.
If CHARS contains multiple characters, they must all be present.
Alternatively you can use U+xxxx to search for a single character with
code point xxxx (hexadecimal digits).
If REGEX is specified, the font name must match this regular expression.''')
sys.exit(0)
characters = sys.argv[1]
if characters.startswith('U+'):
characters = unichr(int(characters[2:], 16))
else:
characters = characters.decode(sys.stdout.encoding)
regexp = re.compile(sys.argv[2] if len(sys.argv) > 2 else '')
font_names = fontconfig.query()
found = False
for name in font_names:
if not re.search(regexp, name): continue
font = fontconfig.FcFont(name)
if all(font.has_char(c) for c in characters):
print(name)
found = True
sys.exit(0 if found else 1)
Пример использования:
$ fc-search-codepoint
решение3
В конечном итоге gnome-terminal используетfontconfig(среди прочего):
...эффективно и быстро находите нужные вам шрифты среди набора установленных у вас шрифтов, даже если у вас установлены тысячи шрифтов...
вAPI-документациявы можете найти функции для запроса диапазонов символов шрифтов и для операций над диапазонами символов, но документация настолько запутанная, что я так и не смог понять, как различные наборы функций соотносятся друг с другом. Если бы мне нужно было погрузиться глубже, я бы предпочел посмотреть примеры использования в другом программном обеспечении, возможновте(библиотека эмуляции терминала, используемая в gnome-terminal).
Еще одна библиотека между нимивтеиfontconfigявляетсяпанго «...библиотека для компоновки и отображения текста с упором на интернационализацию...». Теперь, когда я об этом думаю, мне кажется, что именно в этом и заключается большая часть логики, которую вы ищете.
Функциональность покрытия символов в Pango реализована с помощьюкарты покрытия(«В Pango часто необходимо определить, может ли конкретный шрифт представлять определенный символ, а также насколько хорошо он может представлять этот символ. PangoCoverage — это структура данных, которая используется для представления этой информации».), но, вероятно, есть более сложные детали, связанные с решением, какой глиф отображать каким шрифтом. Я полагаюВТЭполагается напангодля отображения строк с соответствующими шрифтами, покапангоиспользуетfontconfig(или другой поддерживаемый бэкэнд шрифтов) для поиска наиболее подходящего шрифта на основе различных фрагментов логики впангосебя и/или бэкэнд.
решение4
Я изменил код, чтобы проверить, содержит ли шрифт все символы определенной строки. Так что это может быть вызвано fc-search-codepoint "$fontname" "$string"
и возвращает код выхода 0 в случае успеха или 1 в противном случае. Имена шрифтов можно получить из fc-query /path/to/FontSandMonoBoldOblique.ttf
или Imagemagick convert -list font
. Я использую его, чтобы проверить, может ли выбранная пользователем строка быть отображена с выбранным пользователем шрифтом, и если команда не выполняется, используется резервный шрифт.
#!/usr/bin/env python2
import re
import sys
import os
import fontconfig
if len(sys.argv) < 3:
print("Usage: " + sys.argv[0] + " 'Fontname-Bold' 'String to check'")
sys.exit(0)
font_name = sys.argv[1].decode('utf-8')
string = sys.argv[2].decode('utf-8')
if '-' in font_name:
font_name = font_name.split('-')
font_style = font_name[-1]
font_name = ''.join(font_name[:-1])
else:
font_style = ""
font_names = fontconfig.query()
for name in font_names:
font = fontconfig.FcFont(name)
if not len(font.family) > 0:
continue
for item in font.family:
if item[1] == unicode(font_name):
if len(font_style) == 0:
match = "yes"
else:
for item in font.style:
if item[1] == unicode(font_style):
match = "yes"
try:
match
except NameError:
continue
if all(font.has_char(c) for c in string):
sys.exit(0)
else:
sys.exit(1)
print >> sys.stderr, "font not found: " + font_name + " " + font_style
sys.exit(1)