You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
3.8 KiB
127 lines
3.8 KiB
#!/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())
|