如何修复 Kindle 自定义字体名称显示问号的问题
前些天小伙伴“预盐”留言提了一个与 Kindle 自定义字体功能相关的问题。他按照《如何使用 Kindle 的原生自定义字体功能》这篇文章提供的步骤,将字体文件放到 Kindle 根目录中的 fonts 文件夹后,在字体选择面板中选择字体时发现,本该显示中文字体名称的地方却出现了如下图所示的一串问号。
▲ 中文字体名称显示问号
此问题的出现可能是字体文件制作不规范导致的,我们可以参考 OpenType 规范(下称“规范”)并利用合适的工具修复此问题。本文提供了一种解决方案,可有效地解决 OpenType 格式(文件扩展名为 .otf、.otc、.ttf 或 .ttc)字体名称在 Kindle 的字体选择面板中无法正确显示的问题。
一、解决思路
OpenType 格式字体文件包含一系列以表格形式呈现的数据,这些数据的类型有很多,具体可查看规范。本文只关注与字体名称(选择字体时看到的字样)相关的元数据信息,即字体的“name”表。
字体的“name”表可以将多种语言的字符串(文本)关联到字体上,比如版权声明、字体名称、字族名称、样式名称等,其目的是为了在不同语言环境的操作系统中显示这些信息的相应语言版本。
如果一个字体的名称没有正确显示就意味着字体文件中的“name”表有问题,为解决这个问题,我们可以先使用工具将其提取出来,然后按照规范进行修正,最后再把修正好的“name”表合并到字体文件中。
二、准备工具
字体文件(即扩展名为 .otf、.otc、.ttf 或 .ttc 的文件)是独立的二进制文件,我们无法直接对其进行编辑,为了能够对其进行我们所需要的修改,必须借助专门的工具或将其转换成人类可读的文本文件。
本文使用的工具是 fontTools,一款基于 Python 的字体处理程序库,其中包含一款名为 ttx 的命令行工具,它可以将字体文件转换成扩展名为 .ttx 的 XML 文本文件,方便我们修改字体的相关信息。
使用 fontTools 需要确保你的操作系统安装版本大于等于 3.6 的 Python。如果你的系统没有安装 Python 或者版本低于 3.6,请前往 Python 官网下载安装(macOS 系统可以通过 Homebrew 安装)。
Python 环境准备好后,可在“终端”或“命令提示符”中输入以下命令安装 fontTools:
pip3 install fonttools
fontTools 安装完成后,可输入如下命令,如果能正常输出版本号就表示安装成功:
ttx --version
三、操作步骤
虽然 ttx 程序可以将整个字体文件转换成 .ttx 文件,也能将 .ttx 文件转换回字体文件,但是如果字体文件较大的话,转换的 .ttx 文件也会很大,这会降低编辑和转换的效率。因此,为了大幅提高效率,我们只需单独提取出字体文件的“name”表进行修改,再利用 ttx 的合并功能将修改后的表合并回字体文件。
为方便展示操作步骤,下面虚构了一个有名称显示问题的字体文件 SampleSong.ttf(在实际操作时将该文件名换成实际的字体文件名即可)。对于步骤中涉及到规范的地方,书伴会做必要的解释。
1、从字体文件中提取出“name”表
要将字体文件中的“name”表单独提取出来,可先切换到字体所在的目录,然后运行如下命令:
ttx -t name SampleSong.ttf
* 提示:如果你处理的是“字体集(Font Collections)”文件(扩展名为 .ttc 或 .otc),需要在命令中指定字体集中单个字体的编号,即在选项 -t
前添加选项 -y
,并在该选项后指定编号。如 ttx -y 0 -t 'name' SampleFonts.ttc
。
默认情况下,提取的“name”表文件名与字体文件名相同,存放位置也与字体文件相同,只是扩展名变成了 .ttx。本例中得到的文件为 SampleSong.ttx,用代码编辑器打开该文件,会看到类似这样的内容:
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.22">
<name>
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
示例宋体
</namerecord>
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
Regular
</namerecord>
<namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
示例宋体 Regular; Version 1.0; 2019-09-27
</namerecord>
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
示例宋体 Regular
</namerecord>
<namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
Version 1.0 September 27, 2019
</namerecord>
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
SampleSong-Regular
</namerecord>
</name>
</ttFont>
这是字体文件中所有的“名称记录(Name Records)”,它由多个 <namerecord>
元素组成,每个元素都含有 nameID
、platformID
、platEncID
和 langID
属性(分别对应着规范中的 nameID、platformID、encodingID 和 languageID),这些属性定义了各元素在字体中的意义。这些属性的含义如下:
- nameID:名称 ID。常用的是 26 个预定义 ID(从 0 到 25),每个 ID 对应一种特定含义。其中 1 和 2 分别对应着“字族名称(Font Family name)”和“子字族名称(Font Subfamily name)”。
- platformID:平台 ID。0 对应 Unicode,1 对应 Macintosh 平台,3 对应 Windows 平台。接下来的两个属性 encodingID 和 languageID 的值均取决于此 ID。本例采用 Windows 平台。
- platEncID:特定平台编码 ID。Windows 平台下常用的编码 ID 为 1(Unicode BMP)。
- langID:语言 ID。Windows 平台下的语言 ID 的值以 16 进制表示,其中美式英文为 0x409,简体中文为 0x804。这个属性是解决问题的关键,它决定了让系统以何种语言解析名称记录元素的内容。
* 提示:“字族名称”也称“系列名称”,即选择字体时显示的名称;“子字族名称”也称“样式名称”,即字重、斜体等字体特性。
名称记录元素的先后顺序取决于这些属性,必须先按平台 ID 排序,再按特定平台编码 ID 排序,接着按语言 ID 排序,最后按名称 ID 排序。这种有序的排列也有助于我们快速辨别某组记录对应何种语言。
了解了这些技术细节之后,我们就能够看出示例“name”表存在的问题,含有简体中文字符串的名称记录,其语言 ID 属性值却是 0x409(即美式英文),显然这会让某些系统(如 Kindle)无法正确解析。
为解决这个问题,就需要修正字体的名称记录中错误的语言 ID,使其与字符串的实际语言相匹配。
2、修正“name”表中错误的语言 ID
修正语言 ID 有两种方法:一种是把所有含有简体中文字符串的名称记录的语言 ID 都更改成 0x804;另一种是在不修改原有名称记录的情况下新增针对简体中文的名称记录,在本例中,只需要添加一项名称 ID 为 1 的名称记录,并将其语言 ID 设为简体中文(如下所示),就足以解决字体名称显示问题了。
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.22">
<name>
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
示例宋体
</namerecord>
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
Regular
</namerecord>
<namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
示例宋体 Regular; Version 1.0; 2019-09-27
</namerecord>
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
示例宋体 Regular
</namerecord>
<namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
Version 1.0 April 25, 2021
</namerecord>
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
SampleSong-Regular
</namerecord>
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x804">
示例宋体
</namerecord>
</name>
</ttFont>
书伴推荐第二种方法。如果你选用第一种方法可能会产生一些副作用。以名称 ID 为 6 的名称记录为例,规范对该记录的建议为:应包含 Macintosh 和 Windows 两个平台的名称记录,且都应将语言 ID 设置为英文。若不小心设为中文,在为 macOS 系统添加字体时,就会遇到字体验证提示表结构错误的情况。
3、将修正的“name”表合并到字体
将字体“name”表中的语言 ID 错误修正之后,即可运行如下命令将“name”表合并回字体文件:
ttx -m SampleSong.ttf SampleSong.ttx
* 提示:如果你要处理的是“字体集(Font Collections)”文件(扩展名为 .ttc 或 .otc),需要注意,由于 ttx 无法直接对字体集文件进行合并操作,因此你需要先使用工具套装 Adobe Font Development Kit for OpenType (AFDKO) 中的 otc2otf 程序将字体集中的单个字体文件全部提取出来,再用 ttx 进行处理,最后用工具套装里面的 otf2ot 程序将重新合并。
命令执行成功后,会生成一个新的字体文件,默认情况下,新字体文件名会在原有文件名的基础上添加一个序号 #1,如 SampleSong#1.ttf(你也可在选项 -m
前添加选项 -o
,并在其后自定义文件名)。
* 提示:在 macOS 系统中,如果字体文件名带有 # 符号,即便字体结构没问题,添加到字体册时也会出现奇怪的“系统验证”错误,无法通过字体的验证。如果你处理的字体文件需要在 macOS 系统中使用,建议删掉字体文件名中的 # 符号。
得到新生成的字体文件后,将其拷贝到 Kindle 中即可查看修正效果,如下所示:
▲ 中文字体名称显示问号修复效果
测试字体时需注意,拷贝字体文件之后,如果电子书处于打开状态,需要先退出回到 Kindle 的首页或图书馆,停上几秒再重新打开,才能让 Kindle 重新加载新拷贝的字体。有时可能需要这样反复重试几次。
至此,自定义字体名称无法在 Kindle 的字体选择面板中正常显示的问题就解决了。文章看起来很长,主要是因为添加了一些规范的描述,简单的说就是先利用 fontTools 里的 ttx 工具从字体文件中提取“name”表,然后并按照规范修正错误,最后将修正的“name”重新合并到字体文件中得到新的字体文件。
© 「书伴」原创文章,转载请注明出处及原文链接:https://bookfere.com/post/899.html
延伸阅读
- 刘亚东:除了那些核心技术,我们还缺什么?
- [网友投稿]《效率脑科学》读书笔记:如何处理自己的情绪?
- [每周一书]《巨婴国》怎样才是一个成熟的个体?
- [每周一书]《最好的决定》那些选择不生育的人
- 如何使用 Kindle 的原生自定义字体功能
- [每周一书]《不公正的胜利》从税收角度讨论不平等
- Calibre 使用教程之电子书繁体字转简体字
- Kindle Voyage 阅读器深度评测(一):第一印象
- 三星版 Kindle 可每月免费领取一本正版电子书
- 通过 Send to Kindle 发送的文档已支持 KFX 增强排版功能
- 为何我会放弃 iPad mini 而换用 Kindle Paperwhite 阅读
- Kindle 中文字体推荐:更换一下字形口味
- [每周一书]《逻辑的引擎》从数理逻辑看计算机发展
- 三二一!Sherry 精选英文分阶阅读系列(一)
- [2019.04.10] Kindle X 咪咕版固件升级至 5.7.2.6
我有个问题,我下载的思源宋体/黑体等包含多字重的ttc文件时,kindle会默认使用extralight字重,并且字体名称会显示日语名称,但是当然不影响显示中文字形。我想问这种情况可以让kindle默认使用regular字重吗?还是说我得每本书自己修改css?
你说的方法我感觉好难。。。有个字体编辑软件叫high-logic font creator,我看了下显示为问号的字体元数据里的名称大部分是有一些特殊符号。我在里面修改了字体属性(识别-字体族那一栏修改了字体名称将特殊符号去掉),保存导出后的字体,我看到元数据里字体名称修改过来了,但是导入KINDLE还是显示为问号 ,我想应该是我哪里没修改到位。请问你能不能研究一下如何使用这个软件解决此问题?这样应该比你说的修正方法更容易理解 适合没有编程经验的小白
用font creator字体编辑软件,把名称显示问号的字体打开,然后菜单栏找到”font”下面属性”properties”, 修改family name就可以,亲测 有效
有些书有些字体某个字显示不出来怎么解决
这是因为字体缺少这个字的字形导致的,如果影响阅读,建议更换字体。
先切换到字体所在的目录,然后运行如下命令,这个能具体说说吗?没看懂,是把字体文件所在的文件地址打开之后,就在哪里运行下列命令,我是直接在cmd的那个命令提示符里运行,之后,结果显示找不到文件。
假设名为 SampleSong.ttf 的字体文件放在 D: 盘的 somewhere 文件夹,可以先运行
cd D:\somewhere
再运行ttx -t name SampleSong.ttf
。或者,也可以在运行命令的时候直接使用字体文件的绝对路径ttx -t name D:\somewhere\SampleSong.ttf
。如果你不知道字体文件的路径,可以直接把文件拖放到命令提示符上,它会自动生成一个绝对路径。现在可以按步骤执行了。但得到的ttx文件,与样例不太一样 ,我按着例子模仿了第二种方法,最后合并得到的文件无法被kindle识别。
测试字体时需注意,拷贝字体文件之后,如果电子书处于打开状态,需要先退出回到 Kindle 的首页或图书馆,停上几秒再重新打开,才能让 Kindle 重新加载新拷贝的字体。有时可能需要这样反复重试几次。
——
Noah 的邮件回复:好的,谢谢书伴。其实真实原因是,我没有将旧文件删除,把新文件和旧文件放在同一个文件夹里font,这样导致kindle只识别了一个文件,新文件因为有后缀#1排在后面,没有识别出来。当时我是想测试看看文件修好没,再删掉旧文件,所以导致了这样的结果。你确定文件是可用的,我猜测了一下(当时没显示出来,我重启了kindle),删掉了旧文件,终于显示成功了。特来向你说明一下。
自定义字体时,例如方正悠宋,发现字体有7个字重,把全部字重都放进去。在kindle 加粗时,发现是直接机械式的加粗字体,而不是匹配到更粗的字重。这种要怎么处理?
自定义字体功能的加粗不会读取字重,如果你想更精细的控制字重,需要自行修改电子书的 CSS 文件。
来了来了,超级感谢,真是名副其实的书伴,直接从源头解决了我的问题,另外说一下在实操中遇到的问题。
安装完成fonttools并检测安装成功后。运行提取ttx文件代码就会显示
“Dumping “新仓耳今楷.ttf” to “新仓耳今楷.ttx”…
No ”name” table found.”。
然后仍然会有ttx文件出现,但是内容只有
最后我采取了暴力的办法,直接把你给的正确代码复制了进去,把名称修改过来,然后进行了合并,问题解决,kindle中显示正确。
但是我再回头对新合并的ttf文件进行提取时,又变成了上边的情况,不过无所谓了,在kindle中不显示名称的问题已经解决了,再次感谢您手把手教我(对于编程和python真的是零基础,只会跟着步骤走)。
好像ttx文件的内容没有显示出来,那我再发一遍
还是没出现,其实就是你给出示例中的头两行和最后一行,中间name开头的每一段都没有
留言会把 XML 代码过滤掉……代码根据你后面留言的描述补上了。
找不到“name”表是因为文中给出的命令在 Windows 命令提示符中执行有点问题(和类 Unix 系统的终端不同,Windows 命令提示符不能正确识别单引号)。你可以直接把“name”的引号去掉(或者将半角单引号换成半角双引号),应该就可以正常执行了:
原来如此,那我明天再试一试
求教一个困扰我很久的问题:为什么kindle的邮箱推送会间歇性失灵
设备:kpw3中亚
版本:长久以来好多版本都这样
推送稳定性完全取决于亚马逊的个人文档服务器,如果你的 Kindle 设备联网正常却无法收到推送,大部分情况下是亚马逊服务器的问题,用户端没有什么可操作的空间。
好的,谢谢释疑。
真的太随机了,偶尔好用,偶尔不好用
推送的文章,格式排版感觉都一般,而且用不了词典,是怎么回事?
如果排版没有通过手工处理,一般都不怎么样。用不了词典有什么具体表现吗?一般情况下,所有电子书都可以使用字典。
表现是只有网络查词的窗口,没有查字典的那个窗口。
用的哪个词典?会不会是你要查的字词字典里不存在。你可以查一下字典里存在的字词,看是否正常。如果还不行的话,可以把查词有问题的电子书发一份到书伴邮箱(页面底部“联系”处获取),书伴实机测试一下。
应该是那本书的问题,我换了另一个版本的书就正常了。