Encuentra la mejor fuente para representar un punto de código


16

¿Cómo encontrar la fuente adecuada para representar puntos de código Unicode?

gnome-terminaldescubra que los caracteres como «🉃 ⼼ 😻🕲🝤» se pueden representar con fuentes como Symbola en lugar de la fuente de mi terminal o la alternativa de codepoint-in-square (????). Cómo ?


Respuestas:


14

Este no es necesariamente el mejor método, y seguro que no es fácil de usar, pero es fácil trabajar: aquí hay un script de Python para hacerlo.

Instale la biblioteca Python-fontconfig . Puede obtenerlo de su distribución (por ejemplo, sudo apt-get install python-fontconfigen Debian y derivados) o instalarlo en su directorio de inicio ( pip install --user python-fontconfig). Luego puede ejecutar este script (guárdelo como fc-search-codepointen un directorio en su PATH, por ejemplo ~/bin, normalmente , y hacerlo ejecutable):

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

Ejemplo de uso:

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

No tengo ninguna fuente con todos estos caracteres.

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

1
¡Es un guión muy útil! Sin embargo, solo es compatible con python2, y supongo que es un poco desagradable hacer exactamente eso portátil. ¿Le importaría al menos cambiar el #!/usr/bin/env pythona #!/usr/bin/env python2según PEP 394.
Zulan

1
Gracias por esta respuesta! Fue muy útil Estoy seguro de que el sistema operativo o las bibliotecas del sistema que implementan la recuperación de fuentes están haciendo algo más eficiente, pero esto funciona. @Zulan También se puede hacer que funcione python3; Acabo de escribir una versión más pequeña de esto al final de esta respuesta .
ShreevatsaR

5

Usando fontconfig,

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

p.ej

> fc-list ':charset=2713 2717'

mostrará cualquier nombre de archivo de fuente que contenga ✓ y ✗.

Para obtener el punto de código correspondiente al uso de caracteres (por ejemplo)

> printf "%x" \'✓
2713>

Utiliza una característica algo oscura de la utilidad POSIXprintf :

Si el carácter inicial es una comilla simple o una comilla doble, el valor será el valor numérico en el conjunto de códigos subyacente del carácter que sigue a la comilla simple o la comilla doble.

Tomados en conjunto,

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

Esto usa la xargs -Ibandera para reemplazar {}con nombres de stdin. Entonces, esto se reduce a:

> fc-list ":charset=2713"

2
Tenga en cuenta que necesita una versión de fontconfigeso es 2.11.91o posterior .
Nathaniel M. Beaver

1
tenga en cuenta ese guión printfy /bin/printfno lo respalde
Steven Penny el

1
¡Increíble! He estado buscando información sobre esto durante mucho tiempo. Tenga en cuenta que también puede especificar rangos, así como caracteres individuales, por lo que para encontrar todas las fuentes que tienen todos los caracteres de dibujo de cuadro, por ejemplo:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew,

3

En última instancia, gnome-terminal usa fontconfig para (entre otras cosas):

... encuentre de manera eficiente y rápida las fuentes que necesita entre el conjunto de fuentes que ha instalado, incluso si ha instalado miles de fuentes ...

En la documentación de la API puede encontrar funciones para consultar rangos de caracteres de fuentes y para operaciones en rangos de caracteres, pero la documentación es tan críptica que nunca pude descubrir cómo se relacionan entre sí diferentes conjuntos de funciones. Si tuviera que profundizar más, preferiría ver ejemplos de uso en otro software, tal vez vte (la biblioteca de emulación de terminal utilizada en gnome-terminal).

Otra biblioteca entre vte y fontconfig es pango "... una biblioteca para diseñar y renderizar texto, con énfasis en la internacionalización ..." . Ahora que lo pienso, suena como el que contiene la mayor parte de la lógica que buscas.

La funcionalidad de cobertura de caracteres en pango se implementa mediante mapas de cobertura ( "A menudo es necesario en Pango determinar si una fuente en particular puede representar un carácter en particular y también qué tan bien puede representar ese carácter. PangoCoverage es una estructura de datos que se utiliza representar esa información " ), pero probablemente haya detalles más complicados involucrados en decidir qué glifo representar con qué fuente. Supongo que VTE se basa en pango para representar cadenas con las fuentes apropiadas, mientras que pango usa fontconfig (u otro backend de fuente compatible) para encontrar la fuente más apropiada basada en varias piezas lógicas en el propio pango y / o el backend.


1

Modifiqué el código para verificar si una fuente contiene todos los caracteres de una cadena determinada. Entonces esto puede ser llamado por fc-search-codepoint "$fontname" "$string"y devuelve el código de salida 0 en caso de éxito o 1 de lo contrario. Los nombres de las fuentes se pueden recuperar de fc-query /path/to/FontSandMonoBoldOblique.ttfo de Imagemagick convert -list font. Lo uso para verificar si una cadena seleccionada por el usuario se puede representar con la fuente seleccionada por el usuario y si el comando falla, se usa una fuente alternativa.

#!/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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.