Найти лучший шрифт для рендеринга кодовой точки


16

Как найти подходящий шрифт для рендеринга кодовых точек Юникода?

gnome-terminalВыясните, что такие символы, как «🉃 ⼼ 😻🕲🝤», могут отображаться с использованием шрифтов, таких как Symbola, а не моего терминального шрифта или запасного варианта кода в квадрате (????). Как ?


Ответы:


14

Это не обязательно лучший метод, и он, конечно, не удобен для пользователя, но его легко начать работать: вот скрипт Python для этого.

Установите библиотеку Python-fontconfig . Либо получите его из своего дистрибутива (например, sudo apt-get install python-fontconfigв Debian и его производных), либо установите в своем домашнем каталоге ( pip install --user python-fontconfig)затем вы можете запустить этот скрипт (сохраните его как fc-search-codepointв каталоге PATH, например ~/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 🉃⼼😻🕲🝤
$ echo $?
1

У меня нет шрифта со всеми этими символами.

$ fc-search-codepoint U+1F64D
/usr/share/fonts/truetype/unifont/unifont_upper.ttf
/usr/share/fonts/truetype/unifont/unifont_upper_csur.ttf

1
Это очень полезный сценарий! Тем не менее, это только Python2-совместимый, и я думаю, что это немного неприятно делать именно этот портативный. Вы не возражаете , по крайней мере , меняя #!/usr/bin/env pythonв #!/usr/bin/env python2качестве одного PEP 394.
Zulan

1
Спасибо за этот ответ! Это было очень полезно. Я уверен, что ОС или системные библиотеки, которые реализуют резервный шрифт, делают что-то более эффективное, но это работает. @Zulan С ним тоже можно работать python3; Я просто написал уменьшенную версию этого в нижней части этого ответа .
ShreevatsaR

5

Используя fontconfig,

> fc-list ':charset=<hex_code1> <hex_code2>'

например

> fc-list ':charset=2713 2717'

отобразит любые имена шрифтов, содержащие ✓ и ✗.

Для получения кодовой точки, соответствующей символу, используйте (например)

> printf "%x" \'✓
2713>

При этом используется несколько неясное особенность в POSIX printfутилиты :

Если начальный символ представляет собой одинарную или двойную кавычку, значение должно быть числовым значением в базовом наборе символов, следующего за одинарной или двойной кавычкой.

Взяты вместе,

> printf '%x' \'✓ | xargs -I{} fc-list ":charset={}"

При этом xargs -Iфлаг используется для замены {}именами из stdin. Так что это эффективно сводится к:

> fc-list ":charset=2713"

2
Обратите внимание, что вам нужна версия fontconfigэтого 2.11.91или позже .
Натаниэль М. Бивер

1
обратите внимание, что черт printfи /bin/printfне поддерживают это
Стивен Пенни

1
Потрясающие! Я долго искал информацию об этом. Обратите внимание, что вы также можете указать диапазоны и отдельные символы, чтобы найти все шрифты, которые имеют все символы рисования блоков, например:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Нил Мэйхью

3

В конечном счете, gnome-терминал использует fontconfig для (среди прочего):

... эффективно и быстро найти нужные шрифты среди набора установленных шрифтов, даже если вы установили тысячи шрифтов ...

В документации API вы можете найти функции для запроса диапазонов символов шрифтов и для операций с диапазонами символов, но документация настолько загадочна, что я никогда не мог понять, как различные наборы функций связаны друг с другом. Если бы мне нужно было погрузиться глубже, я бы предпочел взглянуть на примеры использования в другом программном обеспечении, возможно, vte (библиотека эмуляции терминала, используемая в gnome-terminal).

Другая библиотека между vte и fontconfig - это pango «... библиотека для разметки и рендеринга текста с упором на интернационализацию ...» . Теперь, когда я думаю об этом, это звучит как та, которая содержит большую часть логики, которую вы ищете.

Функциональность покрытия символов в pango реализуется с помощью карт покрытия ( «В Pango часто необходимо определить, может ли конкретный шрифт представлять определенный символ, а также насколько хорошо он может представлять этот символ. PangoCoverage - это структура данных, которая используется чтобы представить эту информацию. " ), но, вероятно, есть более сложные детали, связанные с тем, какой глиф отображать каким шрифтом. Я предполагаю, что VTE использует pango для рендеринга строк с соответствующими шрифтами, в то время как pango использует fontconfig (или другой поддерживаемый бэкэнд шрифтов) для поиска наиболее подходящего шрифта, основанного на различных элементах логики в самом pango и / или бэкэнде.


1

Я изменил код, чтобы проверить, содержит ли шрифт все символы определенной строки. Так что это может быть вызвано, fc-search-codepoint "$fontname" "$string"и он возвращает код выхода 0 в случае успеха или 1 в противном случае. Названия шрифтов могут быть получены из fc-query /path/to/FontSandMonoBoldOblique.ttfили Imagemagick's 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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.