def buildStatic( self, ufo, # input UFO as filename string or defcon.Font object outputFilename, # output filename string cff=True, # true = makes CFF outlines. false = makes TTF outlines. **kwargs, # passed along to ufo2ft.compile*() ): if isinstance(ufo, str): ufo = Font(ufo) # update version to actual, real version. Must come after any call to setFontInfo. updateFontVersion(ufo, dummy=False, isVF=False) compilerOptions = dict( useProductionNames=True, inplace=True, # avoid extra copy removeOverlaps=True, overlapsBackend='pathops', # use Skia's pathops ) log.info("compiling %s -> %s (%s)", _LazyFontName(ufo), outputFilename, "OTF/CFF-2" if cff else "TTF") if cff: font = ufo2ft.compileOTF(ufo, **compilerOptions) else: # ttf font = ufo2ft.compileTTF(ufo, **compilerOptions) log.debug("writing %s", outputFilename) font.save(outputFilename)
def __call__(self, font, glyphSet=None): """Run this filter on all the included glyphs. Return the set of glyph names that were modified, if any. If `glyphSet` (dict) argument is provided, run the filter on the glyphs contained therein (which may be copies). Otherwise, run the filter in-place on the font's default glyph set. """ fontName = _LazyFontName(font) if glyphSet is not None and getattr(glyphSet, "name", None): logger.info("Running %s on %s-%s", self.name, fontName, glyphSet.name) else: logger.info("Running %s on %s", self.name, fontName) if glyphSet is None: glyphSet = _GlyphSet.from_layer(font) context = self.set_context(font, glyphSet) filter_ = self.filter include = self.include modified = context.modified with Timer() as t: # we sort the glyph names to make loop deterministic for glyphName in sorted(glyphSet.keys()): if glyphName in modified: continue glyph = glyphSet[glyphName] if include(glyph) and filter_(glyph): modified.add(glyphName) num = len(modified) if num > 0: logger.debug( "Took %.3fs to run %s on %d glyph%s", t, self.name, len(modified), "" if num == 1 else "s", ) return modified
def buildStatic( self, ufo, # input UFO as filename string or defcon.Font object outputFilename, # output filename string cff=True, # true = makes CFF outlines. false = makes TTF outlines. **kwargs, # passed along to ufo2ft.compile*() ): if isinstance(ufo, str): ufo = Font(ufo) # update version to actual, real version. Must come after any call to setFontInfo. updateFontVersion(ufo, dummy=False, isVF=False) # decompose some glyphs glyphNamesToDecompose = set() for g in ufo: directives = findGlyphDirectives(g.note) if 'decompose' in directives or (g.components and not composedGlyphIsTrivial(g)): glyphNamesToDecompose.add(g.name) self._decompose([ufo], glyphNamesToDecompose) compilerOptions = dict( useProductionNames=True, inplace=True, # avoid extra copy removeOverlaps=True, overlapsBackend='pathops', # use Skia's pathops ) log.info("compiling %s -> %s (%s)", _LazyFontName(ufo), outputFilename, "OTF/CFF-2" if cff else "TTF") if cff: font = ufo2ft.compileOTF(ufo, **compilerOptions) else: # ttf font = ufo2ft.compileTTF(ufo, **compilerOptions) log.debug("writing %s", outputFilename) font.save(outputFilename)
def compileInterpolatableTTFs( ufos, preProcessorClass=TTFInterpolatablePreProcessor, outlineCompilerClass=OutlineTTFCompiler, featureCompilerClass=None, featureWriters=None, glyphOrder=None, useProductionNames=None, cubicConversionError=None, reverseDirection=True, inplace=False, layerNames=None, skipExportGlyphs=None, ): """Create FontTools TrueType fonts from a list of UFOs with interpolatable outlines. Cubic curves are converted compatibly to quadratic curves using the Cu2Qu conversion algorithm. Return an iterator object that yields a TTFont instance for each UFO. *layerNames* refers to the layer names to use glyphs from in the order of the UFOs in *ufos*. By default, this is a list of `[None]` times the number of UFOs, i.e. using the default layer from all the UFOs. When the layerName is not None for a given UFO, the corresponding TTFont object will contain only a minimum set of tables ("head", "hmtx", "glyf", "loca", "maxp", "post" and "vmtx"), and no OpenType layout tables. *skipExportGlyphs* is a list or set of glyph names to not be exported to the final font. If these glyphs are used as components in any other glyph, those components get decomposed. If the parameter is not passed in, the union of all UFO's "public.skipExportGlyphs" lib keys will be used. If they don't exist, all glyphs are exported. UFO groups and kerning will be pruned of skipped glyphs. """ from ufo2ft.util import _LazyFontName if layerNames is None: layerNames = [None] * len(ufos) assert len(ufos) == len(layerNames) if skipExportGlyphs is None: skipExportGlyphs = set() for ufo in ufos: skipExportGlyphs.update(ufo.lib.get("public.skipExportGlyphs", [])) logger.info("Pre-processing glyphs") preProcessor = preProcessorClass( ufos, inplace=inplace, conversionError=cubicConversionError, reverseDirection=reverseDirection, layerNames=layerNames, skipExportGlyphs=skipExportGlyphs, ) glyphSets = preProcessor.process() for ufo, glyphSet, layerName in zip(ufos, glyphSets, layerNames): fontName = _LazyFontName(ufo) if layerName is not None: logger.info("Building OpenType tables for %s-%s", fontName, layerName) else: logger.info("Building OpenType tables for %s", fontName) outlineCompiler = outlineCompilerClass( ufo, glyphSet=glyphSet, glyphOrder=glyphOrder, tables=SPARSE_TTF_MASTER_TABLES if layerName else None, ) ttf = outlineCompiler.compile() # Only the default layer is likely to have all glyphs used in feature # code. if layerName is None: compileFeatures( ufo, ttf, glyphSet=glyphSet, featureWriters=featureWriters, featureCompilerClass=featureCompilerClass, ) postProcessor = PostProcessor(ttf, ufo, glyphSet=glyphSet) ttf = postProcessor.process(useProductionNames) if layerName is not None: # for sparse masters (i.e. containing only a subset of the glyphs), we # need to include the post table in order to store glyph names, so that # fontTools.varLib can interpolate glyphs with same name across masters. # However we want to prevent the underlinePosition/underlineThickness # fields in such sparse masters to be included when computing the deltas # for the MVAR table. Thus, we set them to this unlikely, limit value # (-36768) which is a signal varLib should ignore them when building MVAR. ttf["post"].underlinePosition = -0x8000 ttf["post"].underlineThickness = -0x8000 yield ttf