Trova il carattere migliore per il rendering di un punto di codice


16

Come trovare il carattere appropriato per il rendering dei punti di codice Unicode?

gnome-terminalscopri che caratteri come «🉃 ⼼ 😻🕲🝤» possono essere renderizzati con caratteri come Symbola piuttosto che con il mio carattere terminale o con il fallback codepoint-in-square (????). Come ?


Risposte:


14

Questo non è necessariamente il metodo migliore, e sicuramente non è facile da usare, ma è facile far funzionare: ecco uno script Python per farlo.

Installa la libreria Python-fontconfig . O prendilo dalla tua distribuzione (ad es. sudo apt-get install python-fontconfigSu Debian e derivati) o installalo nella tua home directory ( pip install --user python-fontconfig). Quindi puoi eseguire questo script (salvalo come fc-search-codepointin una directory nella tua PATH, ad es. In genere ~/bin, e renderlo eseguibile):

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

Esempio di utilizzo:

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

Non ho alcun carattere con tutti questi personaggi.

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

1
Questa è una sceneggiatura molto utile! Tuttavia, è compatibile solo con Python2 e suppongo che sia un po 'brutto fare esattamente quel portatile. Ti dispiacerebbe almeno cambiare la #!/usr/bin/env pythona #!/usr/bin/env python2secondo PEP 394.
Zulan

1
Grazie per questa risposta! È stato molto utile Sono sicuro che il sistema operativo o le librerie di sistema che implementano il fallback dei font stanno facendo qualcosa di più efficiente, ma funziona. @Zulan Può essere fatto funzionare python3anche con ; Ho appena scritto una versione più piccola di questo in fondo a questa risposta .
ShreevatsaR,

5

Utilizzando fontconfig,

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

per esempio

> fc-list ':charset=2713 2717'

visualizzerà qualsiasi nome di file di font contenente ✓ e ✗.

Per ottenere il punto di codice corrispondente al carattere utilizzare (ad esempio)

> printf "%x" \'✓
2713>

Questo utilizza una caratteristica un po 'oscura della POSIX printfutility :

Se il carattere principale è una virgoletta singola o una virgoletta doppia, il valore deve essere il valore numerico nel set di codici sottostante del carattere che segue la virgoletta singola o la virgoletta doppia.

Presi insieme,

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

Questo utilizza il xargs -Iflag per sostituire {}con i nomi di stdin. Quindi questo si riduce efficacemente a:

> fc-list ":charset=2713"

2
Si noti che è necessaria una versione di fontconfigtale versione 2.11.91o successiva .
Nathaniel M. Beaver,

1
notare che trattino printfe /bin/printfnon lo supportano
Steven Penny,

1
Eccezionale! Ho cercato informazioni su questo per molto tempo. Nota che puoi anche specificare intervalli e caratteri singoli, quindi per trovare tutti i caratteri che hanno tutti i caratteri di disegno a scatola, ad esempio:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew,

3

Alla fine gnome-terminal usa fontconfig per (tra le altre cose):

... trova in modo efficiente e rapido i caratteri di cui hai bisogno nel set di caratteri che hai installato, anche se hai installato migliaia di caratteri ...

Nella documentazione dell'API puoi trovare le funzioni per interrogare gli intervalli di caratteri dei caratteri e per le operazioni sugli intervalli di caratteri, ma la documentazione è così enigmatica che non sono mai riuscito a capire come diversi insiemi di funzioni si relazionano tra loro. Se avessi bisogno di approfondire, preferirei guardare esempi di utilizzo in altri software, forse vte (la libreria di emulazione terminale usata in gnome-terminal).

Un'altra biblioteca tra VTE e fontconfig è Pango "... una biblioteca per la posa fuori e rendering del testo, con l'accento sulla internazionalizzazione ..." . Ora che ci penso, suona come quello che contiene la maggior parte della logica che stai cercando.

La funzionalità di copertura dei caratteri in pango è implementata dalle mappe di copertura ( "Spesso è necessario in Pango determinare se un determinato carattere può rappresentare un determinato carattere, e anche quanto bene può rappresentare quel carattere. PangoCoverage è una struttura di dati che viene utilizzata per rappresentare quell'informazione " ), ma probabilmente ci sono dettagli più complicati coinvolti nel decidere quale glifo rendere con quale font. Immagino che VTE faccia affidamento su pango per eseguire il rendering di stringhe con caratteri appropriati, mentre pango utilizza fontconfig (o altri backend di font supportati) per trovare il font più appropriato basato su vari elementi logici di pango stesso e / o backend.


1

Ho modificato il codice per verificare se un carattere contiene tutti i caratteri di una determinata stringa. Quindi questo può essere chiamato da fc-search-codepoint "$fontname" "$string"e restituisce il codice di uscita 0 in caso di successo o 1 altrimenti. I nomi dei caratteri possono essere recuperati da fc-query /path/to/FontSandMonoBoldOblique.ttfo Imagemagick convert -list font. Lo uso per verificare se una stringa selezionata dall'utente può essere renderizzata con il carattere selezionato dall'utente e se il comando non riesce, viene utilizzato un carattere di fallback.

#!/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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.