From e146ddfd865d0e12a7dfc04553e8b5facdb9cf79 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 19 Aug 2022 12:20:21 -0600 Subject: [PATCH 1/4] [cliTools.makeOutputFileName] Add fragment argument And use it from subsetter and instancer. Related to https://github.com/fonttools/fonttools/issues/1156 --- Lib/fontTools/misc/cliTools.py | 9 ++++++--- Lib/fontTools/subset/__init__.py | 8 ++------ Lib/fontTools/varLib/instancer/__init__.py | 6 +++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Lib/fontTools/misc/cliTools.py b/Lib/fontTools/misc/cliTools.py index e8c176772..0d28afbb7 100644 --- a/Lib/fontTools/misc/cliTools.py +++ b/Lib/fontTools/misc/cliTools.py @@ -6,7 +6,7 @@ import re numberAddedRE = re.compile(r"#\d+$") -def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False): +def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False, fragment=""): """Generates a suitable file name for writing output. Often tools will want to take a file, do some kind of transformation to it, @@ -14,6 +14,7 @@ def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False): output file, through one or more of the following steps: - changing the output directory + - appending fragment before file extension - replacing the file extension - suffixing the filename with a number (``#1``, ``#2``, etc.) to avoid overwriting an existing file. @@ -21,6 +22,8 @@ def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False): Args: input: Name of input file. outputDir: Optionally, a new directory to write the file into. + fragment: Optionally, a string fragment is appended to file name before + the extension. extension: Optionally, a replacement for the current file extension. overWrite: Overwriting an existing file is permitted if true; if false and the proposed filename exists, a new name will be generated by @@ -36,11 +39,11 @@ def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False): fileName = numberAddedRE.split(fileName)[0] if extension is None: extension = os.path.splitext(input)[1] - output = os.path.join(dirName, fileName + extension) + output = os.path.join(dirName, fileName + fragment + extension) n = 1 if not overWrite: while os.path.exists(output): output = os.path.join( - dirName, fileName + "#" + repr(n) + extension) + dirName, fileName + fragment + "#" + repr(n) + extension) n += 1 return output diff --git a/Lib/fontTools/subset/__init__.py b/Lib/fontTools/subset/__init__.py index 265e2adf1..ddf60bbfe 100644 --- a/Lib/fontTools/subset/__init__.py +++ b/Lib/fontTools/subset/__init__.py @@ -10,6 +10,7 @@ from fontTools.ttLib.tables.otBase import USE_HARFBUZZ_REPACKER from fontTools.otlLib.maxContextCalc import maxCtxFont from fontTools.pens.basePen import NullPen from fontTools.misc.loggingTools import Timer +from fontTools.misc.cliTools import makeOutputFileName from fontTools.subset.util import _add_method, _uniq_sort from fontTools.subset.cff import * from fontTools.subset.svg import * @@ -3189,12 +3190,7 @@ def main(args=None): font = load_font(fontfile, options, dontLoadGlyphNames=dontLoadGlyphNames) if outfile is None: - basename, _ = splitext(fontfile) - if options.flavor is not None: - ext = "." + options.flavor.lower() - else: - ext = ".ttf" if font.sfntVersion == "\0\1\0\0" else ".otf" - outfile = basename + ".subset" + ext + outfile = makeOutputFileName(fontfile, overWrite=True, fragment=".subset") with timer("compile glyph list"): if wildcard_glyphs: diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index f131f1edb..552583494 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -90,6 +90,7 @@ from fontTools.varLib import builder from fontTools.varLib.mvar import MVAR_ENTRIES from fontTools.varLib.merger import MutatorMerger from fontTools.varLib.instancer import names +from fontTools.misc.cliTools import makeOutputFileName import collections from copy import deepcopy from enum import IntEnum @@ -1468,9 +1469,8 @@ def main(args=None): updateFontNames=options.update_name_table, ) - outfile = ( - os.path.splitext(infile)[0] - + "-{}.ttf".format("instance" if isFullInstance else "partial") + fragment = "-instance" if isFullInstance else "-partial" + outfile = (makeOutputFileName(infile, overWrite=True, fragment=fragment) if not options.output else options.output ) From f24bdddb283d6b50a7a0d60ded214ff373f99c19 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 19 Aug 2022 12:28:52 -0600 Subject: [PATCH 2/4] [scaleUpem] Add argparse and --output-file --- Lib/fontTools/ttLib/scaleUpem.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Lib/fontTools/ttLib/scaleUpem.py b/Lib/fontTools/ttLib/scaleUpem.py index 02d356996..e6d0ca4d8 100644 --- a/Lib/fontTools/ttLib/scaleUpem.py +++ b/Lib/fontTools/ttLib/scaleUpem.py @@ -221,13 +221,29 @@ def main(args=None): args = sys.argv[1:] from fontTools.ttLib import TTFont + from fontTools.misc.cliTools import makeOutputFileName + import argparse - if len(args) != 2: - print("usage: fonttools ttLib.scaleUpem font new-upem") - sys.exit() + parser = argparse.ArgumentParser( + "fonttools ttLib.scaleUpem", description="Change the units-per-EM of fonts" + ) + parser.add_argument("font", metavar="font", help="Font file.") + parser.add_argument( + "new_upem", metavar="new-upem", help="New units-per-EM integer value." + ) + parser.add_argument( + "--output-file", metavar="path", default=None, help="Output file." + ) - font = TTFont(args[0]) - new_upem = int(args[1]) + options = parser.parse_args(args) + + font = TTFont(options.font) + new_upem = int(options.new_upem) + output_file = ( + options.output_file + if options.output_file is not None + else makeOutputFileName(options.font, overWrite=True, fragment="-scaled") + ) if "CFF " in font or "CFF2" in font: print( @@ -238,8 +254,8 @@ def main(args=None): scale_upem(font, new_upem) - print("Writing out.ttf") - font.save("out.ttf") + print("Writing %s" % output_file) + font.save(output_file) if __name__ == "__main__": From 24c9fb6ffae16b15e80db148774c12d70883f694 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 22 Aug 2022 06:26:30 -0600 Subject: [PATCH 3/4] [cliTools] Rename fragment to suffix --- Lib/fontTools/misc/cliTools.py | 10 +++++----- Lib/fontTools/subset/__init__.py | 2 +- Lib/fontTools/ttLib/scaleUpem.py | 2 +- Lib/fontTools/varLib/instancer/__init__.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Lib/fontTools/misc/cliTools.py b/Lib/fontTools/misc/cliTools.py index 0d28afbb7..e7dadf982 100644 --- a/Lib/fontTools/misc/cliTools.py +++ b/Lib/fontTools/misc/cliTools.py @@ -6,7 +6,7 @@ import re numberAddedRE = re.compile(r"#\d+$") -def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False, fragment=""): +def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False, suffix=""): """Generates a suitable file name for writing output. Often tools will want to take a file, do some kind of transformation to it, @@ -14,7 +14,7 @@ def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False, f output file, through one or more of the following steps: - changing the output directory - - appending fragment before file extension + - appending suffix before file extension - replacing the file extension - suffixing the filename with a number (``#1``, ``#2``, etc.) to avoid overwriting an existing file. @@ -22,7 +22,7 @@ def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False, f Args: input: Name of input file. outputDir: Optionally, a new directory to write the file into. - fragment: Optionally, a string fragment is appended to file name before + suffix: Optionally, a string suffix is appended to file name before the extension. extension: Optionally, a replacement for the current file extension. overWrite: Overwriting an existing file is permitted if true; if false @@ -39,11 +39,11 @@ def makeOutputFileName(input, outputDir=None, extension=None, overWrite=False, f fileName = numberAddedRE.split(fileName)[0] if extension is None: extension = os.path.splitext(input)[1] - output = os.path.join(dirName, fileName + fragment + extension) + output = os.path.join(dirName, fileName + suffix + extension) n = 1 if not overWrite: while os.path.exists(output): output = os.path.join( - dirName, fileName + fragment + "#" + repr(n) + extension) + dirName, fileName + suffix + "#" + repr(n) + extension) n += 1 return output diff --git a/Lib/fontTools/subset/__init__.py b/Lib/fontTools/subset/__init__.py index ddf60bbfe..be0fe9639 100644 --- a/Lib/fontTools/subset/__init__.py +++ b/Lib/fontTools/subset/__init__.py @@ -3190,7 +3190,7 @@ def main(args=None): font = load_font(fontfile, options, dontLoadGlyphNames=dontLoadGlyphNames) if outfile is None: - outfile = makeOutputFileName(fontfile, overWrite=True, fragment=".subset") + outfile = makeOutputFileName(fontfile, overWrite=True, suffix=".subset") with timer("compile glyph list"): if wildcard_glyphs: diff --git a/Lib/fontTools/ttLib/scaleUpem.py b/Lib/fontTools/ttLib/scaleUpem.py index e6d0ca4d8..b4f20ef7e 100644 --- a/Lib/fontTools/ttLib/scaleUpem.py +++ b/Lib/fontTools/ttLib/scaleUpem.py @@ -242,7 +242,7 @@ def main(args=None): output_file = ( options.output_file if options.output_file is not None - else makeOutputFileName(options.font, overWrite=True, fragment="-scaled") + else makeOutputFileName(options.font, overWrite=True, suffix="-scaled") ) if "CFF " in font or "CFF2" in font: diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 552583494..76d34ed4f 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -1469,8 +1469,8 @@ def main(args=None): updateFontNames=options.update_name_table, ) - fragment = "-instance" if isFullInstance else "-partial" - outfile = (makeOutputFileName(infile, overWrite=True, fragment=fragment) + suffix = "-instance" if isFullInstance else "-partial" + outfile = (makeOutputFileName(infile, overWrite=True, suffix=suffix) if not options.output else options.output ) From aa2dae3be18f352e09cf9bf492718e4330230f37 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 22 Aug 2022 06:28:48 -0600 Subject: [PATCH 4/4] [instancer] Run black --- Lib/fontTools/varLib/instancer/__init__.py | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 76d34ed4f..8f9761236 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -328,7 +328,9 @@ def limitTupleVariationAxisRange(var, axisTag, axisRange): return [var, newVar] -def _instantiateGvarGlyph(glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, optimize=True): +def _instantiateGvarGlyph( + glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, optimize=True +): coordinates, ctrl = glyf._getCoordinatesAndControls(glyphname, hMetrics, vMetrics) endPts = ctrl.endPts @@ -364,22 +366,26 @@ def _instantiateGvarGlyph(glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, for var in tupleVarStore: var.optimize(coordinates, endPts, isComposite) + def instantiateGvarGlyph(varfont, glyphname, axisLimits, optimize=True): """Remove? https://github.com/fonttools/fonttools/pull/2266""" gvar = varfont["gvar"] glyf = varfont["glyf"] - hMetrics = varfont['hmtx'].metrics - vMetrics = getattr(varfont.get('vmtx'), 'metrics', None) - _instantiateGvarGlyph(glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, optimize=optimize) + hMetrics = varfont["hmtx"].metrics + vMetrics = getattr(varfont.get("vmtx"), "metrics", None) + _instantiateGvarGlyph( + glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, optimize=optimize + ) + def instantiateGvar(varfont, axisLimits, optimize=True): log.info("Instantiating glyf/gvar tables") gvar = varfont["gvar"] glyf = varfont["glyf"] - hMetrics = varfont['hmtx'].metrics - vMetrics = getattr(varfont.get('vmtx'), 'metrics', None) + hMetrics = varfont["hmtx"].metrics + vMetrics = getattr(varfont.get("vmtx"), "metrics", None) # Get list of glyph names sorted by component depth. # If a composite glyph is processed before its base glyph, the bounds may # be calculated incorrectly because deltas haven't been applied to the @@ -394,7 +400,9 @@ def instantiateGvar(varfont, axisLimits, optimize=True): ), ) for glyphname in glyphnames: - _instantiateGvarGlyph(glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, optimize=optimize) + _instantiateGvarGlyph( + glyphname, glyf, gvar, hMetrics, vMetrics, axisLimits, optimize=optimize + ) if not gvar.variations: del varfont["gvar"] @@ -925,7 +933,9 @@ def instantiateAvar(varfont, axisLimits): if fromCoord < axisRange.minimum or fromCoord > axisRange.maximum: continue - fromCoord = normalizeValue(fromCoord, (axisRange.minimum, 0, axisRange.maximum)) + fromCoord = normalizeValue( + fromCoord, (axisRange.minimum, 0, axisRange.maximum) + ) assert mappedMin <= toCoord <= mappedMax toCoord = normalizeValue(toCoord, (mappedMin, 0, mappedMax)) @@ -1400,7 +1410,7 @@ def parseArgs(args): "--no-recalc-timestamp", dest="recalc_timestamp", action="store_false", - help="Don't set the output font's timestamp to the current time." + help="Don't set the output font's timestamp to the current time.", ) parser.add_argument( "--no-recalc-bounds", @@ -1470,7 +1480,8 @@ def main(args=None): ) suffix = "-instance" if isFullInstance else "-partial" - outfile = (makeOutputFileName(infile, overWrite=True, suffix=suffix) + outfile = ( + makeOutputFileName(infile, overWrite=True, suffix=suffix) if not options.output else options.output )