Ensure all fonttools CLI tools have help documentation (#1948)
Note UI change : `fonttools varLib.models` now takes prefixed options `-d` or `-l` instead of guessing the intended feature from the number of arguments. We have a number of command line tools which are somewhat opaque. (varLib.models in particular was very confusing.) This ensures that they all use argparse to have a consistent interface, and all have --help documentation which at least details their parameters, and hopefully therefore gives more of a clue about what they do. Those which use logging have had a command-line logging parameter added.
This commit is contained in:
parent
a114ec2c20
commit
089f24da6b
@ -146,16 +146,30 @@ def optimizeWidths(widths):
|
|||||||
|
|
||||||
return default, nominal
|
return default, nominal
|
||||||
|
|
||||||
def main():
|
def main(args=None):
|
||||||
"""Calculate optimum defaultWidthX/nominalWidthX values"""
|
"""Calculate optimum defaultWidthX/nominalWidthX values"""
|
||||||
for fontfile in sys.argv[1:]:
|
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
"fonttools cffLib.width",
|
||||||
|
description=main.__doc__,
|
||||||
|
)
|
||||||
|
parser.add_argument('inputs', metavar='FILE', type=str, nargs='+',
|
||||||
|
help="Input TTF files")
|
||||||
|
parser.add_argument('-b', '--brute-force', dest="brute", action="store_true",
|
||||||
|
help="Use brute-force approach (VERY slow)")
|
||||||
|
|
||||||
|
args = parser.parse_args(args)
|
||||||
|
|
||||||
|
for fontfile in args.inputs:
|
||||||
font = TTFont(fontfile)
|
font = TTFont(fontfile)
|
||||||
hmtx = font['hmtx']
|
hmtx = font['hmtx']
|
||||||
widths = [m[0] for m in hmtx.metrics.values()]
|
widths = [m[0] for m in hmtx.metrics.values()]
|
||||||
|
if args.brute:
|
||||||
|
default, nominal = optimizeWidthsBruteforce(widths)
|
||||||
|
else:
|
||||||
default, nominal = optimizeWidths(widths)
|
default, nominal = optimizeWidths(widths)
|
||||||
print("glyphs=%d default=%d nominal=%d byteCost=%d" % (len(widths), default, nominal, byteCost(widths, default, nominal)))
|
print("glyphs=%d default=%d nominal=%d byteCost=%d" % (len(widths), default, nominal, byteCost(widths, default, nominal)))
|
||||||
#default, nominal = optimizeWidthsBruteforce(widths)
|
|
||||||
#print("glyphs=%d default=%d nominal=%d byteCost=%d" % (len(widths), default, nominal, byteCost(widths, default, nominal)))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
|
@ -1164,17 +1164,31 @@ def main(args=None, font=None):
|
|||||||
# comment this out to enable debug messages from mtiLib's logger
|
# comment this out to enable debug messages from mtiLib's logger
|
||||||
# log.setLevel(logging.DEBUG)
|
# log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
"fonttools mtiLib",
|
||||||
|
description=main.__doc__,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument('--font', '-f', metavar='FILE', dest="font",
|
||||||
|
help="Input TTF files (used for glyph classes and sorting coverage tables)")
|
||||||
|
parser.add_argument('--table', '-t', metavar='TABLE', dest="tableTag",
|
||||||
|
help="Table to fill (sniffed from input file if not provided)")
|
||||||
|
parser.add_argument('inputs', metavar='FILE', type=str, nargs='+',
|
||||||
|
help="Input FontDame .txt files")
|
||||||
|
|
||||||
|
args = parser.parse_args(args)
|
||||||
|
|
||||||
if font is None:
|
if font is None:
|
||||||
|
if args.font:
|
||||||
|
font = ttLib.TTFont(args.font)
|
||||||
|
else:
|
||||||
font = MockFont()
|
font = MockFont()
|
||||||
|
|
||||||
tableTag = None
|
for f in args.inputs:
|
||||||
if args[0].startswith('-t'):
|
|
||||||
tableTag = args[0][2:]
|
|
||||||
del args[0]
|
|
||||||
for f in args:
|
|
||||||
log.debug("Processing %s", f)
|
log.debug("Processing %s", f)
|
||||||
with open(f, 'rt', encoding="utf-8") as f:
|
with open(f, 'rt', encoding="utf-8") as f:
|
||||||
table = build(f, font, tableTag=tableTag)
|
table = build(f, font, tableTag=args.tableTag)
|
||||||
blob = table.compile(font) # Make sure it compiles
|
blob = table.compile(font) # Make sure it compiles
|
||||||
decompiled = table.__class__()
|
decompiled = table.__class__()
|
||||||
decompiled.decompile(blob, font) # Make sure it decompiles!
|
decompiled.decompile(blob, font) # Make sure it decompiles!
|
||||||
|
@ -1395,6 +1395,17 @@ def main(args=None):
|
|||||||
from fontTools import configLogger
|
from fontTools import configLogger
|
||||||
from fontTools.ttx import makeOutputFileName
|
from fontTools.ttx import makeOutputFileName
|
||||||
|
|
||||||
|
class _HelpAction(argparse._HelpAction):
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
subparsers_actions = [
|
||||||
|
action for action in parser._actions
|
||||||
|
if isinstance(action, argparse._SubParsersAction)]
|
||||||
|
for subparsers_action in subparsers_actions:
|
||||||
|
for choice, subparser in subparsers_action.choices.items():
|
||||||
|
print(subparser.format_help())
|
||||||
|
parser.exit()
|
||||||
|
|
||||||
class _NoGlyfTransformAction(argparse.Action):
|
class _NoGlyfTransformAction(argparse.Action):
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
namespace.transform_tables.difference_update({"glyf", "loca"})
|
namespace.transform_tables.difference_update({"glyf", "loca"})
|
||||||
@ -1405,12 +1416,18 @@ def main(args=None):
|
|||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog="fonttools ttLib.woff2",
|
prog="fonttools ttLib.woff2",
|
||||||
description=main.__doc__
|
description=main.__doc__,
|
||||||
|
add_help = False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
parser.add_argument('-h', '--help', action=_HelpAction,
|
||||||
|
help='show this help message and exit')
|
||||||
|
|
||||||
parser_group = parser.add_subparsers(title="sub-commands")
|
parser_group = parser.add_subparsers(title="sub-commands")
|
||||||
parser_compress = parser_group.add_parser("compress")
|
parser_compress = parser_group.add_parser("compress",
|
||||||
parser_decompress = parser_group.add_parser("decompress")
|
description = "Compress a TTF or OTF font to WOFF2")
|
||||||
|
parser_decompress = parser_group.add_parser("decompress",
|
||||||
|
description = "Decompress a WOFF2 font to OTF")
|
||||||
|
|
||||||
for subparser in (parser_compress, parser_decompress):
|
for subparser in (parser_compress, parser_decompress):
|
||||||
group = subparser.add_mutually_exclusive_group(required=False)
|
group = subparser.add_mutually_exclusive_group(required=False)
|
||||||
|
@ -1011,7 +1011,7 @@ def main(args=None):
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from fontTools import configLogger
|
from fontTools import configLogger
|
||||||
|
|
||||||
parser = ArgumentParser(prog='varLib')
|
parser = ArgumentParser(prog='varLib', description = main.__doc__)
|
||||||
parser.add_argument('designspace')
|
parser.add_argument('designspace')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-o',
|
'-o',
|
||||||
|
@ -157,23 +157,31 @@ def test(glyphsets, glyphs=None, names=None):
|
|||||||
#for x in hist:
|
#for x in hist:
|
||||||
# print(x)
|
# print(x)
|
||||||
|
|
||||||
def main(args):
|
def main(args=None):
|
||||||
"""Test for interpolatability issues between fonts"""
|
"""Test for interpolatability issues between fonts"""
|
||||||
filenames = args
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
"fonttools varLib.interpolatable",
|
||||||
|
description=main.__doc__,
|
||||||
|
)
|
||||||
|
parser.add_argument('inputs', metavar='FILE', type=str, nargs='+',
|
||||||
|
help="Input TTF files")
|
||||||
|
|
||||||
|
args = parser.parse_args(args)
|
||||||
glyphs = None
|
glyphs = None
|
||||||
#glyphs = ['uni08DB', 'uniFD76']
|
#glyphs = ['uni08DB', 'uniFD76']
|
||||||
#glyphs = ['uni08DE', 'uni0034']
|
#glyphs = ['uni08DE', 'uni0034']
|
||||||
#glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina']
|
#glyphs = ['uni08DE', 'uni0034', 'uni0751', 'uni0753', 'uni0754', 'uni08A4', 'uni08A4.fina', 'uni08A5.fina']
|
||||||
|
|
||||||
from os.path import basename
|
from os.path import basename
|
||||||
names = [basename(filename).rsplit('.', 1)[0] for filename in filenames]
|
names = [basename(filename).rsplit('.', 1)[0] for filename in args.inputs]
|
||||||
|
|
||||||
from fontTools.ttLib import TTFont
|
from fontTools.ttLib import TTFont
|
||||||
fonts = [TTFont(filename) for filename in filenames]
|
fonts = [TTFont(filename) for filename in args.inputs]
|
||||||
|
|
||||||
glyphsets = [font.getGlyphSet() for font in fonts]
|
glyphsets = [font.getGlyphSet() for font in fonts]
|
||||||
test(glyphsets, glyphs=glyphs, names=names)
|
test(glyphsets, glyphs=glyphs, names=names)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
import sys
|
import sys
|
||||||
main(sys.argv[1:])
|
main()
|
||||||
|
@ -60,28 +60,40 @@ def interpolate_layout(designspace, loc, master_finder=lambda s:s, mapped=False)
|
|||||||
def main(args=None):
|
def main(args=None):
|
||||||
"""Interpolate GDEF/GPOS/GSUB tables for a point on a designspace"""
|
"""Interpolate GDEF/GPOS/GSUB tables for a point on a designspace"""
|
||||||
from fontTools import configLogger
|
from fontTools import configLogger
|
||||||
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
if args is None:
|
|
||||||
args = sys.argv[1:]
|
|
||||||
|
|
||||||
designspace_filename = args[0]
|
parser = argparse.ArgumentParser(
|
||||||
locargs = args[1:]
|
"fonttools varLib.interpolate_layout",
|
||||||
outfile = os.path.splitext(designspace_filename)[0] + '-instance.ttf'
|
description=main.__doc__,
|
||||||
|
)
|
||||||
|
parser.add_argument('designspace_filename', metavar='DESIGNSPACE',
|
||||||
|
help="Input TTF files")
|
||||||
|
parser.add_argument('locations', metavar='LOCATION', type=str, nargs='+',
|
||||||
|
help="Axis locations (e.g. wdth=120")
|
||||||
|
parser.add_argument('-o', '--output', metavar='OUTPUT',
|
||||||
|
help="Output font file (defaults to <designspacename>-instance.ttf)")
|
||||||
|
parser.add_argument('-l', '--loglevel', metavar='LEVEL', default="INFO",
|
||||||
|
help="Logging level (defaults to INFO)")
|
||||||
|
|
||||||
# TODO: allow user to configure logging via command-line options
|
|
||||||
configLogger(level="INFO")
|
args = parser.parse_args(args)
|
||||||
|
|
||||||
|
if not args.output:
|
||||||
|
args.output = os.path.splitext(args.designspace_filename)[0] + '-instance.ttf'
|
||||||
|
|
||||||
|
configLogger(level=args.loglevel)
|
||||||
|
|
||||||
finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable').replace('.ufo', '.ttf')
|
finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable').replace('.ufo', '.ttf')
|
||||||
|
|
||||||
loc = {}
|
loc = {}
|
||||||
for arg in locargs:
|
for arg in args.locations:
|
||||||
tag,val = arg.split('=')
|
tag,val = arg.split('=')
|
||||||
loc[tag] = float(val)
|
loc[tag] = float(val)
|
||||||
|
|
||||||
font = interpolate_layout(designspace_filename, loc, finder)
|
font = interpolate_layout(args.designspace_filename, loc, finder)
|
||||||
log.info("Saving font %s", outfile)
|
log.info("Saving font %s", args.output)
|
||||||
font.save(outfile)
|
font.save(args.output)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -422,27 +422,32 @@ def piecewiseLinearMap(v, mapping):
|
|||||||
return va + (vb - va) * (v - a) / (b - a)
|
return va + (vb - va) * (v - a) / (b - a)
|
||||||
|
|
||||||
|
|
||||||
def main(args):
|
def main(args=None):
|
||||||
"""Normalize locations on a given designspace"""
|
"""Normalize locations on a given designspace"""
|
||||||
from fontTools import configLogger
|
from fontTools import configLogger
|
||||||
|
import argparse
|
||||||
|
|
||||||
args = args[1:]
|
parser = argparse.ArgumentParser(
|
||||||
|
"fonttools varLib.models",
|
||||||
|
description=main.__doc__,
|
||||||
|
)
|
||||||
|
parser.add_argument('--loglevel', metavar='LEVEL', default="INFO",
|
||||||
|
help="Logging level (defaults to INFO)")
|
||||||
|
|
||||||
# TODO: allow user to configure logging via command-line options
|
group = parser.add_mutually_exclusive_group(required=True)
|
||||||
configLogger(level="INFO")
|
group.add_argument('-d', '--designspace',metavar="DESIGNSPACE",type=str)
|
||||||
|
group.add_argument('-l', '--locations', metavar='LOCATION', nargs='+',
|
||||||
|
help="Master locations as comma-separate coordinates. One must be all zeros.")
|
||||||
|
|
||||||
if len(args) < 1:
|
args = parser.parse_args(args)
|
||||||
print("usage: fonttools varLib.models source.designspace", file=sys.stderr)
|
|
||||||
print(" or")
|
|
||||||
print("usage: fonttools varLib.models location1 location2 ...", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
configLogger(level=args.loglevel)
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
if len(args) == 1 and args[0].endswith('.designspace'):
|
if args.designspacefile:
|
||||||
from fontTools.designspaceLib import DesignSpaceDocument
|
from fontTools.designspaceLib import DesignSpaceDocument
|
||||||
doc = DesignSpaceDocument()
|
doc = DesignSpaceDocument()
|
||||||
doc.read(args[0])
|
doc.read(args.designspacefile)
|
||||||
locs = [s.location for s in doc.sources]
|
locs = [s.location for s in doc.sources]
|
||||||
print("Original locations:")
|
print("Original locations:")
|
||||||
pprint(locs)
|
pprint(locs)
|
||||||
@ -452,7 +457,7 @@ def main(args):
|
|||||||
pprint(locs)
|
pprint(locs)
|
||||||
else:
|
else:
|
||||||
axes = [chr(c) for c in range(ord('A'), ord('Z')+1)]
|
axes = [chr(c) for c in range(ord('A'), ord('Z')+1)]
|
||||||
locs = [dict(zip(axes, (float(v) for v in s.split(',')))) for s in args]
|
locs = [dict(zip(axes, (float(v) for v in s.split(',')))) for s in args.locations]
|
||||||
|
|
||||||
model = VariationModel(locs)
|
model = VariationModel(locs)
|
||||||
print("Sorted locations:")
|
print("Sorted locations:")
|
||||||
@ -464,6 +469,6 @@ if __name__ == "__main__":
|
|||||||
import doctest, sys
|
import doctest, sys
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
sys.exit(main(sys.argv))
|
sys.exit(main())
|
||||||
|
|
||||||
sys.exit(doctest.testmod().failed)
|
sys.exit(doctest.testmod().failed)
|
||||||
|
@ -551,7 +551,7 @@ def main(args=None):
|
|||||||
from fontTools.ttLib import TTFont
|
from fontTools.ttLib import TTFont
|
||||||
from fontTools.ttLib.tables.otBase import OTTableWriter
|
from fontTools.ttLib.tables.otBase import OTTableWriter
|
||||||
|
|
||||||
parser = ArgumentParser(prog='varLib.varStore')
|
parser = ArgumentParser(prog='varLib.varStore', description= main.__doc__)
|
||||||
parser.add_argument('fontfile')
|
parser.add_argument('fontfile')
|
||||||
parser.add_argument('outfile', nargs='?')
|
parser.add_argument('outfile', nargs='?')
|
||||||
options = parser.parse_args(args)
|
options = parser.parse_args(args)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user