Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save palopezv/b234e07945c06ba001981566517f4de6 to your computer and use it in GitHub Desktop.

Select an option

Save palopezv/b234e07945c06ba001981566517f4de6 to your computer and use it in GitHub Desktop.
Converts a Type 1 font into a OpenType-CFF font
# Copyright 2023 Adobe, Inc. All Rights Reserved.
# Author: Miguel Sousa
"""
Converts a Type 1 font into a OpenType-CFF font.
"""
import argparse
from fontTools.agl import toUnicode
from fontTools.fontBuilder import FontBuilder
from fontTools.misc.cliTools import makeOutputFileName
from fontTools.pens.basePen import NullPen
from fontTools.pens.t2CharStringPen import T2CharStringPen
from fontTools.t1Lib import T1Font
def convert_font(input_path):
t1 = T1Font(input_path)
t1.parse()
# Collect 'name' table strings
font_name = t1.font.get('FontName', '')
font_info = t1.font.get('FontInfo', {})
full_name = font_info.get('FullName', '')
font_version = font_info.get('version', '')
name_strings = dict(
familyName=font_info.get('FamilyName', ''),
styleName=font_info.get('Weight', ''),
fullName=full_name,
psName=font_name,
version=f"Version {font_version}",
uniqueFontIdentifier=f"{font_version};{font_name}",
)
# Collect glyph names
encoding = t1.font.get('Encoding')
char_names = t1.font.get('CharStrings')
gnames = []
for gname in encoding:
if gname not in gnames:
gnames.append(gname)
for gname in char_names:
if gname not in gnames:
gnames.append(gname)
# Infer 'cmap' table values from glyph names
cmap = {}
for gname in gnames:
char = toUnicode(gname)
if char:
cmap[ord(char)] = gname
# Collect charstrings and advance widths
char_strings = {}
adv_widths = {}
gset = t1.getGlyphSet()
npen = NullPen()
for gname in gnames:
glyph = gset[gname]
glyph.draw(npen)
gwidth = round(glyph.width)
adv_widths[gname] = gwidth
t2pen = T2CharStringPen(gwidth, None)
glyph.draw(t2pen)
cs = t2pen.getCharString()
char_strings[gname] = cs
fb = FontBuilder(1000, isTTF=False)
fb.setupGlyphOrder(gnames)
fb.setupCharacterMap(cmap)
fb.setupCFF(font_name, {"FullName": full_name}, char_strings, {})
lsb = {}
for gname, cs in char_strings.items():
xmin = 0
gbbox = cs.calcBounds(None)
if gbbox:
xmin, *_ = gbbox
lsb[gname] = xmin
metrics = {
gname: (adv_width, lsb[gname])
for gname, adv_width in adv_widths.items()
}
fb.setupHorizontalMetrics(metrics)
fb.setupHorizontalHeader(ascent=824, descent=-200)
fb.setupNameTable(name_strings, mac=False)
fb.setupOS2(sTypoAscender=824, usWinAscent=824, usWinDescent=200)
fb.setupPost()
save_path = makeOutputFileName(input_path, extension='.otf')
fb.save(save_path)
def main(args=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('input_path', help='path to Type 1 font file')
opts = parser.parse_args(args)
convert_font(opts.input_path)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment