
“好了?你搞定了吗?!”
在回答这个问题之前,如果你错过了上下文,请查看我之前的博客的最后几行…保证你只需要不到30秒就能了解整个问题!
通过这篇简短的文章,我打算谈谈我们做了什么以及为什么我们做了这些。XD
鸵鸟算法#
听起来熟悉吗?还记得操作系统(OS)吗?这是我当时逃课现在后悔的几门核心计算机科学课程之一。(╥﹏╥)
如果你不知道什么是鸵鸟算法,可以查看维基百科页面,上面有2行解释…但我猜你们大多数人不会点击它XD,所以这里就简单解释一下
鸵鸟算法是一种通过“把头埋在沙子里假装没有问题”来忽略潜在问题的策略。
需要注意的一点是:当允许问题发生比试图防止它更具成本效益时,就会使用它。
正如你现在可能猜到的那样,我们最终得到了一个不太干净的 API(稍后详细介绍)。
问题是什么?#
问题最高级别的概述是
❌ fontTools -> buffer -> ttconv_with_buffer
✅ fontTools -> buffer -> tempfile -> ttconv_with_file
第一种方法产生了损坏的输出,但第二种方法运行良好。这里需要注意的一点是,方法1在将文件读取与解析数据分离方面更好。
- fontTools 为我们处理 Type42 子集,而 ttconv 处理嵌入。
ttconv_with_buffer
是对原始ttconv_with_file
的修改;它允许输入文件缓冲区而不是文件路径。
你可能会想说
“好吧,
ttconv_with_buffer
肯定修改错误了,这很明显。”
从逻辑上讲,是的。ttconv
被设计为使用文件路径而不是文件对象(缓冲区),并且修改一个编写于1998年的代码库比我们预期的要痛苦得多。
到了某个时刻,我的一个导师决定用 Python 实现所有内容!#
他确实这么做了,但是将它投入生产/或修复ttconv
嵌入的工作量⋙ 仅仅继续使用第二种方法。那个该死的鸵鸟确实帮助我们摆脱了调试地狱。🙃
字体回退 - 初始步骤#
最后,我们开始着手夏季的第二个子目标:字体回退!
为了说明目前的情况
- 用户要求 Matplotlib 使用某些字体系列,由
matplotlib.rcParams["font-family"] = ["list", "of", "font", "families"]
- 此列表用于搜索用户系统上可用的字体。
- 但是,在 Matplotlib 的当前(和先前)版本中
一旦通过迭代字体系列找到字体,所有文本都将由且仅由该字体呈现。
你可以立即看到这种方法的问题;对每个字符使用相同的字体将不会呈现该字体中不存在的任何字形,而是会输出一个称为“豆腐”的方形矩形(阅读第一行此处)。
这正是第一个里程碑!也就是说,解析字体系列的整个列表以获得多字体界面的中间表示。
不要崩溃,有很多东西岌岌可危!#
想象一下,如果你有能力更改 Python 标准库的内部函数,而无需咨询任何人。假设你想通过挂钩和更改来编写一个解决方案,例如通过返回更改str("dumb")
的实现
>>> str("dumb")
["d", "u", "m", "b"]
非常“愚蠢”,对吧?xD
对于你的用例,它可能运行良好,但它也意味着破坏整个 Python 用户群的工作流程,更不用说依赖于原始功能的 1000000+ 库了。
同样,Matplotlib 有一个称为findfont(prop: str)
的公共 API,它在给定字符串(或FontProperties)时,会找到与系统中给定属性最匹配的字体。
它在整个库中使用,以及在其他多个地方使用,包括下游库。由于我当时很天真,所以我更改了此函数签名并提交了PR。🥲
与我的导师就此进行了深入的讨论,很快提出了另一个 PR,它根本没有触及findfont
API。
最后需要指出的一点是:即使我们完成了第一个里程碑,我们也还没有完成,因为这仅仅是解析整个列表以获取多个字体…
我们仍然需要将库的内部实现从字体优先迁移到文本优先!
但那是以后的事情,现在: