Finden Sie die beste Schriftart zum Rendern eines Codepunkts

16

Wie finde ich die passende Schriftart zum Rendern von Unicode-Codepunkten?

gnome-terminalStellen Sie fest, dass Zeichen wie "🉃 ⼼ 😻🕲🝤" mit Schriftarten wie "Symbola" und nicht mit meiner Terminalschriftart oder dem Codepoint-in-Square-Fallback (????) gerendert werden können. Wie ?

Nee
quelle
Related: askubuntu.com/questions/27598/…
Nathaniel M. Beaver

Antworten:

14

Dies ist nicht unbedingt die beste Methode, und es ist sicher nicht benutzerfreundlich, aber es ist einfach, daran zu arbeiten: Hier ist ein Python-Skript, um dies zu tun.

Installieren Sie die Python-fontconfig- Bibliothek. Beziehen Sie es entweder von Ihrer Distribution (z. B. sudo apt-get install python-fontconfigunter Debian und Derivaten) oder installieren Sie es in Ihrem Home-Verzeichnis ( pip install --user python-fontconfig). Dann können Sie dieses Skript ausführen (speichern Sie es fc-search-codepointin einem Verzeichnis auf Ihrem PATH, z. B. typical ~/bin, und machen Sie es ausführbar):

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

Anwendungsbeispiel:

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

Ich habe keine Schrift mit all diesen Zeichen.

$ fc-search-codepoint U+1F64D
/usr/share/fonts/truetype/unifont/unifont_upper.ttf
/usr/share/fonts/truetype/unifont/unifont_upper_csur.ttf
Gilles 'SO - hör auf böse zu sein'
quelle
1
Das ist ein sehr hilfreiches Skript! Es ist jedoch nur Python2-konform, und ich nehme an, es ist ein bisschen unangenehm, genau das zu tun, was portabel ist. Würden Sie zumindest die Änderung der etwas dagegen #!/usr/bin/env pythonzu #!/usr/bin/env python2laut PEP 394.
Zulan
1
Danke für diese Antwort! Es war sehr hilfreich. Ich bin sicher, dass das Betriebssystem oder die Systembibliotheken, die Font Fallback implementieren, etwas effizienteres tun, aber das funktioniert. @ Zulan Es kann gemacht werden, um mit python3zu arbeiten; Ich habe gerade eine kleinere Version davon am Ende dieser Antwort geschrieben .
ShreevatsaR
5

Fontconfig verwenden,

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

z.B

> fc-list ':charset=2713 2717'

zeigt alle Schriftdateinamen an, die ✓ und ✗ enthalten.

Um den Codepunkt zu erhalten, der dem Zeichen entspricht, verwenden Sie (zum Beispiel)

> printf "%x" \'✓
2713>

Dies verwendet eine etwas undurchsichtige Funktion des POSIX- printfDienstprogramms :

Wenn das führende Zeichen ein einfaches Anführungszeichen oder ein doppeltes Anführungszeichen ist, ist der Wert der numerische Wert im zugrunde liegenden Codesatz des Zeichens, das auf das einfache Anführungszeichen oder das doppelte Anführungszeichen folgt.

Zusammen genommen,

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

Dies verwendet das xargs -IFlag, um {}durch Namen von zu ersetzen stdin. Das läuft also effektiv auf Folgendes hinaus:

> fc-list ":charset=2713"
David Baynard
quelle
2
Beachten Sie, dass Sie eine Version von fontconfigdieser Version 2.11.91oder höher benötigen .
Nathaniel M. Beaver
1
Beachten Sie, dass Bindestrich printfund /bin/printfnicht unterstützen
Steven Penny
1
Genial! Ich habe lange nach Informationen darüber gesucht. Beachten Sie, dass Sie auch Bereiche sowie einzelne Zeichen angeben können, um alle Schriftarten zu finden, die alle Zeichen zum Zeichnen von Feldern enthalten. Beispiel:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew,
3

Letztendlich benutzt gnome-terminal fontconfig um (unter anderem):

... finden Sie effizient und schnell die Schriften, die Sie benötigen, unter den Schriften, die Sie installiert haben, auch wenn Sie Tausende von Schriften installiert haben ...

In der API-Dokumentation finden Sie Funktionen zum Abfragen von Schriftzeichenbereichen und für Vorgänge in Zeichenbereichen. Die Dokumentation ist jedoch so kryptisch, dass ich nie herausfinden konnte, wie verschiedene Funktionssätze miteinander zusammenhängen. Wenn ich tiefer eintauchen müsste, würde ich mir lieber Beispiele für die Verwendung in anderer Software ansehen, vielleicht vte (die Terminalemulationsbibliothek, die in gnome-terminal verwendet wird).

Eine weitere Bibliothek zwischen vte und fontconfig ist pango "... eine Bibliothek zum Layouten und Rendern von Text mit Schwerpunkt auf Internationalisierung ..." . Nun, da ich darüber nachdenke, klingt es so, als würde es den größten Teil der Logik enthalten, nach der Sie suchen.

Die Zeichenabdeckungsfunktion in Pango wird durch Abdeckungskarten implementiert ( "In Pango muss häufig festgestellt werden, ob eine bestimmte Schriftart ein bestimmtes Zeichen darstellen kann und wie gut sie dieses Zeichen darstellen kann. PangoCoverage ist eine verwendete Datenstruktur um diese Informationen darzustellen. " ), aber es gibt wahrscheinlich kompliziertere Details bei der Entscheidung, welche Glyphe mit welcher Schriftart dargestellt werden soll. Ich denke , VTE auf verläßt sich pango Strings mit entsprechenden Schriftart zu machen , während pango Anwendungen fontconfig (oder anderer Backend unterstützt Schriftart) die am besten geeignete Schriftart auf verschiedene pieced der Logik in Basis zu finden pango selbst und / oder das Backend.

artm
quelle
1

Ich habe den Code geändert, um zu überprüfen, ob eine Schriftart alle Zeichen einer bestimmten Zeichenfolge enthält. Dies kann also von aufgerufen werden fc-search-codepoint "$fontname" "$string"und gibt bei Erfolg den Exit-Code 0 oder andernfalls 1 zurück. Die Schriftnamen können von fc-query /path/to/FontSandMonoBoldOblique.ttfoder Imagemagick's abgerufen werden convert -list font. Ich verwende es, um zu überprüfen, ob eine vom Benutzer ausgewählte Zeichenfolge mit der vom Benutzer ausgewählten Schriftart gerendert werden kann, und wenn der Befehl fehlschlägt, wird eine Ersatzschrift verwendet.

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