Encontre a melhor fonte para renderizar um codepoint

Encontre a melhor fonte para renderizar um codepoint

Como encontrar a fonte apropriada para renderizar pontos de código Unicode?

gnome-terminaldescobrir que personagens como «

Responder1

Usando fontconfig,

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

por exemplo

> fc-list ':charset=2713 2717'

exibirá qualquer nome de arquivo de fonte contendo ✓ e ✗.

Para obter o codepoint correspondente ao uso do caractere (por exemplo)

> printf "%x" \'✓
2713>

Isso usa umrecurso um tanto obscuro doprintfUtilitário POSIX:

Se o caractere inicial for aspas simples ou aspas duplas, o valor deverá ser o valor numérico no conjunto de códigos subjacente do caractere após as aspas simples ou aspas duplas.

Tomados em conjunto,

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

Isso usa o xargs -Isinalizador para substituir {}por nomes de stdin. Então, isso efetivamente se resume a:

> fc-list ":charset=2713"

Responder2

Este não é necessariamente o melhor método e com certeza não é fácil de usar, mas é fácil de fazer funcionar: aqui está um script Python para fazer isso.

Instale oPython-fontconfigbiblioteca. Obtenha-o em sua distribuição (por exemplo, sudo apt-get install python-fontconfigno Debian e derivados) ou instale-o em seu diretório inicial ( pip install --user python-fontconfig). Então você pode executar este script (salve-o como fc-search-codepointem um diretório em seu PATH, por exemplo, normalmente ~/bin, e torne-o executável):

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

Exemplo de uso:

$ fc-search-codepoint 

Responder3

Em última análise, o gnome-terminal usaconfiguração de fontepara (entre outras coisas):

...encontre com eficiência e rapidez as fontes que você precisa entre o conjunto de fontes que você instalou, mesmo que você tenha instalado milhares de fontes...

NoDocumentação da APIvocê pode encontrar funções para consultar intervalos de caracteres de fontes e para operações em intervalos de caracteres, mas a documentação é tão enigmática que nunca consegui descobrir como diferentes conjuntos de funções se relacionam entre si. Se eu precisasse me aprofundar, preferiria ver exemplos de uso em outros softwares, talvezvte(a biblioteca de emulação de terminal usada no gnome-terminal).

Outra biblioteca no meiovteeconfiguração de fonteépango "...uma biblioteca para diagramação e renderização de texto, com ênfase na internacionalização...". Agora que penso nisso, parece que contém a maior parte da lógica que você procura.

A funcionalidade de cobertura de caracteres no pango é implementada pormapas de cobertura("Muitas vezes é necessário no Pango determinar se uma fonte específica pode representar um caractere específico e também quão bem ela pode representar esse caractere. O PangoCoverage é uma estrutura de dados usada para representar essa informação."), mas provavelmente há detalhes mais complicados envolvidos na decisão de qual glifo renderizar com qual fonte. Eu achoTEVdepende depangopara renderizar strings com fontes apropriadas enquantopangousaconfiguração de fonte(ou outro back-end de fonte compatível) para encontrar a fonte mais apropriada com base em várias partes da lógica empangoele mesmo e/ou o back-end.

Responder4

Alterei o código para verificar se uma fonte contém todos os caracteres de uma determinada string. Portanto, isso pode ser chamado por fc-search-codepoint "$fontname" "$string"e retorna o código de saída 0 em caso de sucesso ou 1 caso contrário. Os nomes das fontes podem ser recuperados do fc-query /path/to/FontSandMonoBoldOblique.ttfarquivo convert -list font. Eu o uso para verificar se uma string selecionada pelo usuário pode ser renderizada com a fonte selecionada pelo usuário e se o comando falhar, uma fonte substituta será usada.

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

informação relacionada