def main(args=None): from fontTools import configLogger import sys if args is None: args = sys.argv[1:] designspace_filename = args[0] locargs = args[1:] outfile = os.path.splitext(designspace_filename)[0] + '-instance.ttf' # TODO: allow user to configure logging via command-line options configLogger(level="INFO") finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable' ).replace('.ufo', '.ttf') loc = {} for arg in locargs: tag, val = arg.split('=') loc[tag] = float(val) font = interpolate_layout(designspace_filename, loc, finder) log.info("Saving font %s", outfile) font.save(outfile)
def main(args=None): from fontTools import configLogger if args is None: args = sys.argv[1:] # configure the library logger (for >= WARNING) configLogger() # comment this out to enable debug messages from logger # log.setLevel(logging.DEBUG) if len(args) < 1: print("usage: fonttools varLib.plot source.designspace", file=sys.stderr) print(" or") print("usage: fonttools varLib.plot location1 location2 ...", file=sys.stderr) sys.exit(1) fig = pyplot.figure() if len(args) == 1 and args[0].endswith('.designspace'): doc = DesignSpaceDocument() doc.read(args[0]) plotDocument(doc, fig) else: 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] plotLocationsSurfaces(locs, fig) pyplot.show()
def main(args=None): from fontTools import configLogger if args is None: args = sys.argv[1:] # configure the library logger (for >= WARNING) configLogger() # comment this out to enable debug messages from logger # log.setLevel(logging.DEBUG) if len(args) < 1: print("usage: fonttools varLib.plot source.designspace", file=sys.stderr) print(" or") print("usage: fonttools varLib.plot location1 location2 ...", file=sys.stderr) sys.exit(1) fig = pyplot.figure() fig.set_tight_layout(True) if len(args) == 1 and args[0].endswith('.designspace'): doc = DesignSpaceDocument() doc.read(args[0]) plotDocument(doc, fig) else: 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 ] plotLocations(locs, fig) pyplot.show()
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') parser.add_argument('-o', metavar='OUTPUTFILE', dest='outfile', default=None, help='output file') parser.add_argument('-x', metavar='TAG', dest='exclude', action='append', default=[], help='exclude table') parser.add_argument('--disable-iup', dest='optimize', action='store_false', help='do not perform IUP optimization') parser.add_argument( '--master-finder', default='master_ttf_interpolatable/{stem}.ttf', help=('templated string used for finding binary font ' 'files given the source file names defined in the ' 'designspace document. The following special strings ' 'are defined: {fullname} is the absolute source file ' 'name; {basename} is the file name without its ' 'directory; {stem} is the basename without the file ' 'extension; {ext} is the source file extension; ' '{dirname} is the directory of the absolute file ' 'name. The default value is "%(default)s".')) logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument("-v", "--verbose", action="store_true", help="Run more verbosely.") logging_group.add_argument("-q", "--quiet", action="store_true", help="Turn verbosity off.") options = parser.parse_args(args) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) designspace_filename = options.designspace finder = MasterFinder(options.master_finder) outfile = options.outfile if outfile is None: outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' vf, _, _ = build(designspace_filename, finder, exclude=options.exclude, optimize=options.optimize) log.info("Saving variation font %s", outfile) vf.save(outfile)
def main(args): from fontTools import configLogger args = args[1:] # TODO: allow user to configure logging via command-line options configLogger(level="INFO") if len(args) < 1: 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) from pprint import pprint if len(args) == 1 and args[0].endswith('.designspace'): from fontTools.designspaceLib import DesignSpaceDocument doc = DesignSpaceDocument() doc.read(args[0]) locs = [s.location for s in doc.sources] print("Original locations:") pprint(locs) doc.normalize() print("Normalized locations:") pprint(locs) else: 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] model = VariationModel(locs) print("Sorted locations:") pprint(model.locations) print("Supports:") pprint(model.supports)
def main(args=None): from fontTools import configLogger if args is None: args = sys.argv[1:] try: jobs, options = parseOptions(args) except getopt.GetoptError as e: usage() print("ERROR:", e, file=sys.stderr) sys.exit(2) configLogger(level=options.logLevel) try: process(jobs, options) except KeyboardInterrupt: log.error("(Cancelled.)") sys.exit(1) except SystemExit: if sys.platform == "win32": waitForKeyPress() raise except TTLibError as e: log.error(e) sys.exit(1) except: log.exception('Unhandled exception has occurred') if sys.platform == "win32": waitForKeyPress() sys.exit(1)
def main(args): from fontTools import configLogger # configure the library logger (for >= WARNING) configLogger() # comment this out to enable debug messages from mtiLib's logger # log.setLevel(logging.DEBUG) font = MockFont() tableTag = None if args[0].startswith('-t'): tableTag = args[0][2:] del args[0] for f in args: log.debug("Processing %s", f) table = build(open(f, 'rt', encoding="utf-8"), font, tableTag=tableTag) blob = table.compile(font) # Make sure it compiles decompiled = table.__class__() decompiled.decompile(blob, font) # Make sure it decompiles! #continue from fontTools.misc import xmlWriter tag = table.tableTag writer = xmlWriter.XMLWriter(sys.stdout) writer.begintag(tag) writer.newline() table.toXML(writer, font) #decompiled.toXML(writer, font) writer.endtag(tag) writer.newline()
def main(args=None): """Merge multiple fonts into one""" from fontTools import configLogger if args is None: args = sys.argv[1:] options = Options() args = options.parse_opts(args) if len(args) < 1: print("usage: pyftmerge font...", file=sys.stderr) return 1 configLogger(level=logging.INFO if options.verbose else logging.WARNING) if options.timing: timer.logger.setLevel(logging.DEBUG) else: timer.logger.disabled = True merger = Merger(options=options) font = merger.merge(args) outfile = 'merged.ttf' with timer("compile and save font"): font.save(outfile)
def main(args=None): from fontTools import configLogger if args is None: args = sys.argv[1:] try: jobs, options = parseOptions(args) except getopt.GetoptError as e: usage() print("ERROR:", e, file=sys.stderr) sys.exit(2) configLogger(level=options.logLevel) try: process(jobs, options) except KeyboardInterrupt: log.error("(Cancelled.)") sys.exit(1) except SystemExit: if sys.platform == "win32": waitForKeyPress() else: raise except TTLibError as e: log.error(e) sys.exit(1) except: log.exception('Unhandled exception has occurred') if sys.platform == "win32": waitForKeyPress() sys.exit(1)
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)
def main(args=None): """Convert OpenType fonts to XML and back""" from fontTools import configLogger if args is None: args = sys.argv[1:] try: jobs, options = parseOptions(args) except getopt.GetoptError as e: print("%s\nERROR: %s" % (__doc__, e), file=sys.stderr) sys.exit(2) configLogger(level=options.logLevel) try: process(jobs, options) except KeyboardInterrupt: log.error("(Cancelled.)") sys.exit(1) except SystemExit: raise except TTLibError as e: log.error(e) sys.exit(1) except: log.exception('Unhandled exception has occurred') sys.exit(1)
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)
def main(): parser = argparse.ArgumentParser(description="Merge Aref Ruqaa fonts.") parser.add_argument("file1", metavar="FILE", help="input font to process") parser.add_argument("file2", metavar="FILE", help="input font to process") parser.add_argument("--out-file", metavar="FILE", help="output font to write", required=True) args = parser.parse_args() configLogger(level=logging.ERROR) merger = merge.Merger() font = merger.merge([args.file1, args.file2]) # Drop incomplete Greek support. unicodes = set(font.getBestCmap().keys()) - set(range(0x0370, 0x03FF)) options = subset.Options() options.set( layout_features="*", layout_scripts=["arab", "latn", "DFLT"], name_IDs="*", name_languages="*", notdef_outline=True, glyph_names=False, recalc_average_width=True, ) subsetter = subset.Subsetter(options=options) subsetter.populate(unicodes=unicodes) subsetter.subset(font) font.save(args.out_file)
def main(args=None): parser = argparse.ArgumentParser( description="Use fontTools to compile OpenType feature files (*.fea).") parser.add_argument( "input_fea", metavar="FEATURES", help="Path to the feature file") parser.add_argument( "input_font", metavar="INPUT_FONT", help="Path to the input font") parser.add_argument( "-o", "--output", dest="output_font", metavar="OUTPUT_FONT", help="Path to the output font.") parser.add_argument( "-t", "--tables", metavar="TABLE_TAG", choices=Builder.supportedTables, nargs='+', help="Specify the table(s) to be built.") parser.add_argument( "-v", "--verbose", help="increase the logger verbosity. Multiple -v " "options are allowed.", action="count", default=0) options = parser.parse_args(args) levels = ["WARNING", "INFO", "DEBUG"] configLogger(level=levels[min(len(levels) - 1, options.verbose)]) output_font = options.output_font or makeOutputFileName(options.input_font) log.info("Compiling features to '%s'" % (output_font)) font = TTFont(options.input_font) addOpenTypeFeatures(font, options.input_fea, tables=options.tables) font.save(output_font)
def main(args=None): """Merge multiple fonts into one""" from fontTools import configLogger if args is None: args = sys.argv[1:] options = Options() args = options.parse_opts(args, ignore_unknown=['output-file']) outfile = 'merged.ttf' fontfiles = [] for g in args: if g.startswith('--output-file='): outfile = g[14:] continue fontfiles.append(g) if len(args) < 1: print("usage: pyftmerge font...", file=sys.stderr) return 1 configLogger(level=logging.INFO if options.verbose else logging.WARNING) if options.timing: timer.logger.setLevel(logging.DEBUG) else: timer.logger.disabled = True merger = Merger(options=options) font = merger.merge(fontfiles) with timer("compile and save font"): font.save(outfile)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') parser.add_argument('-o', metavar='OUTPUTFILE', dest='outfile', default=None, help='output file') parser.add_argument('-x', metavar='TAG', dest='exclude', action='append', default=[], help='exclude table') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") designspace_filename = options.designspace finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable' ).replace('.ufo', '.ttf') outfile = options.outfile if outfile is None: outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' vf, model, master_ttfs = build(designspace_filename, finder, exclude=options.exclude) log.info("Saving variation font %s", outfile) vf.save(outfile)
def main(args=None): from fontTools import configLogger if args is None: import sys args = sys.argv[1:] varfilename = args[0] locargs = args[1:] outfile = os.path.splitext(varfilename)[0] + '-instance.ttf' # TODO Allow to specify logging verbosity as command line option configLogger(level=logging.INFO) loc = {} for arg in locargs: tag, val = arg.split('=') assert len(tag) <= 4 loc[tag.ljust(4)] = float(val) log.info("Location: %s", loc) log.info("Loading variable font") varfont = TTFont(varfilename) instantiateVariableFont(varfont, loc, inplace=True) log.info("Saving instance font %s", outfile) varfont.save(outfile)
def main(args=None, font=None): """Convert a FontDame OTL file to TTX XML. Writes XML output to stdout. Args: args: Command line arguments (``--font``, ``--table``, input files). """ import sys from fontTools import configLogger from fontTools.misc.testTools import MockFont if args is None: args = sys.argv[1:] # configure the library logger (for >= WARNING) configLogger() # comment this out to enable debug messages from mtiLib's logger # 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 args.font: font = ttLib.TTFont(args.font) else: font = MockFont() for f in args.inputs: log.debug("Processing %s", f) with open(f, 'rt', encoding="utf-8") as f: table = build(f, font, tableTag=args.tableTag) blob = table.compile(font) # Make sure it compiles decompiled = table.__class__() decompiled.decompile(blob, font) # Make sure it decompiles! #continue from fontTools.misc import xmlWriter tag = table.tableTag writer = xmlWriter.XMLWriter(sys.stdout) writer.begintag(tag) writer.newline() #table.toXML(writer, font) decompiled.toXML(writer, font) writer.endtag(tag) writer.newline()
def main(args=None): from fontTools import configLogger import argparse parser = argparse.ArgumentParser("fonttools varLib.mutator", description="Instantiate a variable font") parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.") parser.add_argument( "locargs", metavar="AXIS=LOC", nargs="*", help="List of space separated locations. A location consist in " "the name of a variation axis, followed by '=' and a number. E.g.: " " wght=700 wdth=80. The default is the location of the base master.") parser.add_argument( "-o", "--output", metavar="OUTPUT.ttf", default=None, help="Output instance TTF file (default: INPUT-instance.ttf).") logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument("-v", "--verbose", action="store_true", help="Run more verbosely.") logging_group.add_argument("-q", "--quiet", action="store_true", help="Turn verbosity off.") options = parser.parse_args(args) varfilename = options.input outfile = (os.path.splitext(varfilename)[0] + '-instance.ttf' if not options.output else options.output) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) loc = {} for arg in options.locargs: try: tag, val = arg.split('=') assert len(tag) <= 4 loc[tag.ljust(4)] = float(val) except (ValueError, AssertionError): parser.error("invalid location argument format: %r" % arg) log.info("Location: %s", loc) log.info("Loading variable font") varfont = TTFont(varfilename) instantiateVariableFont(varfont, loc, inplace=True) log.info("Saving instance font %s", outfile) varfont.save(outfile)
def parseArgs(args): """Parse argv. Returns: 3-tuple (infile, outfile, axis_limits) axis_limits is either a Dict[str, int], for pinning variation axes to specific coordinates along those axes; or a Dict[str, Tuple(int, int)], meaning limit this axis to min/max range. Axes locations are in user-space coordinates, as defined in the "fvar" table. """ from fontTools import configLogger import argparse parser = argparse.ArgumentParser( "fonttools varLib.partialInstancer", description="Partially instantiate a variable font", ) parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.") parser.add_argument( "locargs", metavar="AXIS=LOC", nargs="*", help="List of space separated locations. A location consist in " "the tag of a variation axis, followed by '=' and a number or" "number:number. E.g.: wdth=100 or wght=75.0:125.0", ) parser.add_argument( "-o", "--output", metavar="OUTPUT.ttf", default=None, help="Output instance TTF file (default: INPUT-instance.ttf).", ) logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument( "-v", "--verbose", action="store_true", help="Run more verbosely." ) logging_group.add_argument( "-q", "--quiet", action="store_true", help="Turn verbosity off." ) options = parser.parse_args(args) infile = options.input outfile = ( os.path.splitext(infile)[0] + "-instance.ttf" if not options.output else options.output ) configLogger( level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO") ) axis_limits = parseLimits(options.locargs) if len(axis_limits) != len(options.locargs): raise ValueError("Specified multiple limits for the same axis") return (infile, outfile, axis_limits)
def main(args=None): """Normalize locations on a given designspace""" from fontTools import configLogger import argparse parser = argparse.ArgumentParser( "fonttools varLib.models", description=main.__doc__, ) parser.add_argument( "--loglevel", metavar="LEVEL", default="INFO", help="Logging level (defaults to INFO)", ) group = parser.add_mutually_exclusive_group(required=True) 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.", ) args = parser.parse_args(args) configLogger(level=args.loglevel) from pprint import pprint if args.designspace: from fontTools.designspaceLib import DesignSpaceDocument doc = DesignSpaceDocument() doc.read(args.designspace) locs = [s.location for s in doc.sources] print("Original locations:") pprint(locs) doc.normalize() print("Normalized locations:") locs = [s.location for s in doc.sources] pprint(locs) else: 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.locations ] model = VariationModel(locs) print("Sorted locations:") pprint(model.locations) print("Supports:") pprint(model.supports)
def main(args=None): from fontTools import configLogger import argparse parser = argparse.ArgumentParser( "fonttools varLib.mutator", description="Instantiate a variable font") parser.add_argument( "input", metavar="INPUT.ttf", help="Input variable TTF file.") parser.add_argument( "locargs", metavar="AXIS=LOC", nargs="*", help="List of space separated locations. A location consist in " "the name of a variation axis, followed by '=' and a number. E.g.: " " wght=700 wdth=80. The default is the location of the base master.") parser.add_argument( "-o", "--output", metavar="OUTPUT.ttf", default=None, help="Output instance TTF file (default: INPUT-instance.ttf).") logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument( "-v", "--verbose", action="store_true", help="Run more verbosely.") logging_group.add_argument( "-q", "--quiet", action="store_true", help="Turn verbosity off.") parser.add_argument( "--no-overlap", dest="overlap", action="store_false", help="Don't set OVERLAP_SIMPLE/OVERLAP_COMPOUND glyf flags." ) options = parser.parse_args(args) varfilename = options.input outfile = ( os.path.splitext(varfilename)[0] + '-instance.ttf' if not options.output else options.output) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) loc = {} for arg in options.locargs: try: tag, val = arg.split('=') assert len(tag) <= 4 loc[tag.ljust(4)] = float(val) except (ValueError, AssertionError): parser.error("invalid location argument format: %r" % arg) log.info("Location: %s", loc) log.info("Loading variable font") varfont = TTFont(varfilename) instantiateVariableFont(varfont, loc, inplace=True, overlap=options.overlap) log.info("Saving instance font %s", outfile) varfont.save(outfile)
def main(args=None): """Optimize the layout tables of an existing font.""" from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog="otlLib.optimize", description=main.__doc__, formatter_class=RawTextHelpFormatter) parser.add_argument("font") parser.add_argument("-o", metavar="OUTPUTFILE", dest="outfile", default=None, help="output file") parser.add_argument( "--gpos-compact-mode", help=dedent(f"""\ GPOS Lookup type 2 (PairPos) compaction mode: 0 = do not attempt to compact PairPos lookups; 1 to 8 = create at most 1 to 8 new subtables for each existing subtable, provided that it would yield a 50%% file size saving; 9 = create as many new subtables as needed to yield a file size saving. Default: {GPOS_COMPACT_MODE_DEFAULT}. This compaction aims to save file size, by splitting large class kerning subtables (Format 2) that contain many zero values into smaller and denser subtables. It's a trade-off between the overhead of several subtables versus the sparseness of one big subtable. See the pull request: https://github.com/fonttools/fonttools/pull/2326 """), default=int(GPOS_COMPACT_MODE_DEFAULT), choices=list(range(10)), type=int, ) logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument("-v", "--verbose", action="store_true", help="Run more verbosely.") logging_group.add_argument("-q", "--quiet", action="store_true", help="Turn verbosity off.") options = parser.parse_args(args) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) font = TTFont(options.font) # TODO: switch everything to have type(mode) = int when using the Config class compact(font, str(options.gpos_compact_mode)) font.save(options.outfile or options.font)
def doit(args): levels = ["WARNING", "INFO", "DEBUG"] configLogger(level=levels[min(len(levels) - 1, args.verbose)]) font = TTFont(args.input_font) builder = Builder(font, args.input_fea) builder.build() if args.lookupmap: with open(args.lookupmap, "w") as outf: for n, l in sorted(builder.named_lookups_.items()): outf.write("{},{},{}\n".format(n, l.table, l.lookup_index)) font.save(args.output)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') parser.add_argument('-o', metavar='OUTPUTFILE', dest='outfile', default=None, help='output file') parser.add_argument('-x', metavar='TAG', dest='exclude', action='append', default=[], help='exclude table') parser.add_argument('--disable-iup', dest='optimize', action='store_false', help='do not perform IUP optimization') parser.add_argument( '--master-finder', default='master_ttf_interpolatable/{stem}.ttf', help=('templated string used for finding binary font ' 'files given the source file names defined in the ' 'designspace document. The following special strings ' 'are defined: {fullname} is the absolute source file ' 'name; {basename} is the file name without its ' 'directory; {stem} is the basename without the file ' 'extension; {ext} is the source file extension; ' '{dirname} is the directory of the absolute file ' 'name. The default value is "%(default)s".')) options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") designspace_filename = options.designspace finder = MasterFinder(options.master_finder) outfile = options.outfile if outfile is None: outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' vf, _, _ = build(designspace_filename, finder, exclude=options.exclude, optimize=options.optimize) log.info("Saving variation font %s", outfile) vf.save(outfile)
def main(args): from fontTools import configLogger args = args[1:] # TODO: allow user to configure logging via command-line options configLogger(level="INFO") 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] model = VariationModel(locs) from pprint import pprint print("Sorted locations:") pprint(model.locations) print("Supports:") pprint(model.supports)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") designspace_filename = options.designspace finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable').replace('.ufo', '.ttf') outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' vf, model, master_ttfs = build(designspace_filename, finder) log.info("Saving variation font %s", outfile) vf.save(outfile)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") designspace_filename = options.designspace finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable').replace('.ufo', '.ttf') outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' gx, model, master_ttfs = build(designspace_filename, finder) log.info("Saving variation font %s", outfile) gx.save(outfile)
def main(args=None): """Optimize the layout tables of an existing font.""" from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser( prog="otlLib.optimize", description=main.__doc__, formatter_class=RawTextHelpFormatter, ) parser.add_argument("font") parser.add_argument("-o", metavar="OUTPUTFILE", dest="outfile", default=None, help="output file") parser.add_argument( "--gpos-compression-level", help=COMPRESSION_LEVEL.help, default=COMPRESSION_LEVEL.default, choices=list(range(10)), type=int, ) logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument("-v", "--verbose", action="store_true", help="Run more verbosely.") logging_group.add_argument("-q", "--quiet", action="store_true", help="Turn verbosity off.") options = parser.parse_args(args) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) font = TTFont(options.font) compact(font, options.gpos_compression_level) font.save(options.outfile or options.font)
def main(args=None): """Optimize a font's GDEF variation store""" from argparse import ArgumentParser from fontTools import configLogger from fontTools.ttLib import TTFont from fontTools.ttLib.tables.otBase import OTTableWriter parser = ArgumentParser(prog='varLib.varStore', description=main.__doc__) parser.add_argument('fontfile') parser.add_argument('outfile', nargs='?') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") fontfile = options.fontfile outfile = options.outfile font = TTFont(fontfile) gdef = font['GDEF'] store = gdef.table.VarStore writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("Before: %7d bytes" % size) varidx_map = store.optimize() gdef.table.remap_device_varidxes(varidx_map) if 'GPOS' in font: font['GPOS'].table.remap_device_varidxes(varidx_map) writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("After: %7d bytes" % size) if outfile is not None: font.save(outfile)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger from fontTools.ttLib import TTFont from fontTools.ttLib.tables.otBase import OTTableWriter parser = ArgumentParser(prog='varLib.varStore') parser.add_argument('fontfile') parser.add_argument('outfile', nargs='?') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") fontfile = options.fontfile outfile = options.outfile font = TTFont(fontfile) gdef = font['GDEF'] store = gdef.table.VarStore writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("Before: %7d bytes" % size) varidx_map = store.optimize() gdef.table.remap_device_varidxes(varidx_map) if 'GPOS' in font: font['GPOS'].table.remap_device_varidxes(varidx_map) writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("After: %7d bytes" % size) if outfile is not None: font.save(outfile)
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=-1) 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") files = chain.from_iterable(map(glob.glob, options.input)) with Pool() as pool: pool.map(partial(run, options=options), files)
def main(args=None): """Interpolate GDEF/GPOS/GSUB tables for a point on a designspace""" from fontTools import configLogger import argparse import sys parser = argparse.ArgumentParser( "fonttools varLib.interpolate_layout", 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)") 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') loc = {} for arg in args.locations: tag,val = arg.split('=') loc[tag] = float(val) font = interpolate_layout(args.designspace_filename, loc, finder) log.info("Saving font %s", args.output) font.save(args.output)
def main(args=None): from fontTools import configLogger if args is None: args = sys.argv[1:] options = Options() args = options.parse_opts(args) if len(args) < 1: print("usage: pyftmerge font...", file=sys.stderr) return 1 configLogger(level=logging.INFO if options.verbose else logging.WARNING) if options.timing: timer.logger.setLevel(logging.DEBUG) else: timer.logger.disabled = True merger = Merger(options=options) font = merger.merge(args) outfile = 'merged.ttf' with timer("compile and save font"): font.save(outfile)
def main(args=None): from fontTools import configLogger import sys if args is None: args = sys.argv[1:] designspace_filename = args[0] locargs = args[1:] outfile = os.path.splitext(designspace_filename)[0] + '-instance.ttf' # TODO: allow user to configure logging via command-line options configLogger(level="INFO") finder = lambda s: s.replace('master_ufo', 'master_ttf_interpolatable').replace('.ufo', '.ttf') loc = {} for arg in locargs: tag,val = arg.split('=') loc[tag] = float(val) font = interpolate_layout(designspace_filename, loc, finder) log.info("Saving font %s", outfile) font.save(outfile)
def main(args=None): """Compress and decompress WOFF2 fonts""" import argparse from fontTools import configLogger 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): def __call__(self, parser, namespace, values, option_string=None): namespace.transform_tables.difference_update({"glyf", "loca"}) class _HmtxTransformAction(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): namespace.transform_tables.add("hmtx") parser = argparse.ArgumentParser( prog="fonttools ttLib.woff2", 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_compress = parser_group.add_parser("compress", 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): group = subparser.add_mutually_exclusive_group(required=False) group.add_argument( "-v", "--verbose", action="store_true", help="print more messages to console", ) group.add_argument( "-q", "--quiet", action="store_true", help="do not print messages to console", ) parser_compress.add_argument( "input_file", metavar="INPUT", help="the input OpenType font (.ttf or .otf)", ) parser_decompress.add_argument( "input_file", metavar="INPUT", help="the input WOFF2 font", ) parser_compress.add_argument( "-o", "--output-file", metavar="OUTPUT", help="the output WOFF2 font", ) parser_decompress.add_argument( "-o", "--output-file", metavar="OUTPUT", help="the output OpenType font", ) transform_group = parser_compress.add_argument_group() transform_group.add_argument( "--no-glyf-transform", dest="transform_tables", nargs=0, action=_NoGlyfTransformAction, help="Do not transform glyf (and loca) tables", ) transform_group.add_argument( "--hmtx-transform", dest="transform_tables", nargs=0, action=_HmtxTransformAction, help="Enable optional transformation for 'hmtx' table", ) parser_compress.set_defaults( subcommand=compress, transform_tables={"glyf", "loca"}, ) parser_decompress.set_defaults(subcommand=decompress) options = vars(parser.parse_args(args)) subcommand = options.pop("subcommand", None) if not subcommand: parser.print_help() return quiet = options.pop("quiet") verbose = options.pop("verbose") configLogger( level=("ERROR" if quiet else "DEBUG" if verbose else "INFO"), ) if not options["output_file"]: if subcommand is compress: extension = ".woff2" elif subcommand is decompress: # choose .ttf/.otf file extension depending on sfntVersion with open(options["input_file"], "rb") as f: f.seek(4) # skip 'wOF2' signature sfntVersion = f.read(4) assert len(sfntVersion) == 4, "not enough data" extension = ".otf" if sfntVersion == b"OTTO" else ".ttf" else: raise AssertionError(subcommand) options["output_file"] = makeOutputFileName( options["input_file"], outputDir=None, extension=extension ) try: subcommand(**options) except TTLibError as e: parser.error(e)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') parser.add_argument( '-o', metavar='OUTPUTFILE', dest='outfile', default=None, help='output file' ) parser.add_argument( '-x', metavar='TAG', dest='exclude', action='append', default=[], help='exclude table' ) parser.add_argument( '--disable-iup', dest='optimize', action='store_false', help='do not perform IUP optimization' ) parser.add_argument( '--master-finder', default='master_ttf_interpolatable/{stem}.ttf', help=( 'templated string used for finding binary font ' 'files given the source file names defined in the ' 'designspace document. The following special strings ' 'are defined: {fullname} is the absolute source file ' 'name; {basename} is the file name without its ' 'directory; {stem} is the basename without the file ' 'extension; {ext} is the source file extension; ' '{dirname} is the directory of the absolute file ' 'name. The default value is "%(default)s".' ) ) logging_group = parser.add_mutually_exclusive_group(required=False) logging_group.add_argument( "-v", "--verbose", action="store_true", help="Run more verbosely.") logging_group.add_argument( "-q", "--quiet", action="store_true", help="Turn verbosity off.") options = parser.parse_args(args) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) designspace_filename = options.designspace finder = MasterFinder(options.master_finder) outfile = options.outfile if outfile is None: outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' vf, _, _ = build( designspace_filename, finder, exclude=options.exclude, optimize=options.optimize ) log.info("Saving variation font %s", outfile) vf.save(outfile)
def main(args=None): """Add features from a feature file (.fea) into a OTF font""" parser = argparse.ArgumentParser( description="Use fontTools to compile OpenType feature files (*.fea).") parser.add_argument("input_fea", metavar="FEATURES", help="Path to the feature file") parser.add_argument("input_font", metavar="INPUT_FONT", help="Path to the input font") parser.add_argument( "-o", "--output", dest="output_font", metavar="OUTPUT_FONT", help="Path to the output font.", ) parser.add_argument( "-t", "--tables", metavar="TABLE_TAG", choices=Builder.supportedTables, nargs="+", help="Specify the table(s) to be built.", ) parser.add_argument( "-d", "--debug", action="store_true", help="Add source-level debugging information to font.", ) parser.add_argument( "-v", "--verbose", help="increase the logger verbosity. Multiple -v " "options are allowed.", action="count", default=0, ) parser.add_argument("--traceback", help="show traceback for exceptions.", action="store_true") options = parser.parse_args(args) levels = ["WARNING", "INFO", "DEBUG"] configLogger(level=levels[min(len(levels) - 1, options.verbose)]) output_font = options.output_font or makeOutputFileName(options.input_font) log.info("Compiling features to '%s'" % (output_font)) font = TTFont(options.input_font) try: addOpenTypeFeatures(font, options.input_fea, tables=options.tables, debug=options.debug) except FeatureLibError as e: if options.traceback: raise log.error(e) font.save(output_font)
from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * import fontTools.feaLib.builder as feaLibBuilder from fontTools.ttLib import TTFont from fontTools import configLogger import sys import argparse parser = argparse.ArgumentParser( description="Use fontTools to compile OpenType features.") parser.add_argument("input_fea", metavar="FEATURES", help="Path to the feature file") parser.add_argument("input_font", metavar="INPUT", help="Path to the input font") parser.add_argument("output_font", metavar="OUTPUT", help="Path to the output font") parser.add_argument("-v", "--verbose", help="increase the logger verbosity. " "Multiple -v options are allowed.", action="count", default=0) options = parser.parse_args(sys.argv[1:]) levels = ["WARNING", "INFO", "DEBUG"] configLogger(level=levels[min(len(levels) - 1, options.verbose)]) font = TTFont(options.input_font) feaLibBuilder.addOpenTypeFeatures(font, options.input_fea) font.save(options.output_font)
def parseArgs(args): """Parse argv. Returns: 3-tuple (infile, axisLimits, options) axisLimits is either a Dict[str, Optional[float]], for pinning variation axes to specific coordinates along those axes (with `None` as a placeholder for an axis' default value); or a Dict[str, Tuple(float, float)], meaning limit this axis to min/max range. Axes locations are in user-space coordinates, as defined in the "fvar" table. """ from fontTools import configLogger import argparse parser = argparse.ArgumentParser( "fonttools varLib.instancer", description="Partially instantiate a variable font", ) parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.") parser.add_argument( "locargs", metavar="AXIS=LOC", nargs="*", help="List of space separated locations. A location consist in " "the tag of a variation axis, followed by '=' and one of number, " "number:number or the literal string 'drop'. " "E.g.: wdth=100 or wght=75.0:125.0 or wght=drop", ) parser.add_argument( "-o", "--output", metavar="OUTPUT.ttf", default=None, help="Output instance TTF file (default: INPUT-instance.ttf).", ) parser.add_argument( "--no-optimize", dest="optimize", action="store_false", help= "Don't perform IUP optimization on the remaining gvar TupleVariations", ) parser.add_argument( "--no-overlap-flag", dest="overlap", action="store_false", help= "Don't set OVERLAP_SIMPLE/OVERLAP_COMPOUND glyf flags (only applicable " "when generating a full instance)", ) loggingGroup = parser.add_mutually_exclusive_group(required=False) loggingGroup.add_argument("-v", "--verbose", action="store_true", help="Run more verbosely.") loggingGroup.add_argument("-q", "--quiet", action="store_true", help="Turn verbosity off.") options = parser.parse_args(args) infile = options.input if not os.path.isfile(infile): parser.error("No such file '{}'".format(infile)) configLogger(level=( "DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")) try: axisLimits = parseLimits(options.locargs) except ValueError as e: parser.error(e) if len(axisLimits) != len(options.locargs): parser.error("Specified multiple limits for the same axis") return (infile, axisLimits, options)
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger parser = ArgumentParser(prog='varLib') parser.add_argument('designspace') parser.add_argument( '-o', metavar='OUTPUTFILE', dest='outfile', default=None, help='output file' ) parser.add_argument( '-x', metavar='TAG', dest='exclude', action='append', default=[], help='exclude table' ) parser.add_argument( '--disable-iup', dest='optimize', action='store_false', help='do not perform IUP optimization' ) parser.add_argument( '--master-finder', default='master_ttf_interpolatable/{stem}.ttf', help=( 'templated string used for finding binary font ' 'files given the source file names defined in the ' 'designspace document. The following special strings ' 'are defined: {fullname} is the absolute source file ' 'name; {basename} is the file name without its ' 'directory; {stem} is the basename without the file ' 'extension; {ext} is the source file extension; ' '{dirname} is the directory of the absolute file ' 'name. The default value is "%(default)s".' ) ) options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") designspace_filename = options.designspace finder = MasterFinder(options.master_finder) outfile = options.outfile if outfile is None: outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf' vf, model, master_ttfs = build( designspace_filename, finder, exclude=options.exclude, optimize=options.optimize ) log.info("Saving variation font %s", outfile) vf.save(outfile)