#!/usr/bin/env python3 import argparse import logging import os import sys from fontTools.pens.cu2quPen import Cu2QuPen from fontTools import configLogger from fontTools.misc.cliTools import makeOutputFileName from fontTools.pens.ttGlyphPen import TTGlyphPen from fontTools.ttLib import TTFont, newTable log = logging.getLogger() # default approximation error, measured in UPEM MAX_ERR = 1.0 # default 'post' table format POST_FORMAT = 2.0 # assuming the input contours' direction is correctly set (counter-clockwise), # we just flip it to clockwise REVERSE_DIRECTION = True def glyphs_to_quadratic( glyphs, max_err=MAX_ERR, reverse_direction=REVERSE_DIRECTION): quadGlyphs = {} for gname in glyphs.keys(): glyph = glyphs[gname] ttPen = TTGlyphPen(glyphs) cu2quPen = Cu2QuPen(ttPen, max_err, reverse_direction=reverse_direction) glyph.draw(cu2quPen) quadGlyphs[gname] = ttPen.glyph() return quadGlyphs def update_hmtx(ttFont, glyf): hmtx = ttFont["hmtx"] for glyphName, glyph in glyf.glyphs.items(): if hasattr(glyph, 'xMin'): hmtx[glyphName] = (hmtx[glyphName][0], glyph.xMin) def otf_to_ttf(ttFont, post_format=POST_FORMAT, **kwargs): assert ttFont.sfntVersion == "OTTO" assert "CFF " in ttFont glyphOrder = ttFont.getGlyphOrder() ttFont["loca"] = newTable("loca") ttFont["glyf"] = glyf = newTable("glyf") glyf.glyphOrder = glyphOrder glyf.glyphs = glyphs_to_quadratic(ttFont.getGlyphSet(), **kwargs) del ttFont["CFF "] glyf.compile(ttFont) update_hmtx(ttFont, glyf) ttFont["maxp"] = maxp = newTable("maxp") maxp.tableVersion = 0x00010000 maxp.maxZones = 1 maxp.maxTwilightPoints = 0 maxp.maxStorage = 0 maxp.maxFunctionDefs = 0 maxp.maxInstructionDefs = 0 maxp.maxStackElements = 0 maxp.maxSizeOfInstructions = 0 maxp.maxComponentElements = max( len(g.components if hasattr(g, 'components') else []) for g in glyf.glyphs.values()) maxp.compile(ttFont) post = ttFont["post"] post.formatType = post_format post.extraNames = [] post.mapping = {} post.glyphOrder = glyphOrder try: post.compile(ttFont) except OverflowError: post.formatType = 3 log.warning("Dropping glyph names, they do not fit in 'post' table.") ttFont.sfntVersion = "\000\001\000\000" def main(args=None): configLogger(logger=log) parser = argparse.ArgumentParser() parser.add_argument("input", nargs='+', metavar="INPUT") parser.add_argument("-o", "--output") parser.add_argument("-e", "--max-error", type=float, default=MAX_ERR) parser.add_argument("--post-format", type=float, default=POST_FORMAT) parser.add_argument( "--keep-direction", dest='reverse_direction', action='store_false') parser.add_argument("--face-index", type=int, default=0) parser.add_argument("--overwrite", action='store_true') options = parser.parse_args(args) if options.output and len(options.input) > 1: if not os.path.isdir(options.output): parser.error("-o/--output option must be a directory when " "processing multiple fonts") for path in options.input: if options.output and not os.path.isdir(options.output): output = options.output else: output = makeOutputFileName(path, outputDir=options.output, extension='.ttf', overWrite=options.overwrite) font = TTFont(path, fontNumber=options.face_index) otf_to_ttf(font, post_format=options.post_format, max_err=options.max_error, reverse_direction=options.reverse_direction) font.save(output) if __name__ == "__main__": sys.exit(main())