Znajdź najlepszą czcionkę do renderowania punktu kodowego

16

Jak znaleźć odpowiednią czcionkę do renderowania punktów kodowych Unicode?

gnome-terminalokaże się, że znaki takie jak «🉃 ⼼ 😻🕲🝤» mogą być renderowane za pomocą czcionek takich jak Symbola, a nie czcionek terminalowych lub zastępczego kodu zastępczego w kwadracie (????). W jaki sposób ?

nie
źródło
Powiązane: askubuntu.com/questions/27598/…
Nathaniel M. Beaver

Odpowiedzi:

14

To niekoniecznie najlepsza metoda i na pewno nie jest przyjazna dla użytkownika, ale łatwo jest zacząć działać: oto skrypt Pythona, aby to zrobić.

Zainstaluj bibliotekę Python-fontconfig . Pobierz go ze swojej dystrybucji (np. sudo apt-get install python-fontconfigNa Debianie i jego pochodnych) lub zainstaluj w swoim katalogu domowym ( pip install --user python-fontconfig). Następnie możesz uruchomić ten skrypt (zapisz go jak fc-search-codepointw katalogu na swoim komputerze PATH, np. Zazwyczaj ~/bini spraw , by był wykonywalny):

#!/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)

Przykładowe użycie:

$ fc-search-codepoint 🉃⼼😻🕲🝤
$ echo $?
1

Nie mam żadnej czcionki dla wszystkich tych znaków.

$ fc-search-codepoint U+1F64D
/usr/share/fonts/truetype/unifont/unifont_upper.ttf
/usr/share/fonts/truetype/unifont/unifont_upper_csur.ttf
Gilles „SO- przestań być zły”
źródło
1
To bardzo pomocny skrypt! Jednak jest on zgodny tylko z Python2 i przypuszczam, że robienie tego przenośnego jest nieco nieprzyjemne. Mógłbyś przynajmniej zmieniając #!/usr/bin/env pythonsię #!/usr/bin/env python2zgodnie z PEP 394.
Zulan
1
Dzięki za tę odpowiedź! To było bardzo pomocne. Jestem pewien, że system operacyjny lub biblioteki systemowe, które implementują zastępowanie czcionek, robią coś bardziej wydajnego, ale to działa. @Zulan Może być również przystosowany do pracy python3; Właśnie napisałem mniejszą wersję tego na dole tej odpowiedzi .
ShreevatsaR
5

Używając fontconfig,

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

na przykład

> fc-list ':charset=2713 2717'

wyświetli nazwy plików czcionek zawierające ✓ i ✗.

Aby uzyskać punkt kodowy odpowiadający użyciu znaku (na przykład)

> printf "%x" \'✓
2713>

Ten wykorzystuje nieco niejasne funkcji z POSIX printfużyteczności :

Jeżeli wiodącym znakiem jest pojedynczy cudzysłów lub podwójny cudzysłów, wartością jest wartość liczbowa w podstawowym zestawie znaków znaku następującego po pojedynczym cudzysłowie lub podwójnym cudzysłowie.

Razem wzięte,

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

Używa xargs -Iflagi do zastąpienia {}nazwami z stdin. Skutecznie sprowadza się to do:

> fc-list ":charset=2713"
David Baynard
źródło
2
Pamiętaj, że potrzebujesz wersji fontconfigtego 2.11.91lub nowszej .
Nathaniel M. Beaver
1
zwróć uwagę, że dash printfi /bin/printfdont obsługują to
Steven Penny
1
Niesamowite! Długo szukałem informacji na ten temat. Zauważ, że możesz również określić zakresy, a także pojedyncze znaki, aby znaleźć wszystkie czcionki, które mają wszystkie znaki rysunkowe, na przykład:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew
3

Ostatecznie gnome-terminal używa fontconfig do (między innymi):

... sprawnie i szybko znajduj potrzebne czcionki wśród zestawu zainstalowanych czcionek, nawet jeśli zainstalowałeś tysiące czcionek ...

W dokumentacji API można znaleźć funkcje do wyszukiwania czcionek w zakresach znaków i operacji na zakresach znaków, ale dokumentacja jest tak tajemnicza, że ​​nigdy nie mogłem zrozumieć, w jaki sposób różne zestawy funkcji odnoszą się do siebie. Gdybym musiał zanurkować głębiej, wolałbym spojrzeć na przykłady użycia w innym oprogramowaniu, być może vte (biblioteka emulacji terminala używana w gnome-terminal).

Kolejną biblioteką pomiędzy vte i fontconfig jest pango „… biblioteka do układania i renderowania tekstu, z naciskiem na internacjonalizację…” . Teraz, kiedy o tym myślę, wydaje się, że zawiera większość logiki, której szukasz.

Funkcjonalność pokrycia znaków w Pango jest implementowana przez mapy pokrycia ( „W Pango często konieczne jest ustalenie, czy określona czcionka może reprezentować określony znak, a także jak dobrze może reprezentować ten znak. PangoCoverage to używana struktura danych reprezentować tę informację. ” ), ale prawdopodobnie w bardziej skomplikowanych szczegółach decyduje, który glif ma być renderowany za pomocą jakiej czcionki. Wydaje mi się, że VTE korzysta z pango do renderowania ciągów z odpowiednimi czcionkami, podczas gdy pango używa fontconfig (lub innego obsługiwanego backendu czcionek), aby znaleźć najbardziej odpowiednią czcionkę opartą na różnych elementach logicznych w samym pango i / lub backendie .

artm
źródło
1

Zmieniłem kod, aby sprawdzić, czy czcionka zawiera wszystkie znaki określonego ciągu. Może to być wywołane przez fc-search-codepoint "$fontname" "$string"i zwraca kod zakończenia 0 w przypadku powodzenia lub 1 w przeciwnym razie. Nazwy czcionek można pobrać z fc-query /path/to/FontSandMonoBoldOblique.ttflub Imagemagick convert -list font. Używam go, aby sprawdzić, czy ciąg wybrany przez użytkownika może być renderowany za pomocą czcionki wybranej przez użytkownika, a jeśli polecenie się nie powiedzie, używana jest czcionka zastępcza.

#!/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)
ladiko
źródło