查找用于渲染代码点的最佳字体


Answers:


14

这不一定是最好的方法,并且肯定不是用户友好的,但是很容易上手:这是一个Python脚本来实现。

安装Python-fontconfig库。可以从您的发行版中获取它(例如sudo apt-get install python-fontconfig在Debian和衍生产品上),也可以将其安装在主目录中(pip install --user python-fontconfig)然后,您可以运行该脚本(将其保存fc-search-codepoint在您的目录中PATH,例如通常为~/bin,并使其可执行):

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

用法示例:

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

我没有所有这些字符的字体。

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

1
多数民众赞成在一个非常有用的脚本!但是,它仅兼容python2,我想准确地做到这一点有点可恶。你至少会介意改变#!/usr/bin/env python#!/usr/bin/env python2按PEP 394
Zulan

1
感谢您的回答!这非常有帮助。我确定实现字体后备的OS或系统库的工作效率更高,但这可以实现。@Zulan也可以和它一起工作python3;我只是在此答案的底部写了一个较小的版本。
ShreevatsaR

5

使用fontconfig,

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

例如

> fc-list ':charset=2713 2717'

将显示包含✓和✗的所有字体文件名。

要获取与字符相对应的代码点,请使用(例如)

> printf "%x" \'✓
2713>

这将使用有点模糊功能 的的POSIX printf实用工具

如果前导字符是单引号或双引号,则该值应是单引号或双引号后的字符的基础代码集中的数值。

在一起

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

这将使用该xargs -I标志替换{}来自的名称stdin。因此,这实际上可以归结为:

> fc-list ":charset=2713"

2
请注意,您需要的版本fontconfig2.11.91更高版本
纳撒尼尔·比弗

1
请注意破折号printf/bin/printf不支持该
史蒂文·彭尼

1
太棒了!我一直在寻找有关此信息的信息。请注意,您还可以指定范围以及单个字符,以便查找具有所有框形图字符的所有字体,例如:fc-list --format='%{postscriptname}\n' ':charset=2500-257F'
Neil Mayhew

3

最终,gnome-terminal使用fontconfig进行(除其他事项外):

...即使已经安装了数千种字体,也可以在已安装的字体集中快速,高效地找到所需的字体...

API文档中,您可以找到用于查询字体字符范围和用于字符范围的操作的函数,但是该文档过于神秘,以至于我始终无法弄清不同功能集之间的关系。如果我需要更深入地研究,我宁愿看一下其他软件中的用法示例,也许是vte(gnome-terminal中使用的终端仿真库)。

vtefontconfig之间的另一个库是pango “ ...一个用于布局和呈现文本的库,重点是国际化...”。现在我想到了,它听起来像是包含您所追求的大多数逻辑的一种。

Pango中的字符覆盖功能由覆盖图实现(“在Pango中,通常有必要确定特定字体是否可以表示特定字符​​,以及它可以如何很好地表示该字符。PangoCoverage是一种使用的数据结构。以表示该信息。”),但是在决定使用哪种字体呈现哪种字形时可能涉及更复杂的细节。我猜VTE依靠pango渲染具有适当字体的字符串,而pango使用fontconfig(或其他受支持的字体后端)根据pango本身和/或后端中的各种逻辑找到最合适的字体。


1

我更改了代码,以检查字体是否包含某个字符串的所有字符。因此,可以通过调用此方法fc-search-codepoint "$fontname" "$string",如果成功则返回退出代码0,否则返回1。可以从fc-query /path/to/FontSandMonoBoldOblique.ttf或Imagemagick的中检索字体名称convert -list font。我用它来检查用户选择的字符串是否可以用用户选择的字体呈现,如果命令失败,则使用后备字体。

#!/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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.