def test_apply_instance_data(tmpdir, instance_names): font = glyphsLib.GSFont(TESTFILE_PATH) instance_dir = "instances" designspace = glyphsLib.to_designspace(font, instance_dir=instance_dir) path = str(tmpdir / (font.familyName + '.designspace')) write_designspace_and_UFOs(designspace, path) builder = DesignSpaceDocumentReader(designspace.path, ufoVersion=3) if instance_names is None: # generate all instances builder.process() include_filenames = None else: # generate only selected instances for name in instance_names: builder.readInstance(("stylename", name)) # make relative filenames from paths returned by MutatorMath include_filenames = {os.path.relpath(instance_path, str(tmpdir)) for instance_path in builder.results.values()} ufos = apply_instance_data(designspace.path, include_filenames=include_filenames) for filename in include_filenames or (): assert os.path.isdir(str(tmpdir / filename)) assert len(ufos) == len(builder.results) assert isinstance(ufos[0], defcon.Font)
def _save_gsfont(font): f = glyphsLib.GSFont() f.familyName = font.info.familyName if "com.schriftgestaltung.appVersion" in font.lib: f.appVersion = font.lib["com.schriftgestaltung.appVersion"] if "com.schriftgestaltung.DisplayStrings" in font.lib: f.DisplayStrings = font.lib["com.schriftgestaltung.DisplayStrings"] if font.info.openTypeHeadCreated: f.date = _ufo_date_to_glyphs(font.info.openTypeHeadCreated) f.upm = font.info.unitsPerEm fontmaster = glyphsLib.GSFontMaster() if "com.schriftgestaltung.fontMasterID" in font.lib: fontmaster.id = font.lib["com.schriftgestaltung.fontMasterID"] f.masters = [fontmaster] # f.instances = [glyphsLib.GSInstance()] # f.instances[0].instanceInterpolations = {} fontmaster.ascender = font.info.ascender fontmaster.xHeight = font.info.xHeight fontmaster.capHeight = font.info.capHeight fontmaster.descender = font.info.descender for glyph in font.defaultLayer: _save_glyph(glyph, f, bbf=font) for g in font.groups: if "public.kern" in g: continue f.classes.append(glyphsLib.GSClass(g, " ".join(font.groups[g]))) _save_kerning(font.kerning, f, fontmaster.id) return f
def notExportedGlyphs(self): notExportedGlyphsList = [] GSft = glyphsLib.GSFont(self.sourcePath) for g in GSft.glyphs: if g.export is False: notExportedGlyphsList.append(g.name) return notExportedGlyphsList
def test_background_component_decompose(datadir): font = glyphsLib.GSFont(str(datadir.join("Recursion.glyphs"))) ds = to_designspace(font) for source in ds.sources: for layer in source.font.layers: for glyph in layer: if layer.name == "Apr 27 20, 17:59" and glyph.name == "B": continue assert not glyph.components ufo_rg = ds.sources[0].font assert ufo_rg.layers["public.background"]["A"].contours == ufo_rg[ "B"].contours assert (ufo_rg.layers["Apr 27 20, 17:57.background"]["A"].contours == ufo_rg["B"].contours) assert ufo_rg.layers["public.background"]["B"].contours == ufo_rg[ "A"].contours assert len(ufo_rg.layers["Apr 27 20, 17:59.background"]["B"].contours) == 2 assert ufo_rg.layers["Apr 27 20, 17:59"]["B"].components ufo_bd = ds.sources[1].font assert ufo_bd.layers["public.background"]["A"].contours == ufo_bd[ "B"].contours assert (ufo_bd.layers["Apr 27 20, 17:57.background"]["A"].contours == ufo_bd["B"].contours) assert ufo_bd.layers["public.background"]["B"].contours == ufo_bd[ "A"].contours assert (ufo_bd.layers["Apr 27 20, 17:59.background"]["B"].contours == ufo_bd["A"].contours)
def main(): parser = argparse.ArgumentParser( "Translate all .glyphs files into UFO+designspace in the specified directories." ) parser.add_argument( "-o", "--out", metavar="OUTPUT_DIR", default="ufos", help="Output directory" ) parser.add_argument("directories", nargs="*") args = parser.parse_args() for directory in args.directories: files = glyphs_files(directory) for filename in files: try: # Code for glyphsLib with roundtrip from glyphsLib.builder import to_designspace font = glyphsLib.GSFont(filename) designspace = to_designspace(font) dsname = font.familyName.replace(" ", "") + ".designspace" designspace.write(os.path.join(args.out, dsname)) except ImportError: # This is the version that works with glyphsLib 2.1.0 glyphsLib.build_masters( filename, master_dir=args.out, designspace_instance_dir=args.out )
def build_master_ufos( self, glyphs_path, designspace_path=None, master_dir=None, instance_dir=None, family_name=None, mti_source=None, write_skipexportglyphs=True, ): """Build UFOs and MutatorMath designspace from Glyphs source.""" import glyphsLib if master_dir is None: master_dir = self._output_dir("ufo") if not os.path.isdir(master_dir): os.mkdir(master_dir) if instance_dir is None: instance_dir = self._output_dir("ufo", is_instance=True) if not os.path.isdir(instance_dir): os.mkdir(instance_dir) font = glyphsLib.GSFont(glyphs_path) if designspace_path is not None: designspace_dir = os.path.dirname(designspace_path) else: designspace_dir = master_dir # glyphsLib.to_designspace expects instance_dir to be relative instance_dir = os.path.relpath(instance_dir, designspace_dir) designspace = glyphsLib.to_designspace( font, family_name=family_name, instance_dir=instance_dir, write_skipexportglyphs=write_skipexportglyphs, ) masters = {} # multiple sources can have the same font/filename (but different layer), # we want to save a font only once for source in designspace.sources: if source.filename in masters: assert source.font is masters[source.filename] continue ufo_path = os.path.join(master_dir, source.filename) # no need to also set the relative 'filename' attribute as that # will be auto-updated on writing the designspace document source.path = ufo_path source.font.save(ufo_path) masters[source.filename] = source.font if designspace_path is None: designspace_path = os.path.join(master_dir, designspace.filename) designspace.write(designspace_path) if mti_source: self.add_mti_features_to_master_ufos(mti_source, masters.values()) return designspace_path
def test_background_component_decompose_missing(datadir): font = glyphsLib.GSFont(str(datadir.join("Recursion.glyphs"))) layer = font.glyphs["B"].layers[ "DB4D7D04-C02D-48DE-811E-03AA03052DD2"].background layer.components.append(GSComponent("xxx")) with pytest.raises(MissingComponentError): to_designspace(font)
def test_ufo_filename_custom_param_plus_legacy(): """Test that new-style UFO_FILENAME_CUSTOM_PARAM overrides legacy (UFO_FILENAME_KEY|FULL_FILENAME_KEY).""" font = glyphsLib.GSFont(os.path.join(DATA, "UFOFilenameTest.glyphs")) font.masters[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] = "aaa.ufo" font.instances[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] = "bbb.ufo" ds = glyphsLib.to_designspace(font, minimize_glyphs_diffs=True) assert ds.sources[0].filename == "aaa.ufo" assert ds.instances[0].filename == "bbb.ufo"
def test_ufo_filename_custom_param_instance_empty(): font = glyphsLib.GSFont(os.path.join(DATA, "UFOFilenameTest.glyphs")) font.masters[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] = "aaa.ufo" del font.instances[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] del font.instances[0].customParameters[FULL_FILENAME_KEY] ds = glyphsLib.to_designspace(font, minimize_glyphs_diffs=True) assert ds.sources[0].filename == "aaa.ufo" # Instance filename should be whatever the default is. assert ds.instances[0].filename == "instance_ufos/NewFont-Regular.ufo"
def load(filename, **kwargs): gsfont = glyphsLib.GSFont(filename) gsmaster = None if "master" not in kwargs or not kwargs["master"]: gsmaster = gsfont.masters[0] else: wanted = kwargs["master"] for m in gsfont.masters: if m.name == wanted: gsmaster = m break if not gsmaster: raise ValueError(f"Master {wanted} not found in {filename}") return _load_gsfont(gsmaster)
def load_masters(self): if self.masters: return for src in self.config["sources"]: if src.endswith("glyphs"): gsfont = glyphsLib.GSFont(src) self.masters[src] = [] for master in gsfont.masters: self.masters[src].append( Babelfont.open(src, master=master.name)) elif src.endswith("designspace"): continue else: self.masters[src] = [Babelfont.open(src)]
def build_master_ufos(self, glyphs_path, designspace_path=None, master_dir=None, instance_dir=None, family_name=None, mti_source=None): """Build UFOs and MutatorMath designspace from Glyphs source.""" import glyphsLib if master_dir is None: master_dir = self._output_dir('ufo') if not os.path.isdir(master_dir): os.mkdir(master_dir) if instance_dir is None: instance_dir = self._output_dir('ufo', is_instance=True) if not os.path.isdir(instance_dir): os.mkdir(instance_dir) font = glyphsLib.GSFont(glyphs_path) if designspace_path is not None: designspace_dir = os.path.dirname(designspace_path) else: designspace_dir = master_dir # glyphsLib.to_designspace expects instance_dir to be relative instance_dir = os.path.relpath(instance_dir, designspace_dir) designspace = glyphsLib.to_designspace(font, family_name=family_name, instance_dir=instance_dir) masters = [] for source in designspace.sources: masters.append(source.font) ufo_path = os.path.join(master_dir, source.filename) # no need to also set the relative 'filename' attribute as that # will be auto-updated on writing the designspace document source.path = ufo_path source.font.save(ufo_path) if designspace_path is None: designspace_path = os.path.join(master_dir, designspace.filename) designspace.write(designspace_path) if mti_source: self.add_mti_features_to_master_ufos(mti_source, masters) return designspace_path
def test_apply_instance_data(tmpdir, instance_names, ufo_module): font = glyphsLib.GSFont(os.path.join(DATA, "GlyphsUnitTestSans.glyphs")) instance_dir = "instances" designspace = glyphsLib.to_designspace(font, instance_dir=instance_dir) path = str(tmpdir / (font.familyName + ".designspace")) write_designspace_and_UFOs(designspace, path) test_designspace = DesignSpaceDocument() test_designspace.read(designspace.path) if instance_names is None: # Collect all instances. test_instances = [instance.filename for instance in test_designspace.instances] else: # Collect only selected instances. test_instances = [ instance.filename for instance in test_designspace.instances if instance.styleName in instance_names ] # Generate dummy UFOs for collected instances so we don't actually need to # interpolate. tmpdir.mkdir(instance_dir) for instance in test_instances: ufo = ufo_module.Font() ufo.save(str(tmpdir / instance)) ufos = apply_instance_data(designspace.path, include_filenames=test_instances) for filename in test_instances: assert os.path.isdir(str(tmpdir / filename)) assert len(ufos) == len(test_instances) for ufo in ufos: assert ufo.info.openTypeOS2WeightClass in { 100, 200, 300, 400, 500, 700, 900, 357, } assert ufo.info.openTypeOS2WidthClass is None # GlyphsUnitTestSans is wght only
def test_glyphs_font_without_propagated_anchors(datadir): font = glyphsLib.GSFont(str(datadir.join("AnchorPropagation.glyphs"))) # These two layers are supposed to be devoid of anchors in the .glyphs source # with Glyphs.app expecting to propagate them automatically upon font generation assert len(font.glyphs["lam_alefHamzaabove-ar"].layers[0].anchors) == 0 assert len(font.glyphs["shadda_fatha-ar"].layers[0].anchors) == 0 # check for `top_1` anchor of lam_alef-ar.short to be in its original location layer = font.glyphs["lam_alef-ar.short"].layers[0] assert "top_1" in [x.name for x in layer.anchors] assert layer.anchors["top_1"].position.x == 498 assert layer.anchors["top_1"].position.y == 760 # check for `top_2` anchor of lam_alef-ar.short to be in its original location layer = font.glyphs["lam_alef-ar.short"].layers[0] assert "top_2" in [x.name for x in layer.anchors] assert layer.anchors["top_2"].position.x == 130 assert layer.anchors["top_2"].position.y == 628
def test_gslayer_load(): testfile = glyphsLib.GSFont("tests/data/Test1.glyphs") a = testfile.glyphs[0].layers[0] a_layer = glyphs._load_gslayer(a, None) assert isinstance(a_layer, Glyph) assert len(a_layer.contours) == 2 assert len(a_layer.contours[0].points) == 8 assert len(a_layer.contours[1].points) == 4 assert a_layer.contours[0].points[0].x == 345 assert a_layer.contours[0].points[0].y == 700 assert a_layer.leftMargin == 25 assert a_layer.rightMargin == 25 assert a_layer.bounds == (25, 0, 505, 700) assert a_layer.width == 530 b = testfile.glyphs[1].layers[0] b_layer = glyphs._load_gslayer(b, None) assert isinstance(b_layer, Glyph) assert len(b_layer.contours) == 3 assert b_layer.leftMargin == 65 assert b_layer.rightMargin == 35
def get_family_name(self): """Ensure that all source files have the same family name""" names = set() for fp in self.config["sources"]: if fp.endswith("glyphs"): src = glyphsLib.GSFont(fp) names.add(src.familyName) elif fp.endswith("ufo"): src = Font(fp) names.add(src.info.familyName) elif fp.endswith("designspace"): ds = designspaceLib.DesignSpaceDocument.fromfile( self.config["sources"][0]) names.add(ds.sources[0].familyName) else: raise ValueError(f"{fp} not a supported source file!") if len(names) > 1: raise ValueError( f"Inconsistent family names in sources {names}. Set familyName in config instead" ) return list(names)[0]
def test_ufo_filename_custom_param(): """Test that new-style UFO_FILENAME_CUSTOM_PARAM is written instead of (UFO_FILENAME_KEY|FULL_FILENAME_KEY).""" font = glyphsLib.GSFont(os.path.join(DATA, "UFOFilenameTest.glyphs")) ds = glyphsLib.to_designspace(font, minimize_glyphs_diffs=True) assert ds.sources[0].filename == "MyFontMaster.ufo" assert ds.instances[0].filename == "../build/instance_ufos/MyFont.ufo" assert "com.schriftgestaltung.customParameters" not in ds.instances[0].lib font_rt = glyphsLib.to_glyphs(ds, minimize_ufo_diffs=True) assert ( font_rt.masters[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] == "MyFontMaster.ufo" ) assert UFO_FILENAME_KEY not in font_rt.masters[0].userData assert ( font_rt.instances[0].customParameters[UFO_FILENAME_CUSTOM_PARAM] == "../build/instance_ufos/MyFont.ufo" ) assert FULL_FILENAME_KEY not in font_rt.instances[0].customParameters ds_rt = glyphsLib.to_designspace(font_rt, minimize_glyphs_diffs=True) assert ds_rt.sources[0].filename == "MyFontMaster.ufo" assert ds_rt.instances[0].filename == "../build/instance_ufos/MyFont.ufo"
import glyphsLib import sys font = glyphsLib.GSFont(sys.argv[-2]) for instance in font.instances: for parameter in instance.customParameters: if parameter.name == "Export COLR Table": parameter.value = 1 font.familyName += " Play" font.save(sys.argv[-1])
import glyphsLib import importlib import argparse import sys from glob import glob parser = argparse.ArgumentParser(description='Filter a font file') parser.add_argument('input', metavar='GLYPHS', help='the Glyphs file') parser.add_argument('filter', metavar='FILTER', help='the filter to use') args = parser.parse_args() base_path = "NaNGlyphFilters" sys.path.append(base_path) glyphsLib.Glyphs.font = glyphsLib.GSFont(args.input) filter_script = args.filter sys.modules['GlyphsApp'] = glyphsLib try: i = importlib.import_module(filter_script) except ModuleNotFoundError as e: modules = [ x[len(base_path) + 1:-3] for x in sorted(glob(base_path + "/*.py")) if "/NaN" not in x ] print("Couldn't find filter '%s'.\nTry one of: %s" % (filter_script, ", ".join(modules))) sys.exit(1) save_file = args.input.replace(".glyphs", "-" + filter_script + ".glyphs") glyphsLib.Glyphs.font.save(save_file)
def build_master_ufos( self, glyphs_path, designspace_path=None, master_dir=None, instance_dir=None, family_name=None, mti_source=None, write_skipexportglyphs=True, generate_GDEF=True, ): """Build UFOs and MutatorMath designspace from Glyphs source.""" import glyphsLib if master_dir is None: master_dir = self._output_dir("ufo") if not os.path.isdir(master_dir): os.mkdir(master_dir) if instance_dir is None: instance_dir = self._output_dir("ufo", is_instance=True) if designspace_path is not None: designspace_dir = os.path.dirname(designspace_path) else: designspace_dir = master_dir # glyphsLib.to_designspace expects instance_dir to be relative to the # designspace's own directory try: instance_dir = os.path.relpath(instance_dir, designspace_dir) except ValueError as e: raise FontmakeError( "Can't make instance_dir path relative to designspace. " "If on Windows, please make sure that --instance-dir, " "--master-dir and --designspace-path are on the same mount drive " "(e.g. C: or D:)", glyphs_path, ) from e try: font = glyphsLib.GSFont(glyphs_path) except Exception as e: raise FontmakeError("Loading Glyphs file failed", glyphs_path) from e designspace = glyphsLib.to_designspace( font, family_name=family_name, instance_dir=instance_dir, write_skipexportglyphs=write_skipexportglyphs, ufo_module=ufoLib2, generate_GDEF=generate_GDEF, store_editor_state=False, minimal=True, ) masters = {} # multiple sources can have the same font/filename (but different layer), # we want to save a font only once for source in designspace.sources: if source.path in masters: assert source.font is masters[source.path] continue ufo_path = os.path.join(master_dir, source.filename) # no need to also set the relative 'filename' attribute as that # will be auto-updated on writing the designspace document source.path = ufo_path masters[ufo_path] = source.font if designspace_path is None: designspace_path = os.path.join(master_dir, designspace.filename) designspace.write(designspace_path) if mti_source: self.add_mti_features_to_master_ufos(mti_source, masters) for ufo_path, ufo in masters.items(): self.save_ufo_as(ufo, ufo_path) return designspace_path