我如何从Linux上的TrueType或嵌入式OpenType字体中提取支持的Unicode字符列表?
是否有工具或库可用于处理.ttf或.eot文件并构建字体提供的代码点列表(例如U+0123,U+1234等)?
这里是一种使用fontTools Python库的方法(您可以使用类似于pip install fonttools
的东西进行安装):
#!/usr/bin/env python
from itertools import chain
import sys
from fontTools.ttLib import TTFont
from fontTools.unicode import Unicode
with TTFont(
sys.argv[1], 0, allowVID=0, ignoreDecompileErrors=True, fontNumber=-1
) as ttf:
chars = chain.from_iterable(
[y + (Unicode[y[0]],) for y in x.cmap.items()] for x in ttf["cmap"].tables
)
if len(sys.argv) == 2: # print all code points
for c in chars:
print(c)
elif len(sys.argv) >= 3: # search code points / characters
code_points = {c[0] for c in chars}
for i in sys.argv[2:]:
code_point = int(i) # search code point
#code_point = ord(i) # search character
print(Unicode[code_point])
print(code_point in code_points)
脚本以字体路径为参数,可选搜索的码点 / 字符。$ python checkfont.py /usr/share/fonts/**/DejaVuSans.ttf
(32, 'space', 'SPACE')
(33, 'exclam', 'EXCLAMATION MARK')
(34, 'quotedbl', 'QUOTATION MARK')
…
$ python checkfont.py /usr/share/fonts/**/DejaVuSans.ttf 65 12622 # a ㅎ
LATIN CAPITAL LETTER A
True
HANGUL LETTER HIEUH
False
int(sys.argv[2], 0)
可能会因为“无效的字面量”而失败,因为一个人可能想要找到特殊字符。应该使用 ord(sys.argv[2].decode('string_escape').decode('utf-8'))
来代替。 - Skippy le Grand Gouroupython-fontconfig
的这个脚本似乎要快得多:http://unix.stackexchange.com/a/268286/26952 - Skippy le Grand Gourousys.argv[1]
传递给 TTFont()
吗? - Martin Tournoijchars = list(y + (Unicode[y[0]],) for x in ttf["cmap"].tables for y in x.cmap.items())
替换原有代码:
chars = chain.from_iterable([y + (Unicode[y[0]],) for y in x.cmap.items()] for x in ttf["cmap"].tables)
- Ismael EL ATIFIX程序xfd可以实现这个功能。要查看“DejaVu Sans Mono”字体的所有字符,请运行:
xfd -fa "DejaVu Sans Mono"
在Debian/Ubuntu中,它包含在x11-utils软件包中,在Fedora/RHEL中是xorg-x11-apps,在Arch Linux中是xorg-xfd。
6x13
)进行类似的操作? - domssonfontconfig
命令可以将字形列表输出为紧凑的范围列表,例如:
$ fc-match --format='%{charset}\n' OpenSans
20-7e a0-17f 192 1a0-1a1 1af-1b0 1f0 1fa-1ff 218-21b 237 2bc 2c6-2c7 2c9
2d8-2dd 2f3 300-301 303 309 30f 323 384-38a 38c 38e-3a1 3a3-3ce 3d1-3d2 3d6
400-486 488-513 1e00-1e01 1e3e-1e3f 1e80-1e85 1ea0-1ef9 1f4d 2000-200b
2013-2015 2017-201e 2020-2022 2026 2030 2032-2033 2039-203a 203c 2044 2070
2074-2079 207f 20a3-20a4 20a7 20ab-20ac 2105 2113 2116 2120 2122 2126 212e
215b-215e 2202 2206 220f 2211-2212 221a 221e 222b 2248 2260 2264-2265 25ca
fb00-fb04 feff fffc-fffd
对于一个 .ttf
文件使用 fc-query
命令,对于已安装的字体名称使用 fc-match
。
这可能不需要安装额外的软件包,也不涉及位图转换。
使用命令 fc-match --format='%{file}\n'
来检查是否匹配了正确的字体。
ttx -t cmap -o - /usr/share/fonts/truetype/GentiumPlus-I.ttf | grep 0x2161
返回 <map code="0x2161" name="uni2161"/><!-- ROMAN NUMERAL TWO -->
。可能是FontConfig匹配到了不同的字体。在我安装gentium
之前,fc-match 'Gentium Italic'
返回FreeMono.ttf: "FreeMono" "Regular"
。如果是这样的话,--format=%{charset}
的输出将不会显示您期望的内容。 - Neil Mayhewfc-match --format ='%{file}⇒%{charset} \ n' Gentium:Italic
DTRT,太棒了。 - mirabilosGentium:Italic
而不是Gentium Italic
的好建议,谢谢你。 - Neil Mayhewfc-query my-font.ttf
将为您提供支持的字形图和符合字体配置的所有区域设置映射。这是一个基于 POSIX[1] 的shell脚本,可以通过 fc-match
帮助您以简单易懂的方式打印代码点和字符。Neil Mayhew在他的回答中提到了这个工具(它甚至可以处理多达8位十六进制Unicode):
#!/bin/bash
for range in $(fc-match --format='%{charset}\n' "$1"); do
for n in $(seq "0x${range%-*}" "0x${range#*-}"); do
n_hex=$(printf "%04x" "$n")
# using \U for 5-hex-digits
printf "%-5s\U$n_hex\t" "$n_hex"
count=$((count + 1))
if [ $((count % 10)) = 0 ]; then
printf "\n"
fi
done
done
printf "\n"
fc-match
接受的内容:$ ls-chars "DejaVu Sans"
更新内容:
我了解到子shell非常耗时(脚本中的printf
子shell)。因此,我成功编写了一个改进版本,速度快了5-10倍!
#!/bin/bash
for range in $(fc-match --format='%{charset}\n' "$1"); do
for n in $(seq "0x${range%-*}" "0x${range#*-}"); do
printf "%04x\n" "$n"
done
done | while read -r n_hex; do
count=$((count + 1))
printf "%-5s\U$n_hex\t" "$n_hex"
[ $((count % 10)) = 0 ] && printf "\n"
done
printf "\n"
旧版本:
$ time ls-chars "DejaVu Sans" | wc
592 11269 52740
real 0m2.876s
user 0m2.203s
sys 0m0.888s
$ time ls-chars "DejaVu Sans" | wc
592 11269 52740
real 0m0.399s
user 0m0.446s
sys 0m0.120s
更新结束
示例输出(在我的 st 终端中对齐得更好):
0020 0021 ! 0022 " 0023 # 0024 $ 0025 % 0026 & 0027 ' 0028 ( 0029 )
002a * 002b + 002c , 002d - 002e . 002f / 0030 0 0031 1 0032 2 0033 3
0034 4 0035 5 0036 6 0037 7 0038 8 0039 9 003a : 003b ; 003c < 003d =
003e > 003f ? 0040 @ 0041 A 0042 B 0043 C 0044 D 0045 E 0046 F 0047 G
...
1f61a 1f61b 1f61c 1f61d 1f61e 1f61f 1f620 1f621 1f622 1f623
1f625 1f626 1f627 1f628 1f629 1f62a 1f62b 1f62d 1f62e 1f62f
1f630 1f631 1f632 1f633 1f634 1f635 1f636 1f637 1f638 1f639
1f63a 1f63b 1f63c 1f63d 1f63e 1f63f 1f640 1f643
[1] 看起来在 printf
中使用的 \U
不符合 POSIX 标准?
printf
而不是shell内置的。 - Lu Xuttf/otf字体的字符编码点存储在CMAP
表中。
您可以使用ttx
生成CMAP
表的XML表示形式,详情请参见此处。
您可以运行命令ttx.exe -t cmap MyFont.ttf
,它应该会输出一个名为MyFont.ttx
的文件。在文本编辑器中打开它,它将向您显示字体中找到的所有字符编码。
ttx
是接受答案中提到的fonttools
的一部分。它是一个Python脚本,因此也可在Mac和Linux上使用。 - mivk-o -
参数让ttx
在标准输出中显示输出。例如, ttx -o - -t cmap myfont.ttf
将会把字体文件myfont.ttf
中的cmap
表格内容转储到标准输出。然后,你可以将其用于查看一个给定字符是否定义在给定字体中(例如 $ font ttx -o - -t cmap myfont.ttf | grep '5c81'
)。 - rdrg109ttx -t cmap myfont.ttf
并可能将myfont.ttx
重命名为myfont.xml
以调用Chrome的xml模式后,在Chrome开发工具中查看您的ttx
xml时,可以使用此代码。function codepoint(node) { return Number(node.nodeValue); }
$x('//cmap/*[@platformID="0"]/*/@code').map(codepoint);
fonttools
;如果您在ubuntu系统上,请运行sudo apt-get install fonttools
。)除了 @Oliver Lew 的回答,我还添加了一个选项,可以查询本地字体而不是系统字体:
#!/bin/bash
# If the first argument is a font file, use fc-match instead of fc-query to
# display the font
[[ -f "$1" ]] && fc='fc-query' || fc='fc-match'
for range in $($fc --format='%{charset}\n' "$1"); do
for n in $(seq "0x${range%-*}" "0x${range#*-}"); do
printf "%04x\n" "$n"
done
done | while read -r n_hex; do
count=$((count + 1))
printf "%-5s\U$n_hex\t" "$n_hex"
[ $((count % 10)) = 0 ] && printf "\n"
done
printf "\n"
你可以在Linux上使用Perl的Font::TTF模块来完成这个任务。
fc-list :charset=1234
命令,并仔细检查其输出结果...(对我来说有效,它显示Gentium的字符集为2082但不是2161)。 - mirabilos