def DISABLED_test_check_glyphnames_max_length(): """ Check that glyph names do not exceed max length. """ from fontbakery.profiles.universal import com_google_fonts_check_glyphnames_max_length as check import defcon import ufo2ft # TTF test_font = defcon.Font(TEST_FILE("test.ufo")) test_ttf = ufo2ft.compileTTF(test_font) status, _ = list(check(test_ttf))[-1] assert status == PASS test_glyph = defcon.Glyph() test_glyph.unicode = 0x1234 test_glyph.name = ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") test_font.insertGlyph(test_glyph) test_ttf = ufo2ft.compileTTF(test_font, useProductionNames=False) status, _ = list(check(test_ttf))[-1] assert status == FAIL test_ttf = ufo2ft.compileTTF(test_font, useProductionNames=True) status, _ = list(check(test_ttf))[-1] assert status == PASS # Upgrade to post format 3.0 and roundtrip data to update TTF object. test_ttf["post"].formatType = 3.0 test_file = io.BytesIO() test_ttf.save(test_file) test_ttf = TTFont(test_file) status, message = list(check(test_ttf))[-1] assert status == PASS assert "format 3.0" in message del test_font, test_ttf, test_file # Prevent copypasta errors. # CFF test_font = defcon.Font(TEST_FILE("test.ufo")) test_otf = ufo2ft.compileOTF(test_font) status, _ = list(check(test_otf))[-1] assert status == PASS test_font.insertGlyph(test_glyph) test_otf = ufo2ft.compileOTF(test_font, useProductionNames=False) status, _ = list(check(test_otf))[-1] assert status == FAIL test_otf = ufo2ft.compileOTF(test_font, useProductionNames=True) status, _ = list(check(test_otf))[-1] assert status == PASS
def save_otf(self, ufo, is_instance=False, mti_feafiles=None, kern_writer=KernFeatureWriter): """Build OTF from UFO.""" otf_path = self._output_path(ufo, 'otf', is_instance) otf = compileOTF(ufo, kernWriter=kern_writer) otf.save(otf_path)
def build(args): ufo = merge(args) setInfo(ufo.info, args.version) buildExtraGlyphs(ufo) removeOverlap(ufo) if args.out_file.endswith(".ttf"): otf = compileTTF(ufo) else: otf = compileOTF(ufo) otf = subsetGlyphs(otf, ufo) return otf
def generate_and_write_autohinted_instance( instantiator: instantiator.Instantiator, instance_descriptor: fontTools.designspaceLib.InstanceDescriptor, output_dir: Path, psautohint: str, ): # 3. Generate instance UFO. instance = instantiator.generate_instance(instance_descriptor) file_stem = f"{instance.info.familyName}-{instance.info.styleName}".replace(" ", "") # 3.5. Optionally write instance UFO to disk, for debugging. # instance.save(output_dir / f"{file_stem}.ufo", overwrite=True) # 4. Compile and write instance OTF to disk. instance_font = ufo2ft.compileOTF(instance, removeOverlaps=True, inplace=True) output_path = output_dir / f"{file_stem}.otf" instance_font.save(output_path) # 5. Run psautohint on it. subprocess.run([psautohint, str(output_path)])
def save_otf(self, ufo, is_instance=False, kern_writer=KernFeatureWriter): """Build OTF from UFO.""" otf_path = self._output_path(ufo, 'otf', is_instance) otf = compileOTF(ufo, kernWriter=kern_writer) otf.save(otf_path)
def save_otfs(self, ufos, ttf=False, is_instance=False, interpolatable=False, use_afdko=False, autohint=None, subset=None, use_production_names=None, subroutinize=False, interpolate_layout_from=None, interpolate_layout_dir=None, output_path=None, output_dir=None, kern_writer_class=None, mark_writer_class=None, inplace=True): """Build OpenType binaries from UFOs. Args: ufos: Font objects to compile. ttf: If True, build fonts with TrueType outlines and .ttf extension. is_instance: If output fonts are instances, for generating paths. interpolatable: If output is interpolatable, for generating paths. use_afdko: If True, use AFDKO to compile feature source. autohint: Parameters to provide to ttfautohint. If not provided, the autohinting step is skipped. subset: Whether to subset the output according to data in the UFOs. If not provided, also determined by flags in the UFOs. use_production_names: Whether to use production glyph names in the output. If not provided, determined by flags in the UFOs. subroutinize: If True, subroutinize CFF outlines in output. interpolate_layout_from: A designspace path to give varLib for interpolating layout tables to use in output. interpolate_layout_dir: Directory containing the compiled master fonts to use for interpolating binary layout tables. output_path: output font file path. Only works when the input 'ufos' list contains a single font. output_dir: directory where to save output files. Mutually exclusive with 'output_path' argument. kern_writer_class: Class overriding ufo2ft's KernFeatureWriter. mark_writer_class: Class overriding ufo2ft's MarkFeatureWriter. """ assert not (output_path and output_dir), "mutually exclusive args" if output_path is not None and len(ufos) > 1: raise ValueError("output_path requires a single input") ext = 'ttf' if ttf else 'otf' fea_compiler = FDKFeatureCompiler if use_afdko else FeatureCompiler if kern_writer_class is not None: logger.info("Using %r", kern_writer_class.__module__) if mark_writer_class is not None: logger.info("Using %r", mark_writer_class.__module__) if interpolate_layout_from is not None: if interpolate_layout_dir is None: interpolate_layout_dir = self._output_dir( ext, is_instance=False, interpolatable=interpolatable) finder = partial(_varLib_finder, directory=interpolate_layout_dir, ext=ext) do_autohint = ttf and autohint is not None for ufo in ufos: name = self._font_name(ufo) logger.info('Saving %s for %s' % (ext.upper(), name)) if use_production_names is None: use_production_names = not ufo.lib.get( GLYPHS_PREFIX + "Don't use Production Names") compiler_options = dict( featureCompilerClass=fea_compiler, kernWriterClass=kern_writer_class, markWriterClass=mark_writer_class, glyphOrder=ufo.lib.get(PUBLIC_PREFIX + 'glyphOrder'), useProductionNames=use_production_names, inplace=True, # avoid extra copy ) if ttf: font = compileTTF(ufo, convertCubics=False, **compiler_options) else: font = compileOTF(ufo, optimizeCFF=subroutinize, **compiler_options) if interpolate_layout_from is not None: master_locations, instance_locations = self._designspace_locations( interpolate_layout_from) loc = instance_locations[_normpath(ufo.path)] gpos_src = interpolate_layout(interpolate_layout_from, loc, finder, mapped=True) font['GPOS'] = gpos_src['GPOS'] gsub_src = TTFont( finder(self._closest_location(master_locations, loc))) if 'GDEF' in gsub_src: font['GDEF'] = gsub_src['GDEF'] if 'GSUB' in gsub_src: font['GSUB'] = gsub_src['GSUB'] if do_autohint: # if we are autohinting, we save the unhinted font to a # temporary path, and the hinted one to the final destination fd, otf_path = tempfile.mkstemp("." + ext) os.close(fd) elif output_path is None: otf_path = self._output_path(ufo, ext, is_instance, interpolatable, output_dir=output_dir) else: otf_path = output_path font.save(otf_path) if subset is None: export_key = GLYPHS_PREFIX + 'Glyphs.Export' subset = ((GLYPHS_PREFIX + 'Keep Glyphs') in ufo.lib or any( glyph.lib.get(export_key, True) is False for glyph in ufo)) if subset: self.subset_otf_from_ufo(otf_path, ufo) if not do_autohint: continue if output_path is not None: hinted_otf_path = output_path else: hinted_otf_path = self._output_path(ufo, ext, is_instance, interpolatable, autohinted=True, output_dir=output_dir) try: ttfautohint(otf_path, hinted_otf_path, args=autohint) except TTFAError: # copy unhinted font to destination before re-raising error shutil.copyfile(otf_path, hinted_otf_path) raise finally: # must clean up temp file os.remove(otf_path)
def TTFontFactory(font, useProductionNames=False, optimizeCff=False): otf = compileOTF( font, useProductionNames=useProductionNames, optimizeCff=optimizeCff) return otf
def test_TestFont_CFF(self): self.expectTTX(compileOTF(loadUFO("TestFont.ufo")), "TestFont-CFF.ttx")
def test_optimizeCFF_specialize(self, testufo, cff_version, expected_ttx): otf = compileOTF(testufo, optimizeCFF=1, cffVersion=cff_version) expectTTX(otf, expected_ttx)
def test_TestFont_CFF(self, testufo): otf = compileOTF(testufo) expectTTX(otf, "TestFont-CFF.ttx")
def test_removeOverlaps_CFF(self, testufo): otf = compileOTF(testufo, removeOverlaps=True) expectTTX(otf, "TestFont-NoOverlaps-CFF.ttx")
def test_optimizeCFF_specialize(self, testufo): otf = compileOTF(testufo, optimizeCFF=1) expectTTX(otf, "TestFont-Specialized-CFF.ttx")
def testTestFont(self): # We have specific unit tests for CFF vs TrueType output, but we run # an integration test here to make sure things work end-to-end. # No need to test both formats for every single test case. self.expectTTX(compileTTF(loadUFO("TestFont.ufo")), "TestFont.ttx") self.expectTTX(compileOTF(loadUFO("TestFont.ufo")), "TestFont-CFF.ttx")
import extractor import defcon # from fontTools.ttLib import TTFont from ufo2ft import compileOTF ufo = defcon.Font() # Take the font generated by FL5 from the VFB and extract it to UFO extractor.extractUFO("data/ibm_plex/IBM Plex Serif-Text-FL.otf", ufo) # Save the extracted UFO ufo.save("data/ibm_plex/IBM Plex Serif-Text-FL_extracted.otf.ufo") ufo = defcon.Font("data/ibm_plex/IBM Plex Serif-Text-FL_extracted.otf.ufo") # Build a new TTF from the extracted UFO ttf = compileOTF(ufo) ttf.save("data/ibm_plex/IBM Plex Serif-Text-ufo2ft.otf") # Force recompilation by closing and reopening the font; not needed # ttf.close() # ttf = TTFont("data/ibm_plex/IBM Plex Serif-Text-ufo2ft.ttf") # Also save TTX dump ttf.saveXML("data/ibm_plex/IBM Plex Serif-Text-ufo2ft.otf.ttx") ttf.saveXML("data/ibm_plex/IBM Plex Serif-Text-FL.otf.ttx") # ufo = defcon.Font() # extractor.extractUFO("data/font_a/font-normal-fl.ttf", ufo) # ufo.save("data/font_a/font-normal-fl_extracted.ufo") # ufo = defcon.Font("data/font_a/font-normal-fl_extracted.ufo") # ttf = compileTTF(ufo)
def test_removeOverlaps_CFF(self): self.expectTTX( compileOTF(loadUFO("TestFont.ufo"), removeOverlaps=True), "TestFont-NoOverlaps-CFF.ttx")
from defcon import Font from ufo2ft import compileOTF ufo = Font('removeOverlaps_error.ufo') ufo.info.xHeight = 300 ufo.info.capHeight = 700 otf = compileOTF(ufo, removeOverlaps=True) otf.save('removeOverlaps_error.otf')
def test_optimizeCFF_subroutinize(self, testufo): otf = compileOTF(testufo, optimizeCFF=2) expectTTX(otf, "TestFont-CFF.ttx")
def save_otfs(self, ufos, ttf=False, is_instance=False, interpolatable=False, use_afdko=False, autohint=None, subset=None, use_production_names=None, subroutinize=False, interpolate_layout_from=None, kern_writer_class=None, mark_writer_class=None): """Build OpenType binaries from UFOs. Args: ufos: Font objects to compile. ttf: If True, build fonts with TrueType outlines and .ttf extension. is_instance: If output fonts are instances, for generating paths. interpolatable: If output is interpolatable, for generating paths. use_afdko: If True, use AFDKO to compile feature source. autohint: Parameters to provide to ttfautohint. If not provided, the autohinting step is skipped. subset: Whether to subset the output according to data in the UFOs. If not provided, also determined by flags in the UFOs. use_production_names: Whether to use production glyph names in the output. If not provided, determined by flags in the UFOs. subroutinize: If True, subroutinize CFF outlines in output. interpolate_layout_from: A designspace path to give varLib for interpolating layout tables to use in output. kern_writer_class: Class overriding ufo2ft's KernFeatureWriter. mark_writer_class: Class overriding ufo2ft's MarkFeatureWriter. """ ext = 'ttf' if ttf else 'otf' fea_compiler = FDKFeatureCompiler if use_afdko else FeatureCompiler if kern_writer_class is None: kern_writer_class = KernFeatureWriter else: logger.info("Using %r", kern_writer_class.__module__) if mark_writer_class is None: mark_writer_class = MarkFeatureWriter else: logger.info("Using %r", mark_writer_class.__module__) if interpolate_layout_from is not None: master_locations, instance_locations = self._designspace_locations( interpolate_layout_from) ufod = self._output_dir('ufo', False, interpolatable) otfd = self._output_dir(ext, False, interpolatable) finder = lambda s: s.replace(ufod, otfd).replace('.ufo', '.' + ext) for ufo in ufos: name = self._font_name(ufo) logger.info('Saving %s for %s' % (ext.upper(), name)) otf_path = self._output_path(ufo, ext, is_instance, interpolatable) if use_production_names is None: use_production_names = not ufo.lib.get( GLYPHS_PREFIX + "Don't use Production Names") compiler_options = dict(featureCompilerClass=fea_compiler, kernWriterClass=kern_writer_class, markWriterClass=mark_writer_class, glyphOrder=ufo.lib.get(PUBLIC_PREFIX + 'glyphOrder'), useProductionNames=use_production_names) if ttf: font = compileTTF(ufo, convertCubics=False, **compiler_options) else: font = compileOTF(ufo, optimizeCFF=subroutinize, **compiler_options) if interpolate_layout_from is not None: loc = instance_locations[ufo.path] gpos_src = interpolate_layout(interpolate_layout_from, loc, finder, mapped=True) font['GPOS'] = gpos_src['GPOS'] gsub_src = TTFont( finder(self._closest_location(master_locations, loc))) font['GDEF'] = gsub_src['GDEF'] font['GSUB'] = gsub_src['GSUB'] font.save(otf_path) if subset is None: export_key = GLYPHS_PREFIX + 'Glyphs.Export' subset = ((GLYPHS_PREFIX + 'Keep Glyphs') in ufo.lib or any( glyph.lib.get(export_key, True) is False for glyph in ufo)) if subset: self.subset_otf_from_ufo(otf_path, ufo) if ttf and autohint is not None: hinted_otf_path = self._output_path(ufo, ext, is_instance, interpolatable, autohinted=True) ttfautohint(otf_path, hinted_otf_path, args=autohint)
def test_removeOverlaps_CFF_pathops(self, testufo): otf = compileOTF(testufo, removeOverlaps=True, overlapsBackend="pathops") expectTTX(otf, "TestFont-NoOverlaps-CFF-pathops.ttx")
def TTFontFactory(font): otf = compileOTF(font) return otf
def test_optimizeCFF_none(self, testufo): otf = compileOTF(testufo, optimizeCFF=0) expectTTX(otf, "TestFont-NoOptimize-CFF.ttx")