1*e1fe3e4aSElliott Hughes#!/usr/bin/env python3 2*e1fe3e4aSElliott Hughes 3*e1fe3e4aSElliott Hughesimport argparse 4*e1fe3e4aSElliott Hughesimport logging 5*e1fe3e4aSElliott Hughesimport os 6*e1fe3e4aSElliott Hughesimport sys 7*e1fe3e4aSElliott Hughes 8*e1fe3e4aSElliott Hughesfrom fontTools.pens.cu2quPen import Cu2QuPen 9*e1fe3e4aSElliott Hughesfrom fontTools import configLogger 10*e1fe3e4aSElliott Hughesfrom fontTools.misc.cliTools import makeOutputFileName 11*e1fe3e4aSElliott Hughesfrom fontTools.pens.ttGlyphPen import TTGlyphPen 12*e1fe3e4aSElliott Hughesfrom fontTools.ttLib import TTFont, newTable 13*e1fe3e4aSElliott Hughes 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hugheslog = logging.getLogger() 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott Hughes# default approximation error, measured in UPEM 18*e1fe3e4aSElliott HughesMAX_ERR = 1.0 19*e1fe3e4aSElliott Hughes 20*e1fe3e4aSElliott Hughes# default 'post' table format 21*e1fe3e4aSElliott HughesPOST_FORMAT = 2.0 22*e1fe3e4aSElliott Hughes 23*e1fe3e4aSElliott Hughes# assuming the input contours' direction is correctly set (counter-clockwise), 24*e1fe3e4aSElliott Hughes# we just flip it to clockwise 25*e1fe3e4aSElliott HughesREVERSE_DIRECTION = True 26*e1fe3e4aSElliott Hughes 27*e1fe3e4aSElliott Hughes 28*e1fe3e4aSElliott Hughesdef glyphs_to_quadratic(glyphs, max_err=MAX_ERR, reverse_direction=REVERSE_DIRECTION): 29*e1fe3e4aSElliott Hughes quadGlyphs = {} 30*e1fe3e4aSElliott Hughes for gname in glyphs.keys(): 31*e1fe3e4aSElliott Hughes glyph = glyphs[gname] 32*e1fe3e4aSElliott Hughes ttPen = TTGlyphPen(glyphs) 33*e1fe3e4aSElliott Hughes cu2quPen = Cu2QuPen(ttPen, max_err, reverse_direction=reverse_direction) 34*e1fe3e4aSElliott Hughes glyph.draw(cu2quPen) 35*e1fe3e4aSElliott Hughes quadGlyphs[gname] = ttPen.glyph() 36*e1fe3e4aSElliott Hughes return quadGlyphs 37*e1fe3e4aSElliott Hughes 38*e1fe3e4aSElliott Hughes 39*e1fe3e4aSElliott Hughesdef update_hmtx(ttFont, glyf): 40*e1fe3e4aSElliott Hughes hmtx = ttFont["hmtx"] 41*e1fe3e4aSElliott Hughes for glyphName, glyph in glyf.glyphs.items(): 42*e1fe3e4aSElliott Hughes if hasattr(glyph, "xMin"): 43*e1fe3e4aSElliott Hughes hmtx[glyphName] = (hmtx[glyphName][0], glyph.xMin) 44*e1fe3e4aSElliott Hughes 45*e1fe3e4aSElliott Hughes 46*e1fe3e4aSElliott Hughesdef otf_to_ttf(ttFont, post_format=POST_FORMAT, **kwargs): 47*e1fe3e4aSElliott Hughes assert ttFont.sfntVersion == "OTTO" 48*e1fe3e4aSElliott Hughes assert "CFF " in ttFont 49*e1fe3e4aSElliott Hughes 50*e1fe3e4aSElliott Hughes glyphOrder = ttFont.getGlyphOrder() 51*e1fe3e4aSElliott Hughes 52*e1fe3e4aSElliott Hughes ttFont["loca"] = newTable("loca") 53*e1fe3e4aSElliott Hughes ttFont["glyf"] = glyf = newTable("glyf") 54*e1fe3e4aSElliott Hughes glyf.glyphOrder = glyphOrder 55*e1fe3e4aSElliott Hughes glyf.glyphs = glyphs_to_quadratic(ttFont.getGlyphSet(), **kwargs) 56*e1fe3e4aSElliott Hughes del ttFont["CFF "] 57*e1fe3e4aSElliott Hughes glyf.compile(ttFont) 58*e1fe3e4aSElliott Hughes update_hmtx(ttFont, glyf) 59*e1fe3e4aSElliott Hughes 60*e1fe3e4aSElliott Hughes ttFont["maxp"] = maxp = newTable("maxp") 61*e1fe3e4aSElliott Hughes maxp.tableVersion = 0x00010000 62*e1fe3e4aSElliott Hughes maxp.maxZones = 1 63*e1fe3e4aSElliott Hughes maxp.maxTwilightPoints = 0 64*e1fe3e4aSElliott Hughes maxp.maxStorage = 0 65*e1fe3e4aSElliott Hughes maxp.maxFunctionDefs = 0 66*e1fe3e4aSElliott Hughes maxp.maxInstructionDefs = 0 67*e1fe3e4aSElliott Hughes maxp.maxStackElements = 0 68*e1fe3e4aSElliott Hughes maxp.maxSizeOfInstructions = 0 69*e1fe3e4aSElliott Hughes maxp.maxComponentElements = max( 70*e1fe3e4aSElliott Hughes len(g.components if hasattr(g, "components") else []) 71*e1fe3e4aSElliott Hughes for g in glyf.glyphs.values() 72*e1fe3e4aSElliott Hughes ) 73*e1fe3e4aSElliott Hughes maxp.compile(ttFont) 74*e1fe3e4aSElliott Hughes 75*e1fe3e4aSElliott Hughes post = ttFont["post"] 76*e1fe3e4aSElliott Hughes post.formatType = post_format 77*e1fe3e4aSElliott Hughes post.extraNames = [] 78*e1fe3e4aSElliott Hughes post.mapping = {} 79*e1fe3e4aSElliott Hughes post.glyphOrder = glyphOrder 80*e1fe3e4aSElliott Hughes try: 81*e1fe3e4aSElliott Hughes post.compile(ttFont) 82*e1fe3e4aSElliott Hughes except OverflowError: 83*e1fe3e4aSElliott Hughes post.formatType = 3 84*e1fe3e4aSElliott Hughes log.warning("Dropping glyph names, they do not fit in 'post' table.") 85*e1fe3e4aSElliott Hughes 86*e1fe3e4aSElliott Hughes ttFont.sfntVersion = "\000\001\000\000" 87*e1fe3e4aSElliott Hughes 88*e1fe3e4aSElliott Hughes 89*e1fe3e4aSElliott Hughesdef main(args=None): 90*e1fe3e4aSElliott Hughes configLogger(logger=log) 91*e1fe3e4aSElliott Hughes 92*e1fe3e4aSElliott Hughes parser = argparse.ArgumentParser() 93*e1fe3e4aSElliott Hughes parser.add_argument("input", nargs="+", metavar="INPUT") 94*e1fe3e4aSElliott Hughes parser.add_argument("-o", "--output") 95*e1fe3e4aSElliott Hughes parser.add_argument("-e", "--max-error", type=float, default=MAX_ERR) 96*e1fe3e4aSElliott Hughes parser.add_argument("--post-format", type=float, default=POST_FORMAT) 97*e1fe3e4aSElliott Hughes parser.add_argument( 98*e1fe3e4aSElliott Hughes "--keep-direction", dest="reverse_direction", action="store_false" 99*e1fe3e4aSElliott Hughes ) 100*e1fe3e4aSElliott Hughes parser.add_argument("--face-index", type=int, default=0) 101*e1fe3e4aSElliott Hughes parser.add_argument("--overwrite", action="store_true") 102*e1fe3e4aSElliott Hughes options = parser.parse_args(args) 103*e1fe3e4aSElliott Hughes 104*e1fe3e4aSElliott Hughes if options.output and len(options.input) > 1: 105*e1fe3e4aSElliott Hughes if not os.path.isdir(options.output): 106*e1fe3e4aSElliott Hughes parser.error( 107*e1fe3e4aSElliott Hughes "-o/--output option must be a directory when " 108*e1fe3e4aSElliott Hughes "processing multiple fonts" 109*e1fe3e4aSElliott Hughes ) 110*e1fe3e4aSElliott Hughes 111*e1fe3e4aSElliott Hughes for path in options.input: 112*e1fe3e4aSElliott Hughes if options.output and not os.path.isdir(options.output): 113*e1fe3e4aSElliott Hughes output = options.output 114*e1fe3e4aSElliott Hughes else: 115*e1fe3e4aSElliott Hughes output = makeOutputFileName( 116*e1fe3e4aSElliott Hughes path, 117*e1fe3e4aSElliott Hughes outputDir=options.output, 118*e1fe3e4aSElliott Hughes extension=".ttf", 119*e1fe3e4aSElliott Hughes overWrite=options.overwrite, 120*e1fe3e4aSElliott Hughes ) 121*e1fe3e4aSElliott Hughes 122*e1fe3e4aSElliott Hughes font = TTFont(path, fontNumber=options.face_index) 123*e1fe3e4aSElliott Hughes otf_to_ttf( 124*e1fe3e4aSElliott Hughes font, 125*e1fe3e4aSElliott Hughes post_format=options.post_format, 126*e1fe3e4aSElliott Hughes max_err=options.max_error, 127*e1fe3e4aSElliott Hughes reverse_direction=options.reverse_direction, 128*e1fe3e4aSElliott Hughes ) 129*e1fe3e4aSElliott Hughes font.save(output) 130*e1fe3e4aSElliott Hughes 131*e1fe3e4aSElliott Hughes 132*e1fe3e4aSElliott Hughesif __name__ == "__main__": 133*e1fe3e4aSElliott Hughes sys.exit(main()) 134