Trouvez la meilleure police pour rendre un point de code


16

Comment trouver la police appropriée pour le rendu des points de code Unicode?

gnome-terminaltrouver que des caractères comme «🉃 ⼼ 😻🕲🝤» peuvent être rendus avec des polices comme Symbola plutôt que ma police terminale ou le repli codepoint-in-square (????). Comment ?


Réponses:


14

Ce n'est pas nécessairement la meilleure méthode, et ce n'est certainement pas convivial, mais c'est facile de travailler: voici un script Python pour le faire.

Installez la bibliothèque Python-fontconfig . Soit l'obtenir à partir de votre distribution (par exemple sudo apt-get install python-fontconfigsur Debian et dérivés) ou l'installer dans votre répertoire personnel ( pip install --user python-fontconfig). Ensuite, vous pouvez exécuter ce script (l'enregistrer comme fc-search-codepointdans un répertoire sur votre PATH, par exemple, typiquement ~/bin, et le rendre exécutable):

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

Exemple d'utilisation:

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

Je n'ai aucune police avec tous ces caractères.

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

1
C'est un script très utile! Cependant, il n'est compatible qu'avec python2, et je suppose que c'est un peu méchant de faire exactement ce portable. Tu veux bien au moins changer le #!/usr/bin/env pythonà #!/usr/bin/env python2selon PEP 394.
Zulan

1
Merci pour cette réponse! Ce fut très utile. Je suis sûr que le système d'exploitation ou les bibliothèques système qui implémentent le remplacement des polices font quelque chose de plus efficace, mais cela fonctionne. @Zulan Il peut également être utilisé avec python3; Je viens d'écrire une version plus petite de cela au bas de cette réponse .
ShreevatsaR

5

En utilisant fontconfig,

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

par exemple

> fc-list ':charset=2713 2717'

affichera tous les noms de fichiers de polices contenant ✓ et ✗.

Pour obtenir le point de code correspondant à l'utilisation du caractère (par exemple)

> printf "%x" \'✓
2713>

Cela utilise une fonctionnalité quelque peu obscure de l' utilitaire POSIXprintf :

Si le caractère de tête est un guillemet simple ou un guillemet double, la valeur doit être la valeur numérique dans le jeu de codes sous-jacent du caractère suivant le guillemet simple ou le guillemet double.

Pris ensemble,

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

Cela utilise le xargs -Idrapeau pour remplacer {}par des noms de stdin. Donc, cela se résume effectivement à:

> fc-list ":charset=2713"

2
Notez que vous avez besoin d'une version de fontconfigcette version 2.11.91ou ultérieure .
Nathaniel M. Beaver

1
notez ce tiret printfet /bin/printfne supportez pas cela
Steven Penny

1
Impressionnant! Je cherchais des informations à ce sujet depuis longtemps. Notez que vous pouvez également spécifier des plages ainsi que des caractères uniques, afin de trouver toutes les polices qui ont tous les caractères de dessin, par exemple:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew

3

En fin de compte, gnome-terminal utilise fontconfig pour (entre autres):

... trouvez efficacement et rapidement les polices dont vous avez besoin parmi l'ensemble de polices que vous avez installées, même si vous avez installé des milliers de polices ...

Dans la documentation de l' API, vous pouvez trouver des fonctions pour interroger les plages de caractères des polices et pour les opérations sur les plages de caractères, mais la documentation est tellement cryptique que je n'ai jamais pu comprendre comment les différents ensembles de fonctions sont liés les uns aux autres. Si j'avais besoin de plonger plus profondément, je préfère regarder des exemples d'utilisation dans d'autres logiciels, peut-être vte (la bibliothèque d'émulation de terminal utilisée dans gnome-terminal).

Une autre bibliothèque entre vte et fontconfig est pango "... une bibliothèque pour la mise en page et le rendu de texte, avec un accent sur l'internationalisation ..." . Maintenant que j'y pense, cela semble être celui qui contient la plupart de la logique que vous recherchez.

La fonctionnalité de couverture de caractères dans pango est implémentée par des cartes de couverture ( "Il est souvent nécessaire dans Pango de déterminer si une police particulière peut représenter un caractère particulier, et aussi dans quelle mesure elle peut représenter ce caractère. Le PangoCoverage est une structure de données qui est utilisée pour représenter ces informations. " ), mais il y a probablement des détails plus compliqués impliqués dans le choix du glyphe à rendre avec quelle police. Je suppose que VTE s'appuie sur pango pour rendre les chaînes avec les polices appropriées tandis que pango utilise fontconfig (ou un autre backend de police pris en charge) pour trouver la police la plus appropriée en fonction de divers éléments de logique dans pango lui-même et / ou le backend.


1

J'ai modifié le code pour vérifier si une police contient tous les caractères d'une certaine chaîne. Donc cela peut être appelé par fc-search-codepoint "$fontname" "$string"et il retourne le code de sortie 0 en cas de succès ou 1 sinon. Les noms de police peuvent être récupérés depuis fc-query /path/to/FontSandMonoBoldOblique.ttfou ceux d'Imagemagick convert -list font. Je l'utilise pour vérifier si une chaîne sélectionnée par l'utilisateur peut être rendue avec la police sélectionnée par l'utilisateur et si la commande échoue, une police de secours est utilisée.

#!/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)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.