def execute(self, pipedata): task = self.bakery.logging_task('Optimizing TTF') if self.bakery.forcerun: return try: for filename in pipedata['bin_files']: # convert the ttf to a ttx file - this may fail font = fontforge.open(op.join(self.builddir, filename)) glyphs = [] for g in font.glyphs(): if not g.codepoint: continue glyphs.append(g.codepoint) from fontTools import subset args = [op.join(self.builddir, filename)] + glyphs args += ['--layout-features="*"'] subset.main(args) self.bakery.logging_cmd('pyftsubset %s' % ' '.join(args)) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" cmd = "ls -l '%s'* %s" % (filename, comment) run(cmd, cwd=self.builddir, log=self.bakery.log) # move ttx files to src shutil.move(op.join(self.builddir, filename + '.subset'), op.join(self.builddir, filename), log=self.bakery.log) self.bakery.logging_task_done(task) except: self.bakery.logging_task_done(task, failed=True) raise
def fix_metrics(testcase): """ Fix vmet table with actual min and max values """ targetpath = os.path.dirname(testcase.operator.path) SCRIPTPATH = 'fontbakery-fix-vertical-metrics.py' directory = UpstreamDirectory(targetpath) paths = [] for f in directory.BIN: path = op.join(targetpath, f) paths.append(path) command = "$ {0} --autofix {1}" command = command.format(SCRIPTPATH, ' '.join(paths)) if hasattr(testcase, 'operator'): testcase.operator.debug(command) metricfix(paths) for path in paths: try: shutil.move(path + '.fix', path, log=testcase.operator.logger) except IOError: pass command = "$ {0} {1}".format(SCRIPTPATH, ' '.join(paths)) if hasattr(testcase, 'operator'): testcase.operator.debug(command) testcase.operator.debug(metricview(paths))
def optimize(self, builddir): filename = self.postscript_fontname # convert the ttf to a ttx file - this may fail font = fontforge.open(op.join(builddir, filename) + '.ttf') glyphs = [] for g in font.glyphs(): if not g.codepoint: continue glyphs.append(g.codepoint) from fontTools import subset args = [op.join(builddir, filename) + '.ttf'] + glyphs args += ['--layout-features="*"'] subset.main(args) self.stdout_pipe.write('$ pyftsubset %s' % ' '.join(args)) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" cmd = "ls -l '%s.ttf'* %s" % (filename, comment) run(cmd, cwd=builddir, log=self.stdout_pipe) # move ttx files to src shutil.move(op.join(builddir, filename + '.ttf.subset'), op.join(builddir, filename + '.ttf'), log=self.stdout_pipe)
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 execute_pyftsubset(self, pipedata, subsetname, name, glyphs="", args=""): from fontTools import subset argv = [op.join(self.builddir, name)] + glyphs.split() # argv += ['--notdef-outline', '--name-IDs="*"', '--hinting'] override_argv = [] if pipedata.get('pyftsubset'): override_argv = pipedata['pyftsubset'].split() if pipedata.get('pyftsubset.%s' % subsetname): override_argv = pipedata['pyftsubset.%s' % subsetname].split() argv = argv + override_argv subset.main(argv) self.bakery.logging_cmd('pyftsubset %s' % ' '.join(argv)) # need to move result .subset file to avoid overwrite with # next subset shutil.move(op.join(self.builddir, name) + '.subset', op.join(self.builddir, name)[:-4] + '.' + subsetname, log=self.bakery.log)
def fix_fstype_to_zero(font_path, log=None): """ Fix fsType to zero """ SCRIPTPATH = 'bakery-fstype-fix.py' command = "{0} {1} --autofix {2}".format(PYPATH, SCRIPTPATH, font_path) logging(log, command) reset_fstype(font_path) shutil.move(font_path + '.fix', font_path, log=log)
def fix_name_ascii(font_path, log=None): """ Replacing non ascii names in copyright """ SCRIPTPATH = 'bakery-ascii-fix.py' command = "{0} {1} {2}".format(PYPATH, SCRIPTPATH, font_path) logging(log, command) fix_name_table(font_path) shutil.move(font_path + '.fix', font_path, log=log)
def rename(testcase): targetpath = testcase.operator.path new_targetpath = op.join(op.dirname(targetpath), testcase.expectedfilename) shutil.move(targetpath, new_targetpath, log=testcase.operator.logger) testcase.operator.path = new_targetpath
def execute(self, pipedata): if self.bakery.forcerun: return rename_executed = False newfiles = [] task = None for i, filepath in enumerate(pipedata['bin_files']): path = op.join(self.builddir, filepath) font = ttLib.TTFont(path) psname = self.get_psname(font) if psname: if op.basename(path) != psname: if not rename_executed: msg = 'Rename built files with PS Naming' task = self.bakery.logging_task(msg) rename_executed = True try: shutil.move(path, op.join(op.dirname(path), psname), log=self.bakery.log) except: if task: self.bakery.logging_task_done(task, failed=True) raise newfiles.append(filepath.replace(op.basename(filepath), psname)) else: newfiles.append(filepath) if task: self.bakery.logging_task_done(task) pipedata['bin_files'] = newfiles return pipedata
def replace_origfont(testcase): targetpath = testcase.operator.path command = "$ mv {0}.fix {0}".format(targetpath) if hasattr(testcase, 'operator'): testcase.operator.debug(command) fixed_font_path = '{}.fix'.format(targetpath) if op.exists(fixed_font_path): shutil.move(fixed_font_path, targetpath)
def run(self, filename, pipedata): if not pipedata.get('fontcrunch'): return # run fontcrunch only if user set flag in config filename = os.path.join(self.builddir, filename) self.bakery.logging_raw('### Fontcrunch {}\n'.format(filename)) fontcrunch.optimize(filename, '{}.crunched'.format(filename)) shutil.move('{}.crunched'.format(filename), filename) return 1
def fix_ttf_stylenames(font_path, log=None): """ Fix style names """ SCRIPTPATH = 'bakery-stylenames-fix.py' command = "{0} {1} --autofix {2}".format(PYPATH, SCRIPTPATH, font_path) logging(log, command) fix_style_names(font_path) shutil.move(font_path + '.fix', font_path, log=log)
def fix_fstype_to_zero(testcase): """ Fix fsType to zero """ targetpath = testcase.operator.path SCRIPTPATH = 'fontbakery-fix-fstype.py' command = "$ {0} --autofix {1}".format(SCRIPTPATH, targetpath) if hasattr(testcase, 'operator'): testcase.operator.debug(command) reset_fstype(targetpath) shutil.move(targetpath + '.fix', targetpath, log=testcase.operator.logger)
def fix_nbsp(font_path, log=None): """ Fix width for space and nbsp """ SCRIPTPATH = 'bakery-nbsp-fix.py' command = "{0} {1} {2}".format(PYPATH, SCRIPTPATH, font_path) logging(log, command) checkAndFix(font_path) command = "mv {0}.fix {0}".format(font_path) logging(log, command) shutil.move(font_path + '.fix', font_path, log=log)
def fix_name_ascii(testcase): """ Replacing non ascii names in copyright """ targetpath = testcase.operator.path SCRIPTPATH = 'fontbakery-fix-ascii-fontmetadata.py' command = "$ {0} {1}".format(SCRIPTPATH, targetpath) if hasattr(testcase, 'operator'): testcase.operator.debug(command) fix_name_table(targetpath) shutil.move(targetpath + '.fix', targetpath, log=testcase.operator.logger)
def movebin_to_builddir(self, files): result = [] for a in files: d = op.join(self.builddir, op.basename(a)[:-4] + '.ttf') s = op.join(self.builddir, a[:-4] + '.ttf') try: shellutil.move(s, d, log=self.bakery.logger) result.append(op.basename(a)[:-4] + '.ttf') except: pass return result
def movebin_to_builddir(self, files): result = [] for a in files: d = op.join(self.builddir, op.basename(a)[:-4] + '.ttf') s = op.join(self.builddir, a[:-4] + '.ttf') try: shellutil.move(s, d, log=self.bakery.log) result.append(op.basename(a)[:-4] + '.ttf') except: pass return result
def execute(self, pipedata, prefix=""): """ Run ttfautohint with project command line settings For each ttf file in result src folder, outputting them in the _out root, or just copy the ttfs there. """ # $ ttfautohint -l 7 -r 28 -G 0 -x 13 -w "" \ # -W -c original_font.ttf final_font.ttf params = pipedata.get('ttfautohint', '') if not params: return pipedata task = self.bakery.logging_task('Autohint TTFs (ttfautohint)') if self.bakery.forcerun: return if 'autohinting_sizes' not in pipedata: pipedata['autohinting_sizes'] = [] is_failed = False for filepath in pipedata['bin_files']: filepath = op.join(self.project_root, self.builddir, filepath) cmd = ("ttfautohint {params} {source}" " '{name}.autohint.ttf'").format(params=params.strip(), name=filepath[:-4], source=filepath) try: run(cmd, cwd=self.builddir, log=self.bakery.log) except: self.bakery.logging_err('TTFAutoHint is not available') self.bakery.logging_task_done(task, failed=True) is_failed = True break pipedata['autohinting_sizes'].append({ 'fontname': op.basename(filepath), 'origin': op.getsize(filepath), 'processed': op.getsize(filepath[:-4] + '.autohint.ttf') }) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" cmd = "ls -l %s.*ttf %s" % (filepath[:-4], comment) run(cmd, cwd=self.builddir, log=self.bakery.log) shellutil.move(filepath[:-4] + '.autohint.ttf', filepath, log=self.bakery.log) if not is_failed: self.bakery.logging_task_done(task) return pipedata
def after_copy(self, builddir): out_name = self.postscript_fontname + '.ttf' self.compile_ttx(builddir) if self.source.sfntVersion == 'OTTO': # OTF self.convert_otf2ttf(builddir) # If TTF already, move it up else: try: shutil.move(op.join(builddir, 'sources', out_name), op.join(builddir, out_name), log=self.stdout_pipe) except (OSError, IOError): pass
def run(self, filepath, pipedata): if not pipedata.get('ttfautohint', ''): return False self.bakery.logging_raw( '### Autohint TTFs (ttfautohint) {}\n'.format(filepath)) params = pipedata['ttfautohint'] filepath = op.join(self.project_root, self.builddir, filepath) cmd = ("ttfautohint {params} {source}" " '{name}.autohint.ttf'").format(params=params.strip(), name=filepath[:-4], source=filepath) try: run(cmd, cwd=self.builddir, log=self.bakery.logger) except: return False if 'autohinting_sizes' not in pipedata: pipedata['autohinting_sizes'] = [] origsize = op.getsize(filepath) autohintsize = op.getsize(filepath[:-4] + '.autohint.ttf') pipedata['autohinting_sizes'].append({ 'fontname': op.basename(filepath), 'origin': origsize, 'processed': autohintsize }) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" cmd = "ls -l %s.*ttf %s" % (filepath[:-4], comment) self.bakery.logging_cmd(cmd) statusmessage = "{0}: {1} bytes\n{2}: {3} bytes\n" self.bakery.logging_raw( statusmessage.format(filepath, origsize, filepath[:-4] + '.autohint.ttf', autohintsize)) shellutil.move(filepath[:-4] + '.autohint.ttf', filepath, log=self.bakery.logger) return 1
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 run(self, filepath, pipedata): if not pipedata.get('ttfautohint', ''): return False self.bakery.logging_raw('### Autohint TTFs (ttfautohint) {}\n'.format(filepath)) params = pipedata['ttfautohint'] filepath = op.join(self.project_root, self.builddir, filepath) cmd = ("ttfautohint {params} {source}" " '{name}.autohint.ttf'").format(params=params.strip(), name=filepath[:-4], source=filepath) try: run(cmd, cwd=self.builddir, log=self.bakery.logger) except: return False if 'autohinting_sizes' not in pipedata: pipedata['autohinting_sizes'] = [] origsize = op.getsize(filepath) autohintsize = op.getsize(filepath[:-4] + '.autohint.ttf') pipedata['autohinting_sizes'].append({ 'fontname': op.basename(filepath), 'origin': origsize, 'processed': autohintsize }) # compare filesizes TODO print analysis of this :) comment = "# look at the size savings of that subset process" cmd = "ls -l %s.*ttf %s" % (filepath[:-4], comment) self.bakery.logging_cmd(cmd) statusmessage = "{0}: {1} bytes\n{2}: {3} bytes\n" self.bakery.logging_raw(statusmessage.format(filepath, origsize, filepath[:-4] + '.autohint.ttf', autohintsize)) shellutil.move(filepath[:-4] + '.autohint.ttf', filepath, log=self.bakery.logger) return 1
def otf2ttf(self, filepath, pipedata): fontname = filepath[:-4] ttfpath = '{}.ttf'.format(op.basename(fontname)) path = '{}.otf'.format(op.basename(fontname)) if op.exists(op.join(self.builddir, 'sources', path)): _ = 'fontbakery-build-font2ttf.py {0}.otf {1}\n' self.bakery.logging_cmd(_.format(fontname, ttfpath)) try: convert(op.join(self.builddir, 'sources', path), op.join(self.builddir, 'sources', ttfpath), log=self.bakery.logger) os.remove(op.join(self.builddir, 'sources', path)) except Exception as ex: self.bakery.logging_err(ex.message) raise shellutil.move(op.join(self.builddir, 'sources', ttfpath), op.join(self.builddir, ttfpath), log=self.bakery.logger) self.run_processes(ttfpath, pipedata)
def fix_metrics(path, log=None): """ Fix vmet table with actual min and max values """ SCRIPTPATH = 'bakery-vmet-fix.py' from bakery_lint.metadata import FamilyMetadata family_metadata = FamilyMetadata(json.load(open(path))) paths = [] for f in family_metadata.fonts: path = op.join(op.dirname(path), f.filename) paths.append(path) command = "{0} {1} --autofix {2}" command = command.format(PYPATH, SCRIPTPATH, ' '.join(paths)) logging(log, command) metricfix(paths) for font_path in paths: shutil.move(font_path + '.fix', font_path, log=log) command = "{0} {1} {2}".format(PYPATH, SCRIPTPATH, ' '.join(paths)) logging(log, command) log.write(metricview(paths))