def __init__(self, filename=None): """Load a variable font from the given filename.""" self.masters = {} self.designspace = None self.master_order = [] if filename.endswith(".glyphs"): f = GSFont(filename) self.designspace = UFOBuilder(f).designspace self.masters = { master.name: _load_gsfont(master) for master in f.masters } self.master_order = [master.name for master in f.masters] elif filename.endswith(".designspace"): self.designspace = DesignSpaceDocument.fromfile(filename) self.designspace.loadSourceFonts(load_ufo) self.masters = { source.styleName: source.font for source in self.designspace.sources } self.master_order = [ source.styleName for source in self.designspace.sources ] if self.designspace: self._make_model()
def test_instance_filtering_by_family_name(self): # See https://github.com/googlefonts/fontmake/issues/257 path = os.path.join(os.path.dirname(__file__), "..", "data", "MontserratStrippedDown.glyphs") font = GSFont(path) # By default (no special parameter), all instances are exported designspace_all = to_designspace(font) assert len(designspace_all.instances) == 18 # If we specify that we want the same familyName as the masters, # we only get instances that have that same family name, and the # masters are copied as-is. (basically a subset of the previous doc) designspace_no_alternates = to_designspace(font, family_name="Montserrat") assert len(designspace_no_alternates.instances) == 9 # If we specify the alternate family name, we only get the instances # that have that family name, and the masters are renamed to have the # given family name. designspace_alternates = to_designspace( font, family_name="Montserrat Alternates") assert designspace_alternates.sources[ 0].familyName == "Montserrat Alternates" assert (designspace_alternates.sources[0].font.info.familyName == "Montserrat Alternates") assert len(designspace_alternates.instances) == 9
def test_master_with_light_weight_but_thin_name(self): font = generate_minimal_font() master = font.masters[0] name = "Thin" # In Glyphs.app, show "Thin" in the sidebar weight = "Light" # In Glyphs.app, have the light "n" icon width = None # No data => should be equivalent to Regular custom_name = "Thin" master.set_all_name_components(name, weight, width, custom_name) assert master.name == "Thin" assert master.weight == "Light" ufo, = to_ufos(font) font_rt = to_glyphs([ufo]) master_rt = font_rt.masters[0] assert master_rt.name == "Thin" assert master_rt.weight == "Light" tmpdir = tempfile.mkdtemp() try: filename = os.path.join(tmpdir, "test.glyphs") font_rt.save(filename) font_rt_written = GSFont(filename) master_rt_written = font_rt_written.masters[0] assert master_rt_written.name == "Thin" assert master_rt_written.weight == "Light" finally: shutil.rmtree(tmpdir)
def setUp(self): self.font = GSFont() self.font.masters.append(GSFontMaster()) self.font.glyphs.append(GSGlyph("a")) self.font.glyphs.append(GSGlyph("c")) self.font.glyphs.append(GSGlyph("f")) self.ufo = Font() self.ufo.newGlyph("a") self.ufo.newGlyph("c") self.ufo.newGlyph("f")
def setUp(self): self.font = GSFont() self.font.masters.append(GSFontMaster()) self.font.glyphs.append(GSGlyph('a')) self.font.glyphs.append(GSGlyph('c')) self.font.glyphs.append(GSGlyph('f')) self.ufo = Font() self.ufo.newGlyph('a') self.ufo.newGlyph('c') self.ufo.newGlyph('f')
def test_custom_parameter_vfo_old_name(): """Tests get_regular_master when 'Variation Font Origin' custom parameter name is used with master set to 'Regular Text'. This custom parameter name is not used in current releases of the Glyphs editor / glyphs source file specification.""" source_path = os.path.join("tests", "data", "CustomParameterVFO.glyphs") font = GSFont(source_path) # mock up source for this test with a source file from another test del font.customParameters["Variable Font Origin"] font.customParameters["Variation Font Origin"] = "Regular Text" assert font.customParameters["Variable Font Origin"] is None # start tests test_name = font.customParameters["Variation Font Origin"] matched = False for master in font.masters: if master.name == test_name: matched = True assert matched is True default_master = get_regular_master(font) assert default_master.name == "Regular Text"
def test_custom_parameter_vfo_not_set(): """Tests default behavior of get_regular_master when Variable Font Origin custom parameter is not set""" source_path = os.path.join("tests", "data", "CustomParameterVFO.glyphs") font = GSFont(source_path) # mock up source for this test with a source file from another test del font.customParameters["Variable Font Origin"] del font.customParameters["Variation Font Origin"] assert font.customParameters["Variable Font Origin"] is None assert font.customParameters["Variation Font Origin"] is None default_master = get_regular_master(font) assert default_master.name == "Regular Text"
def test_custom_parameter_vfo_current(): """Tests get_regular_master when 'Variable Font Origin' custom parameter name is used with master set to 'Regular Text'. This is the current default custom parameter name in the Glyphs editor / glyphs source file specification.""" source_path = os.path.join("tests", "data", "CustomParameterVFO.glyphs") font = GSFont(source_path) assert font.customParameters["Variation Font Origin"] is None test_id = font.customParameters["Variable Font Origin"] assert test_id == "ACC63F3E-1323-486A-94AF-B18797A154CE" matched = False for master in font.masters: if master.id == test_id: assert master.name == "Regular Text" matched = True assert matched is True default_master = get_regular_master(font) assert default_master.name == "Regular Text"
def test_single_master_default_weight_400(ufo_module): font = GSFont() master = GSFontMaster() master.weightValue = 400 font.masters.append(master) doc = to_designspace(font, ufo_module=ufo_module) assert len(doc.axes) == 1 assert doc.axes[0].name == "Weight" assert doc.axes[0].minimum == 400 assert doc.axes[0].default == 400 assert doc.axes[0].maximum == 400 assert len(doc.sources) == 1 assert doc.sources[0].location["Weight"] == 400 font2 = to_glyphs(doc) assert len(font2.masters) == 1 assert font2.masters[0].weightValue == 400
def replace_prefixes(repl_map, features_text, glyph_names=None): """Replace all '# Prefix: NAME' sections in features. Args: repl_map: Dict[str, str]: dictionary keyed by prefix name containing feature code snippets to be replaced. features_text: str: feature text to be parsed. glyph_names: Optional[Sequence[str]]: list of valid glyph names, used by feaLib Parser to distinguish glyph name tokens containing '-' from glyph ranges such as 'a-z'. Returns: str: new feature text with replaced prefix paragraphs. """ from glyphsLib.classes import GSFont temp_font = GSFont() _to_glyphs_features(temp_font, features_text, glyph_names=glyph_names) for prefix in temp_font.featurePrefixes: if prefix.name in repl_map: prefix.code = repl_map[prefix.name] return _to_ufo_features(temp_font)
def build_masters( filename, master_dir, designspace_instance_dir=None, designspace_path=None, family_name=None, propagate_anchors=True, minimize_glyphs_diffs=False, normalize_ufos=False, create_background_layers=False, generate_GDEF=True, store_editor_state=True, write_skipexportglyphs=False, ): """Write and return UFOs from the masters and the designspace defined in a .glyphs file. Args: master_dir: Directory where masters are written. designspace_instance_dir: If provided, a designspace document will be written alongside the master UFOs though no instances will be built. family_name: If provided, the master UFOs will be given this name and only instances with this name will be included in the designspace. Returns: A named tuple of master UFOs (`ufos`) and the path to the designspace file (`designspace_path`). """ font = GSFont(filename) if not os.path.isdir(master_dir): os.mkdir(master_dir) if designspace_instance_dir is None: instance_dir = None else: instance_dir = os.path.relpath(designspace_instance_dir, master_dir) designspace = to_designspace( font, family_name=family_name, propagate_anchors=propagate_anchors, instance_dir=instance_dir, minimize_glyphs_diffs=minimize_glyphs_diffs, generate_GDEF=generate_GDEF, store_editor_state=store_editor_state, write_skipexportglyphs=write_skipexportglyphs, ) # Only write full masters to disk. This assumes that layer sources are always part # of another full master source, which must always be the case in a .glyphs file. ufos = {} for source in designspace.sources: if source.filename in ufos: assert source.font is ufos[source.filename] continue if create_background_layers: ufo_create_background_layer_for_all_glyphs(source.font) ufo_path = os.path.join(master_dir, source.filename) clean_ufo(ufo_path) source.font.save(ufo_path) if normalize_ufos: import ufonormalizer ufonormalizer.normalizeUFO(ufo_path, writeModTimes=False) ufos[source.filename] = source.font if not designspace_path: designspace_path = os.path.join(master_dir, designspace.filename) designspace.write(designspace_path) return Masters(ufos, designspace_path)
def setUp(self): self.ufo = Font() self.font = GSFont() self.master = GSFontMaster() self.font.masters.insert(0, self.master) self.builder = UFOBuilder(self.font)
def makeFont(masters, instances, familyName): font = GSFont() font.familyName = familyName font.masters = masters font.instances = instances return font
def test_wheres_ma_axis2(datadir): font2 = GSFont(datadir.join("AxesWdthWght.glyphs")) doc2 = to_designspace(font2) assert [a.tag for a in doc2.axes] == ["wdth", "wght"]
def test_wheres_ma_axis(datadir): font1 = GSFont(datadir.join("AxesWdth.glyphs")) doc1 = to_designspace(font1) assert [a.tag for a in doc1.axes] == ["wdth"]
def build_masters( filename, master_dir, designspace_instance_dir=None, designspace_path=None, family_name=None, propagate_anchors=True, minimize_glyphs_diffs=False, normalize_ufos=False, create_background_layers=False, generate_GDEF=True, ): """Write and return UFOs from the masters and the designspace defined in a .glyphs file. Args: master_dir: Directory where masters are written. designspace_instance_dir: If provided, a designspace document will be written alongside the master UFOs though no instances will be built. family_name: If provided, the master UFOs will be given this name and only instances with this name will be included in the designspace. Returns: A named tuple of master UFOs (`ufos`) and the path to the designspace file (`designspace_path`). """ font = GSFont(filename) if not os.path.isdir(master_dir): os.mkdir(master_dir) if designspace_instance_dir is None: instance_dir = None else: instance_dir = os.path.relpath(designspace_instance_dir, master_dir) designspace = to_designspace( font, family_name=family_name, propagate_anchors=propagate_anchors, instance_dir=instance_dir, minimize_glyphs_diffs=minimize_glyphs_diffs, generate_GDEF=generate_GDEF, ) ufos = [] for source in designspace.sources: ufos.append(source.font) if create_background_layers: ufo_create_background_layer_for_all_glyphs(source.font) ufo_path = os.path.join(master_dir, source.filename) clean_ufo(ufo_path) source.font.save(ufo_path) if normalize_ufos: import ufonormalizer ufonormalizer.normalizeUFO(ufo_path, writeModTimes=False) if not designspace_path: designspace_path = os.path.join(master_dir, designspace.filename) designspace.write(designspace_path) return Masters(ufos, designspace_path)