如何使用Python将一组图像转换成`.ttf`字体文件?

4

场景

我有一组名为 32.png,..,126.png 的手写字母图片,涵盖了ASCII可打印字符中的数字,我想将它们转换成字体文件,比如 .ttf 文件,这样我就可以用它来输入(基本)LaTeX字母。

通过查看项目描述fonttools文档,我还没有找到如何用python将这些图像转换为.ttf字体文件的方法。

看起来我可以将.png图像转换为.svg格式,因为fonttools通常用于字体向量,但我没有找到输出字体文件的方法。因此,我想问:

问题

如何在python中将一组图片(.png.svg格式)转换为.ttf字体文件?

尝试

  1. 在Windows上安装FontForge并将../FontForgeBuilds/bin文件夹添加到路径后,Anaconda无法识别fontforge模块,因为它会抛出错误:

ModuleNotFoundError: No module named 'fontforge'.svg文件转换为.ttf文件的脚本中。这个名为svgs2ttf的脚本是通过命令调用的:python svgs2ttf.py examples/example.json

import sys
import os.path
import json
import fontforge
#python svgs2ttf.py examples/example.json

IMPORT_OPTIONS = ('removeoverlap', 'correctdir')

try:
    unicode
except NameError:
    unicode = str

def loadConfig(filename='font.json'):
    with open(filename) as f:
        return json.load(f)

def setProperties(font, config):
    props = config['props']
    lang = props.pop('lang', 'English (US)')
    family = props.pop('family', None)
    style = props.pop('style', 'Regular')
    props['encoding'] = props.get('encoding', 'UnicodeFull')
    if family is not None:
        font.familyname = family
        font.fontname = family + '-' + style
        font.fullname = family + ' ' + style
    for k, v in config['props'].items():
        if hasattr(font, k):
            if isinstance(v, list):
                v = tuple(v)
            setattr(font, k, v)
        else:
            font.appendSFNTName(lang, k, v)
    for t in config.get('sfnt_names', []):
        font.appendSFNTName(str(t[0]), str(t[1]), unicode(t[2]))

def addGlyphs(font, config):
    for k, v in config['glyphs'].items():
        g = font.createMappedChar(int(k, 0))
        # Get outlines
        src = '%s.svg' % k
        if not isinstance(v, dict):
            v = {'src': v or src}
        src = '%s%s%s' % (config.get('input', '.'), os.path.sep, v.pop('src', src))
        g.importOutlines(src, IMPORT_OPTIONS)
        g.removeOverlap()
        # Copy attributes
        for k2, v2 in v.items():
            if hasattr(g, k2):
                if isinstance(v2, list):
                    v2 = tuple(v2)
                setattr(g, k2, v2)

def main(config_file):
    config = loadConfig(config_file)
    os.chdir(os.path.dirname(config_file) or '.')
    font = fontforge.font()
    setProperties(font, config)
    addGlyphs(font, config)
    for outfile in config['output']:
        sys.stderr.write('Generating %s...\n' % outfile)
        font.generate(outfile)

if __name__ == '__main__':
    if len(sys.argv) > 1:
        main(sys.argv[1])
    else:
        sys.stderr.write("\nUsage: %s something.json\n" % sys.argv[0] )


1
https://dev59.com/QF0Z5IYBdhLWcg3wdQIy 可能是重复问题。 - Razetime
1个回答

6

FontForge不是Python模块,而是独立的软件。因此,与其从Python脚本调用FontForge,不如从fontforge可执行文件中调用Python。由于我想要从Python脚本中创建.ttf格式的字体,所以我编写了一个名为execute.py的额外Python脚本,该脚本执行一个cmd命令,该命令执行FontForge,并执行Python svgs2ttf脚本。

execute.py包含以下内容:

import os
os.system('cmd /k "fontforge -lang=py -script svgs2ttf examples/example.json"')

svgs2ttf 脚本是从 这个仓库 修改而来的,包含:

