Created
August 20, 2023 17:28
-
-
Save miguelsousa/66ee9504039a8b64c605defa316516c1 to your computer and use it in GitHub Desktop.
Converts a Type 1 font into a OpenType-CFF font
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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