Знайдіть найкращий шрифт для візуалізації кодової точки


16

Як знайти відповідний шрифт для візуалізації точок коду Unicode?

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 python2PEP 394.
Зулан

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'
Neil Mayhew

3

У кінцевому рахунку gnome-terminal використовує fontconfig для (серед іншого):

... ефективно та швидко знайдіть потрібні шрифти серед набору встановлених шрифтів, навіть якщо ви встановили тисячі шрифтів ...

У документації API можна знайти функції для запиту діапазонів символів шрифтів та для операцій з діапазонами символів, але документація настільки виразна, що я ніколи не міг зрозуміти, як різні набори функцій співвідносяться один з одним. Якщо мені потрібно зануритися глибше, я б скоріше подивився приклади використання іншого програмного забезпечення, можливо, vte (бібліотека емуляції терміналів, що використовується в gnome-терміналі).

Ще одна бібліотека між ними vte та fontconfig - це панго, "... бібліотека для викладення та надання тексту, з акцентом на інтернаціоналізацію ..." . Тепер, коли я думаю про це, це звучить як те, що містить більшість логіки, яку ви дотримуєтесь.

Функціональність покриття символів у панго реалізується картами покриття ( "Часто в Pango потрібно визначити, чи може певний шрифт представляти конкретний символ, а також наскільки добре він може представляти цей символ. PangoCoverage - це структура даних, яка використовується представляти цю інформацію. " ), але, ймовірно, є більш складні деталі, які вирішили, який гліф відображати за допомогою шрифту. Я припускаю , що ВТЕ покладається на Панго для візуалізації рядки з відповідними шрифтами в той час як Панго використовує FontConfig (або інший підтримуваний бекенд шрифту) , щоб знайти найбільш підходящий шрифт , заснований на різних шматочки логіки в PanGo себе і / або внутрішній інтерфейсі.


1

Я змінив код, щоб перевірити, чи містить шрифт усі символи певного рядка. Таким чином, це може бути викликано, 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.