mf2ff mf2ff是使用Fontforge的Python API从Metafont代码创建向量字体的工具。
它基于一个概念,即metafont如何与矢量字体生成器一起工作,而无需绕点图跟踪,如下所示,在MF2VEC概念部分中所述。 mf2ff是迄今为止此概念的唯一实现,也是第一个,也是第一个。
在下面,您将在如何设置以及如何使用它方面找到一些帮助。
该工具尚未经过彻底的测试,但是支持大多数常见的metafont命令。除了填充和绘画外,还支持Kerning和一些结扎命令。请查看下面列出的限制。
mf2ffmf2ff的当前局限性您需要安装fontforge和metafont以使用mf2ff 。
您可能会遇到运行mf2ff脚本的问题。一个问题可能是您需要使用Fontforge模块运行Python 3。以下是有关如何使其工作的一些技巧。我不能保证这对您的系统有效,但是您应该尝试一下。
在不同的操作系统或系统配置上,下面的提示不起作用,请检查您是否使用Python和Fontforge的Python模块:
ffpython , python3 , python )。检查版本信息是否指出您正在运行Python 3 。import fontforge应无误。fontforge.font()不应引起错误。如果仅在某些目录中起作用,则应检查PATH或PYTHONPATH变量。对于临时访问Fontforge的Python版本ffpython ,Fontforge带有批处理文件:
C:Program Files (x86)FontForgeBuilds ),并执行fontforge-console.bat ,因为Windows的set命令命令仅在当前命令提示中更改PATH变量,因此,Ffpython仅在patch文件中执行命令提示中的每个位置可用ffpython。对于永久访问,您需要永久编辑路径变量:
environment variables并打开Edit the system environment variables 。单击Environment variables ,并编辑用户帐户的PATH变量,或者如果您需要在多个用户帐户上访问ffpython则该系统。现在,将fontforge的路径(例如C:Program Files (x86)FontForgeBuildsbin ,请注意bin !)。ffpython ,您应该能够使用ffpython path/to/mf2ff.py ...要轻松访问到处的mf2ff脚本,请执行以下操作:
mf2ff的路径添加到PYTHONPATH变量。如果还没有PYTHONPATH变量,请将其添加到列表中。ffpython -m mf2ff ...在新命令提示会话中运行mf2ff 。在此示例中使用了Ubuntu。
一些存储库将Fontforge的旧版本带有Python 2支持。您可能需要从来源构建Fontforge:
sudo apt install libjpeg-dev libtiff5-dev libpng-dev libfreetype6-dev libgif-dev libgtk-3-dev libxml2-dev libpango1.0-dev libcairo2-dev libspiro-dev libuninameslist-dev python3-dev ninja-build cmake build-essentialsudo apt install gitgit clone https://github.com/fontforge/fontforge 。这将创建一个fontforge/目录。fontforge/ Directory内部的单独目录:cd fontforge; mkdir build; cd buildcmake -GNinja ..ninjasudo ninja install注意:如果您对此过程有问题,请检查Fontfore的文档。
要轻松访问Fontforge的Python模块,请将其添加到您的PythonPath中:
~/.profile文件的末尾: export PYTHONPATH=$PYTHONPATH:/path/to/fontforge/ ,其中/path/to/fontforge/ Directory是通过将fontforge与git cloning fontforge创建的,例如$HOME/fontforge 。python3 path/to/mf2ff.py ...注意:根据系统的配置,您需要键入python而不是python3运行Python 3。
要轻松地访问到处的mf2ff脚本,请将其位置添加到PythonPath变量:
~/.profile文件的末尾: export PYTHONPATH=$PYTHONPATH:/path/to/mf2ff/ ,其中/path/to/mf2ff/ Directory是您放置mf2ff.py文件的一个,例如$HOME/mf2ff/mf2ff 。python3 -m mf2ff ...轻松运行mf2ff 。注意:取决于您使用的杂物,重新启动而不是重新启动可能就足够了。
下面的解决方案使用自制。这样,python也可以访问fontforge:
brew install fontforge 。python3 path/to/mf2ff.py ...注意:根据系统的配置,您需要键入python而不是python3运行Python 3。
要轻松地访问到处的mf2ff脚本,请将其位置添加到PYTHONPATH变量:
PYTHONPATH=$PYTHONPATH:/path/to/mf2ff/ 。zsh 。在您的主目录中,创建或修改文件.zshenv 。bash 。在您的主目录中,创建或修改文件.bash_profile 。tcsh 。在您的主目录中,创建或修改tcsh Shell的相应文件。python3 -m mf2ff ...在新的Shell Sessions中运行mf2ff 。 默认情况下, mf2ff将生成一个样条字体数据库(.sfd)文件。您可以使用选项-ttf / mf2ff.options['ttf'] = True或-otf / mf2ff.options['otf'] = True直接生成字体。
默认情况下, mf2ff不会进行太多清理,因为您可能想手动刷新字形。您可以使用选项-cull-at-shipout / mf2ff.options['cull-at-shipout'] = True或-remove-artifacts / mf2ff.options['remove-artifacts'] = True以执行一些自动清理。请注意,作为字形定义一部分的cull命令可能会导致cull-at-shipout选项不会对某些字形进行任何进一步的更改。
请查看下面列出的限制。
MF2VEC概念的主要思想是使Metafont将字形的几何形状重定向到另一个程序(如果是mf2ff则此程序是Fontforge),而不是使用它们来生成位图字体。这是可能的,因为Metafont内部使用了相同的几何描述,该描述随后在vector Font Files(Bézier曲线)中需要。
一些替代方案将Bézier曲线转换为栅格图形,然后回到Bézier曲线。通过直接使用几何形状,不会丢失信息。
由于使用metafont而不是其他工具(例如Metapost)来读取.mf文件,因此可以使用未修改的metafont代码文件,不仅可以使用几何形状,而且还可以使用字符编码,盒子大小,kerning和结扎信息等。没有手动rework将其运送到矢量字体。
信息的拦截是通过重新定义metafont命令来完成的。由于Metafont在运行时无法与其他程序进行交互,因此需要将.mf文件的解释和字体的生成需要及时分开。因此,Metafont将用于生成位图图形的信息保存在Metafont的日志文件中。重新定义了Metafont的命令,以便Metafont在其日志文件中写入几何和字体属性。一旦Metafont处理了Metafont文件的所有命令,就会从日志文件中读取信息,并处理以创建字体然后从日志文件中删除以保持清晰。
这种方法的想法在2018年10月提出。要检查实用性在Python中立即实现了实施,并逐渐扩大了支持命令的范围。当初始测试表明该想法有效时,决定将mf2ff提供给其他感兴趣的用户。这是自2019年3月以来发生的。经过一些改进和错误修复,开发暂停了几年。由于社区的反馈, mf2ff开发于2023年7月继续进行。
基本思想
该概念基于重新定义基本的metafont命令。它们的定义方式使信息metafont通常用于创建位图字体的信息写入日志文件中。随后,将读取此日志文件,并将指令传递给从其生成向量字体的程序。例如, mf2ff将Fontforge用于此目的。之后,从日志文件中删除了修改后的Metafont命令添加的信息,以使其清晰。
下图用mf2ff作为示例说明了该概念。
┌──────────┐
│ font.mf │
└──────────┘
v
┌──────────┐ ┌───────────┐
│ │ > │ METAFONT │
│ │ └───────────┘
│ │ v
│ │ ┌───────────┐
│ mf2ff │ < │ font.log │
│ │ └───────────┘
│ │
│ │ ┌───────────┐
│ │ > │ FontForge │
└──────────┘ └───────────┘
v v
┌──────────┐ ┌─────────────────────┐
│ font.log │ │ font.ttf / font.otf │
└──────────┘ └─────────────────────┘
简单示例
将以下代码添加到metafont文件中会导致metafont不fill轮廓c ,而是将操作写入日志文件:
def fill expr c =
message "fill"; show c;
enddef;
METAFONT完成处理该文件后,脚本分析了日志文件,并知道有一个fill命令,并且知道要填充的轮廓。可以将此信息传递到字体处理程序中,以将其添加到字形中。
实际上,这个过程要复杂得多。为了能够处理不基于普通Metafont的Metafont文件,需要重新定义诸如addto而不是fill之类的命令。但是那些addto命令更为复杂。它们还构成了其他普通的元法命令(如unfill ,( un ) draw ,( un ) drawdot和erase的基础。这些命令扩展到几个关键字,将执行这些不同操作所需的不同信息的不同部分( addto , also , contour , doublepath ,with pen, withpen , withweight )分开。
另一个挑战是结肠在条件和循环中。这些结构也可以出现在任何其他命令中,即使在使用结肠作为分离器( ligtable和fontdimen )的命令中也可以出现,因此:必须像其他关键字一样重新定义以将信息输出到日志文件。在这些命令中,需要在结肠的不同重新定义之间进行复杂的切换。
除此之外,即使Metafont文件中有消息命令与Metafont Primitives的重新定义无关,也需要实现一个过程,以使其易于找到日志文件中的所有命令。这些不应被解释为字体生成的信息。因此,日志文件中写入的所有信息都需要包含在特殊关键字中,这些关键字不太可能在Metafont文件的消息命令中使用。
Metafont自1977年以来由De Knuth开发,是一个程序,该程序从用Metafont语言编写的文件中生成位图字体。位图字体的缺点是它们在放大倍率下变得模糊。 Metafont的开发是为了使打印机的特定分辨率生成单独的字体。如今,矢量字体是标准的,在放大方面没有此问题。因此,它们更适合在显示器上使用。此外,它们可以与每台打印机一起使用,而无需任何限制。
除了此处介绍的mf2ff的MF2VEC方法外,还有以下用于将metafont文件转换为矢量字体的脚本:
| 姓名 | 方法 |
|---|---|
| metatype1 | Metapost |
| MF2PT1 | Metapost |
| mftrace | 位图跟踪 |
| Textrace | 位图跟踪 |
在这种情况下,Metapost意味着程序Metapost用于将Metafont文件的每个字符转换为向量图形。之后,将向量图形组合在一起以获取向量字体。该方法的缺点是,Metapost只能处理Metafont语言的一部分。
位图跟踪意味着Metafont首先生成位图字体。在一个单独的程序中,每个字形的位图都被追踪,然后将其放在一起以获取矢量字体。
每种方法都有特定的缺点。请查看以下比较以获取更多详细信息。
在下表中,显示了可用脚本的比较,以将metafont文件转换为向量字体。
| 特征 | metafont | mf2ff | metatype1 | MF2PT1 | mftrace | Textrace |
|---|---|---|---|---|---|---|
| 脚本写在 | - | Python 3 | 珀尔 | 珀尔 | Python 2 | 珀尔 |
| Metafont文件处理 | metafont | metafont | Metapost | Metapost | metafont | metafont |
| 随后的处理 | - | fontforge | 尴尬 / t1asm | T1asm | Autotrace或Potrace / T1ASM | Autotrace |
| 输出格式 | GF / TFM | ✅TTF,OTF,SFD | ? PFB | ? PFB | ✅afm / pfa / pfb / ttf / svg | ? PFB |
| 产出质量 | 位图 | ✅矢量图 | ✅矢量图 | ✅矢量图 | ?跟踪位图 | ?跟踪位图 |
| 重新定义非原始剂 /需要非原始剂 | ✅不 | ✅不 | 是的 | 是的 | ✅不 | ✅不 |
| Unicode支持 | 不 | ✅是的 | ❔ | 不 | 不 | 不 |
| 支持笔命令 | ✅是的 | ?有限的 | 不 | ?有限的 | ✅是的 | ✅是的 |
| 支持结扎和kerning命令 | ✅是的 | ?有限的 | ❔ | ❔ | ❔ | 不 |
| 支持可变字体 | 不 | 不,可能将来 | 不 | 不 | ❔ | 不 |
以下是使用mf2ff创建的一些示例。在Fontforge显示时,显示出大纲和填充字符。请注意,结果还不是完美的。
计算机现代字体的某些字形尚未正确处理,即Capital S的中间部分和sloped_serif中的小写字母。

![]() | ![]() | ![]() |
左侧的图像是通过停用cull命令而创建的。
在MetafontBook的第124-126页上介绍的有程式化的海岸红木埃尔·帕洛阿尔托(El Palo Alto)。在左版本中,将激活选项cull-at-shipout 。由于后备箱和最高分支共享一个曲线点,因此当前的实现在那里导致错误的结果。
![]() | ![]() | ![]() | ![]() |
该徽标,该徽标在第138页的MetafontBook。在左版本中,将激活选项cull-at-shipout 。在两种情况下,填充徽标都是相同的。
![]() | ![]() | ![]() |
mf2ff的当前局限性由于mf2ff仍在开发且未经彻底的测试中,因此有一些局限性。他们可能会在以后的更新中得到解决。
如果特定的限制阻止您的项目退缩,请打开问题,以便将来的更新可以集中在用户的需求上。
penrazor (请参见danker_bend_symbol示例),fontforge:“中风宽度不能为零”penspeck的使用会引起警告,但在某些情况下,输出似乎还可以。cull命令的支持是有限的。: ,, :: , kern , skipto以及结扎运算符=: |=: , =:|和|=:|得到支持。操作员中的可ligtable命令忽略> 。此外,操作员||:不支持。charlist和extensible命令。picture关键字,以将图片变量初始化为Fontforge矢量层。由于Metafont使用布尔表达式中的变量声明和类型测试的类型关键字,因此picture关键字不能用于测试变量是否为类型picture 。makepen和makepath类的命令无效。笔和路径不能使用布尔表达中的pen或path区分。有一个选项is_type引入is_pen或is_path ,这可能有助于您解决此问题。ligtable和fontdimenmf2ff需要重新定义结肠( : 。 if ...( elseif )...( end )... fi和 /或for / forsuffixes / forever ... endfor在使用自己的语法中使用结肠的命令内部,即ligtable fontdimen这可能会引起多个嵌套的问题。charlist且extensible有几件事可能会有所帮助。请记住,我100%不了解它们:
/usr/local/lib/python3/dist-packages到您的$PYTHONPATHexport PYTHONPATH=$PYTHONPATH:/usr/local/lib/python3/dist-packages to〜 ~/.profile )/usr/local/lib/python3.4/site-packages到Python的路径