def run(self, filename, pipedata): if 'optimize' in pipedata and not pipedata['optimize']: return self.bakery.logging_raw('### Optimize TTF {}'.format(filename)) # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py from fontTools.subset import Options, Subsetter, load_font, save_font options = Options() options.layout_features = "*" options.name_IDs = "*" options.hinting = True options.notdef_outline = True font = load_font(op.join(self.builddir, filename), options) subsetter = Subsetter(options=options) subsetter.populate(glyphs=font.getGlyphOrder()) subsetter.subset(font) save_font(font, op.join(self.builddir, filename + '.opt'), options) newsize = op.getsize(op.join(self.builddir, filename + '.opt')) origsize = op.getsize(op.join(self.builddir, filename)) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" self.bakery.logging_cmd("ls -l '%s'* %s" % (filename, comment)) statusmessage = "{0}.opt: {1} bytes\n{0}: {2} bytes\n" self.bakery.logging_raw(statusmessage.format(filename, newsize, origsize)) # move ttx files to src shutil.move(op.join(self.builddir, filename + '.opt'), op.join(self.builddir, filename), log=self.bakery.logger)
def main(args): """Subset a font (useful for making small test fonts). Args: args: list, arguments the user typed. """ parser = argparse.ArgumentParser() parser.add_argument('fontfile', help='Input font file') parser.add_argument('--subset_postfix', default='', help='Postfix to the subset extension') parser.add_argument('--text', default='', help='Text to include in the subset') parser.add_argument('--unicodes', default='', help='Comma separated list of Unicode codepoints (hex) ' 'to include in the subset; eg, "e7,0xe8,U+00e9"') parser.add_argument('--glyphs', default='', help='Comma separated list of glyph IDs (decimal) to ' 'include in the subset; eg, "1,27"') parser.add_argument('--hinting', default=False, action='store_true', help='Enable hinting if specified, no hinting if not ' 'present') cmd_args = parser.parse_args(args) options = Options() # Definitely want the .notdef glyph and outlines. options.notdef_glyph = True options.notdef_outline = True # Get the item. to keep in the subset. text = cmd_args.text unicodes_str = cmd_args.unicodes.lower().replace('0x', '').replace('u+', '') # TODO(bstell) replace this whole files by using the new subset.py code unicodes_input = [c for c in unicodes_str.split(',') if c] unicodes = [] for c in unicodes_input: if '-' in c: uni_range = c.split('-') uni_range_expanded = range(int(uni_range[0], 16), int(uni_range[1], 16) + 1) unicodes.extend(uni_range_expanded) else: unicodes.append(int(c, 16)) #unicodes = [int(c, 16) for c in unicodes_input_expanded] glyphs = [int(c) for c in cmd_args.glyphs.split(',') if c] fontfile = cmd_args.fontfile options.hinting = cmd_args.hinting # False => no hinting options.hinting = True # hint stripping for CFF is currently broken dirname = os.path.dirname(fontfile) basename = os.path.basename(fontfile) filename, extension = os.path.splitext(basename) subset_postfix = cmd_args.subset_postfix output_file = dirname + '/' + filename + '_subset' + subset_postfix + extension print "output_file =", output_file font = load_font(fontfile, options, lazy=False) subsetter = Subsetter(options) subsetter.populate(text=text, unicodes=unicodes, glyphs=glyphs) subsetter.subset(font) save_font(font, output_file, options)
def run(self, pipedata): if 'optimize' in pipedata and not pipedata['optimize']: return from bakery_cli.utils import ProcessedFile filename = ProcessedFile() self.bakery.logging_raw('### Optimize TTF {}'.format(filename)) # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py from fontTools.subset import Options, Subsetter, load_font, save_font options = Options() options.layout_features = ["*"] options.name_IDs = ["*"] options.hinting = True options.legacy_kern = True options.notdef_outline = True options.no_subset_tables += ['DSIG'] options.drop_tables = list( set(options._drop_tables_default) - set(['DSIG'])) cmd_options = ('--glyphs=*' ' --layout-features=*' ' --name-IDs=*' ' --hinting' ' --legacy-kern --notdef-outline' ' --no-subset-tables+=DSIG' ' --drop-tables-=DSIG') font = load_font(op.join(self.builddir, filename), options) cmdline = 'pyftsubset {1} {0}'.format(cmd_options, op.join(self.builddir, filename)) self.bakery.logging_cmd(cmdline) subsetter = Subsetter(options=options) subsetter.populate(glyphs=font.getGlyphOrder()) subsetter.subset(font) save_font(font, op.join(self.builddir, filename + '.fix'), options) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" self.bakery.logging_cmd(comment) run(u"ls -la {0} {0}.fix | awk '{{ print $5 \"\t\" $9 }}'".format( unicode(op.join(self.builddir, filename)))) comment = "# copy back optimized ttf to original filename" self.bakery.logging_cmd(comment) shutil.move(op.join(self.builddir, filename + '.fix'), op.join(self.builddir, filename))
def run(self, pipedata): if 'optimize' in pipedata and not pipedata['optimize']: return from bakery_cli.utils import ProcessedFile filename = ProcessedFile() self.bakery.logging_raw('### Optimize TTF {}'.format(filename)) # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py from fontTools.subset import Options, Subsetter, load_font, save_font options = Options() options.layout_features = ["*"] options.name_IDs = ["*"] options.hinting = True options.legacy_kern = True options.notdef_outline = True options.no_subset_tables += ['DSIG'] options.drop_tables = list(set(options._drop_tables_default) - set(['DSIG'])) cmd_options = ('--glyphs=*' ' --layout-features=*' ' --name-IDs=*' ' --hinting' ' --legacy-kern --notdef-outline' ' --no-subset-tables+=DSIG' ' --drop-tables-=DSIG') font = load_font(op.join(self.builddir, filename), options) cmdline = 'pyftsubset {1} {0}'.format(cmd_options, op.join(self.builddir, filename)) self.bakery.logging_cmd(cmdline) subsetter = Subsetter(options=options) subsetter.populate(glyphs=font.getGlyphOrder()) subsetter.subset(font) save_font(font, op.join(self.builddir, filename + '.fix'), options) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" self.bakery.logging_cmd(comment) run(u"ls -la {0} {0}.fix | awk '{{ print $5 \"\t\" $9 }}'".format(unicode(op.join(self.builddir, filename)))) comment = "# copy back optimized ttf to original filename" self.bakery.logging_cmd(comment) shutil.move(op.join(self.builddir, filename + '.fix'), op.join(self.builddir, filename))
def customSubsetting(self, font, text): options = Options() options.layout_features = "*" # keep all GSUB/GPOS features options.glyph_names = False # keep post glyph names options.legacy_cmap = True # keep non-Unicode cmaps options.name_legacy = True # keep non-Unicode names options.name_IDs = ["*"] # keep all nameIDs options.name_languages = ["*"] # keep all name languages options.notdef_outline = True options.ignore_missing_glyphs = False options.recommended_glyphs = True options.prune_unicode_ranges = True subsetter = Subsetter(options=options) subsetter.populate(text=text, unicodes=[0, 13, 32]) subsetter.subset(font) return font
def main(args): """Subset a font (useful for making small test fonts). Args: args: list, arguments the user typed. """ parser = argparse.ArgumentParser() parser.add_argument('fontfile', help='Input font file') parser.add_argument('--text', default='', help='Text to include in the subset') parser.add_argument('--unicodes', default='', help='Comma separated list of Unicode codepoints (hex) ' 'to include in the subset; eg, "e7,0xe8,U+00e9"') parser.add_argument('--glyphs', default='', help='Comma separated list of glyph IDs (decimal) to ' 'include in the subset; eg, "1,27"') parser.add_argument('--hinting', default=False, action='store_true', help='Enable hinting if specified, no hinting if not ' 'present') cmd_args = parser.parse_args(args) options = Options() # Definitely want the .notdef glyph and outlines. options.notdef_glyph = True options.notdef_outline = True # Get the item. to keep in the subset. text = cmd_args.text unicodes_str = cmd_args.unicodes.lower().replace('0x', '').replace('u+', '') unicodes = [int(c, 16) for c in unicodes_str.split(',') if c] glyphs = [int(c) for c in cmd_args.glyphs.split(',') if c] fontfile = cmd_args.fontfile options.hinting = cmd_args.hinting # False => no hinting dirname = os.path.dirname(fontfile) basename = os.path.basename(fontfile) filename, extension = os.path.splitext(basename) output_file = dirname + '/' + filename + '_subset' + extension font = load_font(fontfile, options, lazy=False) subsetter = Subsetter(options) subsetter.populate(text=text, unicodes=unicodes, glyphs=glyphs) subsetter.subset(font) save_font(font, output_file, options)
def run(self, filename, pipedata): if 'optimize' in pipedata and not pipedata['optimize']: return self.bakery.logging_raw('### Optimize TTF {}'.format(filename)) # copied from https://code.google.com/p/noto/source/browse/nototools/subset.py from fontTools.subset import Options, Subsetter, load_font, save_font options = Options() options.layout_features = ["*"] options.name_IDs = ["*"] options.hinting = True options.legacy_kern = True options.notdef_outline = True options.no_subset_tables += ['DSIG'] options.drop_tables = list( set(options._drop_tables_default) - set(['DSIG'])) font = load_font(op.join(self.builddir, filename), options) self.bakery.logging_raw('Before: {}'.format(font.keys())) self.bakery.logging_raw('{}'.format(options.__dict__)) subsetter = Subsetter(options=options) subsetter.populate(glyphs=font.getGlyphOrder()) subsetter.subset(font) save_font(font, op.join(self.builddir, filename + '.opt'), options) newsize = op.getsize(op.join(self.builddir, filename + '.opt')) origsize = op.getsize(op.join(self.builddir, filename)) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" self.bakery.logging_cmd("ls -l '%s'* %s" % (filename, comment)) statusmessage = "{0}.opt: {1} bytes\n{0}: {2} bytes\n" self.bakery.logging_raw( statusmessage.format(filename, newsize, origsize)) self.bakery.logging_raw('Now: {}'.format(font.keys())) # move ttx files to src shutil.move(op.join(self.builddir, filename + '.opt'), op.join(self.builddir, filename), log=self.bakery.logger)
def _subset(self, otf, fmt): from fontTools.subset import Options, Subsetter for name, subset in self.subsets.items(): logger.info(f"Creating {name}.{fmt.value} subset") new = deepcopy(otf) options = Options() options.name_IDs = ["*"] options.name_legacy = True options.name_languages = ["*"] options.recommended_glyphs = True options.layout_features = ["*"] options.notdef_outline = True options.notdef_glyph = True options.glyph_names = True options.hinting = True options.legacy_kern = True options.symbol_cmap = True options.layout_closure = False options.prune_unicode_ranges = False options.passthrough_tables = False options.recalc_average_width = True options.ignore_missing_glyphs = True options.layout_scripts = subset["langsys"] options.drop_tables.remove("DSIG") options.no_subset_tables += ["DSIG"] subsetter = Subsetter(options=options) subsetter.populate(subset["glyphlist"]) with TemporaryLogLevel(logging.WARNING): subsetter.subset(new) new = self._optimize(new, name, fmt) names = subset.get("names") if names: logger.info( f"Adding name entries to {name}.{fmt.value} susbet") self._setnames(new, names) self._buildwoff(new, name, fmt) self._save(new, name, fmt)
def subsetter(self, font, subset): """ use the noto fonts glyphsnames to subset fonts with premade subsettings """ options = Options() options.layout_features = "*" # keep all GSUB/GPOS features # options.no_layout_closure = True # TESTING options.glyph_names = False # keep post glyph names options.legacy_cmap = True # keep non-Unicode cmaps options.name_legacy = True # keep non-Unicode names options.name_IDs = ["*"] # keep all nameIDs options.name_languages = ["*"] # keep all name languages options.notdef_outline = False options.ignore_missing_glyphs = True options.prune_unicode_ranges = True options.recommended_glyphs = True subsetter = Subsetter(options=options) subsetter.populate(glyphs=subset) subsetter.subset(font) return font
def subsetFonts(family, writingSystem, flavor=["ttf"], familyNewName=" ", jsonpath=" ", keepFea=True): print(familyNewName) # if len(flavor) == 0: flavor = ["ttf"] latinProCodePageRange = [0, 1, 4, 7, 8] cyrProCodePageRange = [2] greekProCodePageRange = [3] ASCII = [0, 1] SecureSet = [0] coreArabicCodePageRange = [0, 6] unicodePageRangeDict = { "Cyrillic": latinProCodePageRange, "CyrillicPro": latinProCodePageRange, "Greek": greekProCodePageRange, "Latin": latinProCodePageRange, "ASCII": ASCII, "SecureSet": SecureSet, "Core_Arabic": coreArabicCodePageRange } pageRangeToApply = [] subsetFolder = "" for i in writingSystem: subsetFolder += i formats = ["ttf", "woff", "woff2"] toKeep = list() folder = getFolder(family) folderFonts = os.path.join(folder, "fonts") options = Options() options.layout_features = '*' # keep all GSUB/GPOS features # options.legacy_kern = True # keep kern table options.glyph_names = False # keep post glyph names options.legacy_cmap = True # keep non-Unicode cmaps options.symbol_cmap = True # keep Symbol cmaps options.name_legacy = True # keep non-Unicode names options.name_IDs = ['*'] # keep all nameIDs options.name_languages = ['*'] # keep all name languages options.notdef_outline = True # keep outline of .notdef options.ignore_missing_glyphs = True options.prune_unicode_ranges = True keep = [] if family in pan_european_fonts: jsonpath = "subsets/lgc_glyphset.json" elif family in arabic_fonts: jsonpath = "subsets/arabic_glyphset.json" keep, pageRangeToApply = readJsonStoredSubset(jsonpath, writingSystem) for i in flavor: if not os.path.exists(os.path.join(folderFonts, i.upper())): print(">> Make {} fonts.".format(family)) designSpace2Instances(family, i, secureSet=False) for i in flavor: fontspath = [os.path.join(folderFonts, i.upper(), font) \ for font in os.listdir(folder + "/fonts/" + i.upper())] for f in fontspath: if f.split(".")[-1] in formats: newfont = TTFont(f) for namerecord in newfont['name'].names: namerecord.string = namerecord.toUnicode() if namerecord.nameID == 2: WeightName = namerecord.string if namerecord.nameID == 17: WeightName = "".join(namerecord.string.split(" ")) # print(family, WeightName) subsetter = Subsetter(options=options) subsetter.populate(glyphs=keep) subsetter.subset(newfont) destination = os.path.join(folder, "fonts", subsetFolder + "_subset", "fonts") if not os.path.exists(os.path.join(destination, i.upper())): os.makedirs(os.path.join(destination, i.upper())) subsetName = family + subsetFolder + "-" + WeightName + "." + i newfont.save(os.path.join(destination, i.upper(), subsetName)) folder = family + "/fonts/" + subsetFolder + "_subset" if familyNewName != " ": renameFonts(folder, familyNewName, codePageRange=pageRangeToApply) else: familyNewName = family + subsetFolder renameFonts(folder, familyNewName, codePageRange=pageRangeToApply) shutil.rmtree(destination)
def main(args): """Subset a font (useful for making small test fonts). Args: args: list, arguments the user typed. """ parser = argparse.ArgumentParser() parser.add_argument('fontfile', help='Input font file') parser.add_argument('--subset_postfix', default='', help='Postfix to the subset extension') parser.add_argument('--text', default='', help='Text to include in the subset') parser.add_argument( '--unicodes', default='', help='Comma separated list of Unicode codepoints (hex) ' 'to include in the subset; eg, "e7,0xe8,U+00e9"') parser.add_argument('--glyphs', default='', help='Comma separated list of glyph IDs (decimal) to ' 'include in the subset; eg, "1,27"') parser.add_argument('--hinting', default=False, action='store_true', help='Enable hinting if specified, no hinting if not ' 'present') cmd_args = parser.parse_args(args) options = Options() # Definitely want the .notdef glyph and outlines. options.notdef_glyph = True options.notdef_outline = True # Get the item. to keep in the subset. text = cmd_args.text unicodes_str = cmd_args.unicodes.lower().replace('0x', '').replace('u+', '') # TODO(bstell) replace this whole files by using the new subset.py code unicodes_input = [c for c in unicodes_str.split(',') if c] unicodes = [] for c in unicodes_input: if '-' in c: uni_range = c.split('-') uni_range_expanded = range(int(uni_range[0], 16), int(uni_range[1], 16) + 1) unicodes.extend(uni_range_expanded) else: unicodes.append(int(c, 16)) #unicodes = [int(c, 16) for c in unicodes_input_expanded] glyphs = [int(c) for c in cmd_args.glyphs.split(',') if c] fontfile = cmd_args.fontfile options.hinting = cmd_args.hinting # False => no hinting options.hinting = True # hint stripping for CFF is currently broken dirname = os.path.dirname(fontfile) basename = os.path.basename(fontfile) filename, extension = os.path.splitext(basename) subset_postfix = cmd_args.subset_postfix output_file = dirname + '/' + filename + '_subset' + subset_postfix + extension print "output_file =", output_file font = load_font(fontfile, options, lazy=False) subsetter = Subsetter(options) subsetter.populate(text=text, unicodes=unicodes, glyphs=glyphs) subsetter.subset(font) save_font(font, output_file, options)