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