# one can run  this script with:
#fontforge -lang=py -script svgs2ttf examples/example.json

import sys
import os.path
import json
import fontforge

IMPORT_OPTIONS = ('removeoverlap', 'correctdir')

try:
    unicode
except NameError:
    unicode = str

def loadConfig(filename='font.json'):
    with open(filename) as f:
        return json.load(f)

def setProperties(font, config):
    props = config['props']
    lang = props.pop('lang', 'English (US)')
    family = props.pop('family', None)
    style = props.pop('style', 'Regular')
    props['encoding'] = props.get('encoding', 'UnicodeFull')
    if family is not None:
        font.familyname = family
        font.fontname = family + '-' + style
        font.fullname = family + ' ' + style
    for k, v in config['props'].items():
        if hasattr(font, k):
            if isinstance(v, list):
                v = tuple(v)
            setattr(font, k, v)
        else:
            font.appendSFNTName(lang, k, v)
    for t in config.get('sfnt_names', []):
        font.appendSFNTName(str(t[0]), str(t[1]), unicode(t[2]))

def addGlyphs(font, config):
    for k, v in config['glyphs'].items():
        g = font.createMappedChar(int(k, 0))
        # Get outlines
        src = '%s.svg' % k
        if not isinstance(v, dict):
            v = {'src': v or src}
        src = '%s%s%s' % (config.get('input', '.'), os.path.sep, v.pop('src', src))
        g.importOutlines(src, IMPORT_OPTIONS)
        g.removeOverlap()
        # Copy attributes
        for k2, v2 in v.items():
            if hasattr(g, k2):
                if isinstance(v2, list):
                    v2 = tuple(v2)
                setattr(g, k2, v2)

def main(config_file):
    config = loadConfig(config_file)
    os.chdir(os.path.dirname(config_file) or '.')
    font = fontforge.font()
    setProperties(font, config)
    addGlyphs(font, config)
    for outfile in config['output']:
        sys.stderr.write('Generating %s...\n' % outfile)
        font.generate(outfile)

if __name__ == '__main__':
    if len(sys.argv) > 1:
        main(sys.argv[1])
    else:
        sys.stderr.write("\nUsage: %s something.json\n" % sys.argv[0] )

它可以进行改进,以转换比存储库中的 examples 文件夹中的 ab 符号更多的符号图像,以生成字体。

针对评论,这里是 example.json 的内容:

{ "props":
  { "ascent": 96
  , "descent": 32
  , "em": 128
  , "encoding": "UnicodeFull"
  , "lang": "English (US)"
  , "family": "Example"
  , "style": "Regular"
  , "familyname": "Example"
  , "fontname": "Example-Regular"
  , "fullname": "Example Regular"
  }
, "glyphs":
  { "0x3f": { "src": "question.svg", "width": 128 }
  , "0xab": { "src": "back.svg", "width": 128 }
  , "0x263a": ""
  , "0x2723": "overlap-test.svg"
  , "0x1f304": "outline-test.svg"
  }
, "sfnt_names":
  [ ["English (US)", "Copyright", "Copyright (c) 2014 by Nobody"]
  , ["English (US)", "Family", "Example"]
  , ["English (US)", "SubFamily", "Regular"]
  , ["English (US)", "UniqueID", "Example 2014-12-04"]
  , ["English (US)", "Fullname", "Example Regular"]
  , ["English (US)", "Version", "Version 001.000"]
  , ["English (US)", "PostScriptName", "Example-Regular"]
  ]
, "input": "."
, "output": [ "example.ttf", "example.svg", "example.woff" ]
, "# vim: set et sw=2 ts=2 sts=2:": false
}


2
你能给我展示一下 example.json 文件里面的内容吗? - Ann Zen
感谢您提供详细的代码和解释。然而,当我运行这段代码时,我只得到一个空的SVG输出,并且当我按下字符键时,生成的TTF文件也会产生黑色的空白区域。请问有什么帮助吗? - Ammar Ul Hassan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接