from fontTools.designspaceLib import DesignSpaceDocument from vanilla import * import inspect import defcon f = CurrentFont() thisGlyph = CurrentGlyph() doc = DesignSpaceDocument() doc.read("Crispy[SRIF,wdth,wght].designspace") referenceFileName = doc.sources[ 0].familyName #this assumed a well-made designspace file with correctly named font masters. coordinateslist = [] fontsList = doc.loadSourceFonts(defcon.Font) for i in range(len(fontsList)): nameTag = str(fontsList[i].info.styleName) for glyph in fontsList[i]: compatibilityCounter = 0 if glyph.name == thisGlyph.name: pointCount = 0 for contour in glyph: for segment in contour.segments: for points in segment: pointCount += 1 for refFonts in fontslist: compatible = glyph.isCompatible(refFont[glyph.name]) if compatible: compatibilityCounter += 1 print(compatibilityCounter)
def from_designspace( cls, designspace: designspaceLib.DesignSpaceDocument, round_geometry: bool = True, ): """Instantiates a new data class from a Designspace object.""" if designspace.default is None: raise InstantiatorError( "Can't generate UFOs from this designspace: no default font.") if any( anisotropic(instance.location) for instance in designspace.instances): raise InstantiatorError( "The Designspace contains anisotropic instance locations, which are " "not supported by varLib.") designspace.loadSourceFonts(ufoLib2.Font.open) glyph_names: Set[str] = set() for source in designspace.sources: glyph_names.update(source.font.keys()) # Construct Variators axis_bounds: AxisBounds = {} # Design space! axis_order: List[str] = [] special_axes = {} for axis in designspace.axes: axis_order.append(axis.name) axis_bounds[axis.name] = ( axis.map_forward(axis.minimum), axis.map_forward(axis.default), axis.map_forward(axis.maximum), ) # Some axes relate to existing OpenType fields and get special attention. if axis.tag in {"wght", "wdth", "slnt"}: special_axes[axis.tag] = axis masters_info = collect_info_masters(designspace, axis_bounds) info_mutator = Variator.from_masters(masters_info, axis_order) masters_kerning = collect_kerning_masters(designspace, axis_bounds) kerning_mutator = Variator.from_masters(masters_kerning, axis_order) default_font = designspace.findDefault().font glyph_mutators: Dict[str, Variator] = {} glyph_name_to_unicodes: Dict[str, List[int]] = {} for glyph_name in glyph_names: items = collect_glyph_masters(designspace, glyph_name, axis_bounds) glyph_mutators[glyph_name] = Variator.from_masters( items, axis_order) glyph_name_to_unicodes[glyph_name] = default_font[ glyph_name].unicodes # Construct defaults to copy over copy_feature_text: str = default_font.features.text copy_nonkerning_groups: Mapping[str, List[str]] = { key: glyph_names for key, glyph_names in default_font.groups.items() if not key.startswith(("public.kern1.", "public.kern2.")) } # Kerning groups are taken care of by the kerning Variator. copy_info: ufoLib2.objects.Info = default_font.info copy_lib: Mapping[str, Any] = default_font.lib # The list of glyphs-not-to-export-and-decompose-where-used-as-a-component is # supposed to be taken from the Designspace when a Designspace is used as the # starting point of the compilation process. It should be exported to all # instance libs, where the ufo2ft compilation functions will pick it up. skip_export_glyphs = designspace.lib.get("public.skipExportGlyphs", []) return cls( axis_bounds, copy_feature_text, copy_nonkerning_groups, copy_info, copy_lib, designspace.default.location, designspace.rules, glyph_mutators, glyph_name_to_unicodes, info_mutator, kerning_mutator, round_geometry, skip_export_glyphs, special_axes, )
def test_loadSourceFonts_no_required_path(): designspace = DesignSpaceDocument() designspace.sources.append(SourceDescriptor()) with pytest.raises(DesignSpaceDocumentError, match="no 'path' attribute"): designspace.loadSourceFonts(lambda p: p)
class fontsWithMti(): def __init__(self, mtiFolderPath, destination, UIVersionedFeatures=False, makeUIVersion=False, oneMaster=False): self.mtiFolderPath = mtiFolderPath self.UIVersionedFeaturesExists = UIVersionedFeatures self.makeUIVersion = makeUIVersion self.destination = destination self.oneMaster = oneMaster ############ # PROPERTY # ############ @property def mti_file(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist") and "UI" not in i: path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def simple_mti_file(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist"): path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def mti_file_for_UI_Version(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist") and "UI" in i: path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def masters(self): return self.designSpaceDocument.loadSourceFonts(Font) @property def familyName(self): return self.mtiFolderPath.split("/")[-1] ############### # FUNCTIONS # ############### def load(self): self.ufos = [ os.path.join(self.mtiFolderPath, i) for i in os.listdir(self.mtiFolderPath) if i.endswith(".ufo") ] if self.oneMaster is False: print(">>> Load {}.designspace".format(self.familyName)) else: print(" Load {}.designspace".format(self.familyName)) designSpacePath = os.path.join( self.mtiFolderPath, os.path.basename(self.mtiFolderPath) + ".designspace") self.designSpaceDocument = DesignSpaceDocument() self.designSpaceDocument.read(designSpacePath) @property def basicStylePath(self): if "Italic" not in os.path.basename(self.mtiFolderPath): basicStylePath_ = os.path.join( self.mtiFolderPath, os.path.basename(self.mtiFolderPath).strip() + "-Regular.ufo") if not os.path.exists(basicStylePath_): basicStylePath_ = os.path.join( self.mtiFolderPath, os.path.basename(self.mtiFolderPath).strip() + "-Light.ufo") if not os.path.exists(basicStylePath_): basicStylePath_ = os.path.join( self.mtiFolderPath, os.path.basename(self.mtiFolderPath).strip() + "-Thin.ufo") else: basicStylePath_ = os.path.join( self.mtiFolderPath, os.basename(self.mtiFolderPath).strip() + "-Italic.ufo") print(" >>> " + os.path.basename(self.mtiFolderPath) + "Variable has failed."\ "\n A static ttf version of the 'Regular' weight"\ "\n will be generated instead.") return basicStylePath_ def loadBasicStyle(self): self.ufos = [] self.ufos.append(self.basicStylePath) print(">>> Load {} as Basic Style Path".format( os.path.basename(self.basicStylePath))) # print("Start working on", self.familyName) designSpacePath = os.path.join( self.mtiFolderPath, os.path.basename(self.mtiFolderPath) + ".designspace") self.designSpaceDocument = DesignSpaceDocument() self.designSpaceDocument.read(designSpacePath) def makeStaticFont(self): ufoSource = self.add_mti_features_to_master()[0] staticTTF = compileTTF(ufoSource, removeOverlaps=True, useProductionNames=False, featureCompilerClass=MtiFeatureCompiler, featureWriters=None) staticTTF.save( os.path.join(self.staticPath, os.path.basename(self.ufos[0])[:-4] + ".ttf")) print(" " + os.path.basename(self.ufos[0])[:-4] + " generated\n") def makeStaticFontUI(self): ufoSource = self.add_ui_mti_features_to_master()[0] self.staticTTF_UI = compileTTF(ufoSource, removeOverlaps=True, useProductionNames=False, featureCompilerClass=MtiFeatureCompiler, featureWriters=None) self.staticTTF_UI = self.renamer_(single=True) self.staticTTF_UI.save( os.path.join(self.staticPath, os.path.basename(self.ufos[0])[:-4] + "-UI.ttf")) print(" " + os.path.basename(self.ufos[0])[:-4] + "-UI generated\n") def makeVarFont(self, mti=False): self.designSpaceDocument.loadSourceFonts(Font) print("\tStart to build Variable Tables") self.vfont, _, _ = varLib.build(compileInterpolatableTTFsFromDS( self.designSpaceDocument, featureCompilerClass=MtiFeatureCompiler, featureWriters=None), optimize=False) if self.makeUIVersion is False: path = os.path.join(self.destination, self.familyName + "-VF.ttf") print(path) self.vfont.save(path) print("\t" + self.familyName + " Variable Font generated\n") else: path = os.path.join(self.destination, self.familyName + "UI-VF.ttf") vfontUI = self.renamer_() vfontUI.save(path) print("\t" + self.familyName + "UI Variable Font generated\n") def renamer_(self, single=False): if single is True: renamedFont = self.staticTTF_UI else: renamedFont = self.vfont newName = self.familyName + " UI" # First : GET THE STYLE NAME EITHER IN namerecord *2* # IF the font is a RBIBI font # and in namerecord *17* in other cases for namerecord in renamedFont['name'].names: namerecord.string = namerecord.toUnicode() if namerecord.nameID == 2: WeightName = namerecord.string if namerecord.nameID == 5: version = namerecord.string if namerecord.nameID == 17: WeightName = namerecord.string #Then Change the name everywhere for namerecord in renamedFont['name'].names: namerecord.string = namerecord.toUnicode() # Create the naming of the font Family # (+ StyleName if the style is non RBIBI) if namerecord.nameID == 1: if WeightName in ["Bold", "Regular", "Italic", "Bold Italic"]: namerecord.string = newName else: namerecord.string = newName + " " + WeightName if namerecord.nameID == 3: unicID = namerecord.string.split(";") newUnicID = version + ";" + unicID[1] + ";" + ''.join( newName.split(' ')) + "-" + ''.join(WeightName.split(' ')) namerecord.string = newUnicID if namerecord.nameID == 4: namerecord.string = newName + " " + WeightName if namerecord.nameID == 6: namerecord.string = ''.join( newName.split(' ')) + '-' + ''.join(WeightName.split(' ')) if namerecord.nameID == 16: namerecord.string = newName return renamedFont def add_mti_features_to_master(self): ufoWithMtiData = [] if self.UIVersionedFeaturesExists: mti_source = self.mti_file else: mti_source = self.simple_mti_file mti_paths = readPlist(mti_source) for master in self.masters: key = master.info.familyName.replace( " ", "") + "-" + master.info.styleName.replace(" ", "") for table, path in mti_paths[key].items(): with open(os.path.join(self.mtiFolderPath, path), "rb") as mti_: ufo_path = ( "com.github.googlei18n.ufo2ft.mtiFeatures/%s.mti" % table.strip()) master.data[ufo_path] = mti_.read() # If we have MTI sources, any Adobe feature files derived from # the Glyphs file should be ignored. We clear it here because # it only contains junk information anyway. master.features.text = "" ufoWithMtiData.append(master) # Don't save the ufo, to keep them clean from mti data print(" ufos updated with MTI data") return ufoWithMtiData def add_ui_mti_features_to_master(self): ufoWithMtiData = [] mti_source = self.mti_file_for_UI_Version mti_paths = readPlist(mti_source) for master in self.masters: key = master.info.familyName.replace( " ", "") + "UI-" + master.info.styleName.replace(" ", "") for table, path in mti_paths[key].items(): with open(os.path.join(self.mtiFolderPath, path), "rb") as mti_: ufo_path = ( "com.github.googlei18n.ufo2ft.mtiFeatures/%s.mti" % table.strip()) master.data[ufo_path] = mti_.read() # If we have MTI sources, any Adobe feature files derived from # the Glyphs file should be ignored. We clear it here because # it only contains junk information anyway. master.features.text = "" # Don't save the ufo, to keep them clean from mti data ufoWithMtiData.append(master) print(" ufos updated with UI versioned MTI data") return ufoWithMtiData
def from_designspace( cls, designspace: designspaceLib.DesignSpaceDocument, round_geometry: bool = True, ): """Instantiates a new data class from a Designspace object.""" if designspace.default is None: raise InstantiatorError(_error_msg_no_default(designspace)) if any( anisotropic(instance.location) for instance in designspace.instances): raise InstantiatorError( "The Designspace contains anisotropic instance locations, which are " "not supported by varLib. Look for and remove all 'yvalue=\"...\"' or " "use MutatorMath instead.") designspace.loadSourceFonts(ufoLib2.Font.open) # The default font (default layer) determines which glyphs are interpolated, # because the math behind varLib and MutatorMath uses the default font as the # point of reference for all data. default_font = designspace.default.font glyph_names: Set[str] = set(default_font.keys()) for source in designspace.sources: other_names = set(source.font.keys()) diff_names = other_names - glyph_names if diff_names: logger.warning( "The source %s (%s) contains glyphs that are missing from the " "default source, which will be ignored: %s. If this is unintended, " "check that these glyphs have the exact same name as the " "corresponding glyphs in the default source.", source.name, source.filename, ", ".join(sorted(diff_names)), ) # Construct Variators axis_bounds: AxisBounds = {} # Design space! axis_order: List[str] = [] special_axes = {} for axis in designspace.axes: axis_order.append(axis.name) axis_bounds[axis.name] = ( axis.map_forward(axis.minimum), axis.map_forward(axis.default), axis.map_forward(axis.maximum), ) # Some axes relate to existing OpenType fields and get special attention. if axis.tag in {"wght", "wdth", "slnt"}: special_axes[axis.tag] = axis masters_info = collect_info_masters(designspace, axis_bounds) try: info_mutator = Variator.from_masters(masters_info, axis_order) except varLib.errors.VarLibError as e: raise InstantiatorError( f"Cannot set up fontinfo for interpolation: {e}'") from e masters_kerning = collect_kerning_masters(designspace, axis_bounds) try: kerning_mutator = Variator.from_masters(masters_kerning, axis_order) except varLib.errors.VarLibError as e: raise InstantiatorError( f"Cannot set up kerning for interpolation: {e}'") from e glyph_mutators: Dict[str, Variator] = {} glyph_name_to_unicodes: Dict[str, List[int]] = {} for glyph_name in glyph_names: items = collect_glyph_masters(designspace, glyph_name, axis_bounds) try: glyph_mutators[glyph_name] = Variator.from_masters( items, axis_order) except varLib.errors.VarLibError as e: raise InstantiatorError( f"Cannot set up glyph '{glyph_name}' for interpolation: {e}'" ) from e glyph_name_to_unicodes[glyph_name] = default_font[ glyph_name].unicodes # Construct defaults to copy over copy_feature_text: str = default_font.features.text copy_nonkerning_groups: Mapping[str, List[str]] = { key: glyph_names for key, glyph_names in default_font.groups.items() if not key.startswith(("public.kern1.", "public.kern2.")) } # Kerning groups are taken care of by the kerning Variator. copy_info: ufoLib2.objects.Info = default_font.info copy_lib: Mapping[str, Any] = default_font.lib # The list of glyphs-not-to-export-and-decompose-where-used-as-a-component is # supposed to be taken from the Designspace when a Designspace is used as the # starting point of the compilation process. It should be exported to all # instance libs, where the ufo2ft compilation functions will pick it up. skip_export_glyphs = designspace.lib.get("public.skipExportGlyphs", []) return cls( axis_bounds, copy_feature_text, copy_nonkerning_groups, copy_info, copy_lib, designspace.default.location, designspace.rules, glyph_mutators, glyph_name_to_unicodes, info_mutator, kerning_mutator, round_geometry, skip_export_glyphs, special_axes, )
def from_designspace( cls, designspace: designspaceLib.DesignSpaceDocument, round_geometry: bool = True, ): """Instantiates a new data class from a Designspace object.""" if designspace.default is None: raise ValueError( "Can't generate UFOs from this designspace: no default font." ) designspace.loadSourceFonts(ufoLib2.Font.open) glyph_names: Set[str] = set() for source in designspace.sources: glyph_names.update(source.font.keys()) # Construct Variators axis_bounds: Dict[str, Tuple[float, float, float]] = {} # Design space! axis_order: List[str] = [] weight_width_axes = {} for axis in designspace.axes: axis_order.append(axis.name) axis_bounds[axis.name] = ( axis.map_forward(axis.minimum), axis.map_forward(axis.default), axis.map_forward(axis.maximum), ) if axis.tag in ("wght", "wdth"): weight_width_axes[axis.tag] = axis masters_info = collect_info_masters(designspace, axis_bounds) info_mutator = Variator.from_masters(masters_info, axis_order) masters_kerning = collect_kerning_masters(designspace, axis_bounds) kerning_mutator = Variator.from_masters(masters_kerning, axis_order) default_font = designspace.findDefault().font glyph_mutators: Dict[str, Variator] = {} glyph_name_to_unicodes: Dict[str, List[int]] = {} for glyph_name in glyph_names: items = collect_glyph_masters(designspace, glyph_name, axis_bounds) glyph_mutators[glyph_name] = Variator.from_masters(items, axis_order) glyph_name_to_unicodes[glyph_name] = default_font[glyph_name].unicodes # Construct defaults to copy over copy_feature_text: str = default_font.features.text copy_groups: Mapping[str, List[str]] = default_font.groups copy_info: ufoLib2.objects.Info = default_font.info copy_lib: Mapping[str, Any] = default_font.lib # The list of glyphs not to export and decompose where used as a component is # supposed to be taken from the Designspace when a Designspace is used as the # starting point of the compilation process. It should be exported to all # instance libs, where the ufo2ft compilation functions will pick it up. skip_export_glyphs = designspace.lib.get("public.skipExportGlyphs", []) return cls( axis_bounds, copy_feature_text, copy_groups, copy_info, copy_lib, designspace.rules, glyph_mutators, glyph_name_to_unicodes, info_mutator, kerning_mutator, round_geometry, skip_export_glyphs, weight_width_axes, )
class fontsWithMti(): def __init__(self, directory, output): self.mtiFolderPath = os.path.abspath(os.path.join("../src/", directory)) self.directory = directory self.output = output def load(self): self.ufos = [os.path.join(self.mtiFolderPath, i) for i in os.listdir( self.mtiFolderPath) if i.endswith(".ufo")] print(">>> Load {}.designspace".format(self.familyName)) designSpacePath = os.path.join(self.mtiFolderPath, os.path.basename( self.mtiFolderPath)+".designspace") self.designSpaceDocument = DesignSpaceDocument() self.designSpaceDocument.read(designSpacePath) def makeStaticFont(self, ufoSource, otfFlavor = False): if otfFlavor is True: staticTTF = compileOTF(ufoSource, removeOverlaps=True, useProductionNames = False, featureCompilerClass = MtiFeatureCompiler, featureWriters = None) else: staticTTF = compileTTF(ufoSource, removeOverlaps=True, useProductionNames = False, featureCompilerClass = MtiFeatureCompiler, featureWriters = None) return staticTTF def makeStaticFontUI(self, ufoSource, otfFlavor = False): if otfFlavor is True: self.static_UI = compileOTF(ufoSource, removeOverlaps=True, useProductionNames = False, featureCompilerClass = MtiFeatureCompiler, featureWriters = None) else: self.static_UI = compileTTF(ufoSource, removeOverlaps=True, useProductionNames = False, featureCompilerClass = MtiFeatureCompiler, featureWriters = None) self.static_UI = self.renamer_(single=True) print(" " + os.path.basename(self.ufos[0])[:-4] +"-UI generated\n") return self.static_UI def renamer_(self): renamedFont = self.static_UI # if single is True: # renamedFont = self.staticTTF_UI # else: # renamedFont = self.vfont newName = self.familyName + " UI" # First : GET THE STYLE NAME EITHER IN namerecord *2* # IF the font is a RBIBI font # and in namerecord *17* in other cases for namerecord in renamedFont['name'].names: namerecord.string = namerecord.toUnicode() if namerecord.nameID == 2: WeightName = namerecord.string if namerecord.nameID == 5: version = namerecord.string if namerecord.nameID == 17: WeightName = namerecord.string #Then Change the name everywhere for namerecord in renamedFont['name'].names: namerecord.string = namerecord.toUnicode() # Create the naming of the font Family # (+ StyleName if the style is non RBIBI) if namerecord.nameID == 1: if WeightName in ["Bold", "Regular", "Italic", "Bold Italic"]: namerecord.string = newName else: namerecord.string = newName + " " + WeightName if namerecord.nameID == 3: unicID = namerecord.string.split(";") newUnicID = version + ";"+ unicID[1] +";"+ ''.join( newName.split(' ')) +"-"+ ''.join(WeightName.split(' ')) namerecord.string = newUnicID if namerecord.nameID == 4: namerecord.string = newName + " " + WeightName if namerecord.nameID == 6: namerecord.string = ''.join(newName.split( ' ')) + '-' + ''.join(WeightName.split(' ')) if namerecord.nameID == 16: namerecord.string = newName return renamedFont @property def plistNumber(self): plistNumber = [] for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist"): plistNumber.append(i) return plistNumber @property def mti_file(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist") and "UI" not in i: path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def simple_mti_file(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist"): path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def mti_file_for_UI_Version(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist") and "UI" in i: path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def masters(self): return self.designSpaceDocument.loadSourceFonts(Font) @property def familyName(self): return self.mtiFolderPath.split("/")[-1] def add_mti_features_to_masters(self, UIVersionedFeaturesExists=False): ufosWithMtiData = [] if UIVersionedFeaturesExists: mti_source = self.mti_file else: mti_source = self.simple_mti_file mti_paths = readPlist(mti_source) for master in self.masters: key = master.info.familyName.replace( " ", "")+"-"+master.info.styleName.replace(" ", "") for table, path in mti_paths[key].items(): with open(os.path.join(self.mtiFolderPath, path), "rb") as mti_: ufo_path = ( "com.github.googlei18n.ufo2ft.mtiFeatures/%s.mti" % table.strip() ) master.data[ufo_path] = mti_.read() # If we have MTI sources, any Adobe feature files derived from # the Glyphs file should be ignored. We clear it here because # it only contains junk information anyway. master.features.text = "" ufosWithMtiData.append(master) # Don't save the ufo, to keep them clean from mti data print(" ufos updated with MTI data") return ufosWithMtiData def add_ui_mti_features_to_masters(self): ufosWithMtiData = [] mti_source = self.mti_file_for_UI_Version mti_paths = readPlist(mti_source) for master in self.masters: key = master.info.familyName.replace( " ", "")+"UI-"+master.info.styleName.replace(" ", "") for table, path in mti_paths[key].items(): with open(os.path.join(self.mtiFolderPath, path), "rb") as mti_: ufo_path = ( "com.github.googlei18n.ufo2ft.mtiFeatures/%s.mti" % table.strip() ) master.data[ufo_path] = mti_.read() # If we have MTI sources, any Adobe feature files derived from # the Glyphs file should be ignored. We clear it here because # it only contains junk information anyway. master.features.text = "" # Don't save the ufo, to keep them clean from mti data ufosWithMtiData.append(master) print(" ufos updated with UI versioned MTI data") return ufosWithMtiData def ufoWithMTIfeatures2fonts(self): self.load() if len(self.plistNumber) == 1: ufoWithMtiData = self.add_mti_features_to_masters() for u in ufoWithMtiData: destination = "" folder = os.path.join(self.mtiFolderPath, "fonts") if "otf" in self.output: destination = os.path.join(folder, "OTF") if not os.path.exists(destination): os.makedirs(destination) otf = self.makeStaticFont(u, otfFlavor = True) otf.save(os.path.join(destination, os.path.basename(u._path)[:-4] + ".otf")) if "ttf" in self.output: destination = os.path.join(folder, "TTF") if not os.path.exists(destination): os.makedirs(destination) ttf = self.makeStaticFont(u) ttf.save(os.path.join(destination, os.path.basename(u._path)[:-4] + ".ttf")) else: ufoWithMtiData = self.add_mti_features_to_masters(UIVersionedFeaturesExists=True) for u in ufoWithMtiData: destination = "" folder = os.path.join(self.mtiFolderPath, "fonts") if "ttf" in self.output: destination = os.path.join(folder, "TTF") if not os.path.exists(destination): os.makedirs(destination) ttf = self.makeStaticFont(u) ttf.save(os.path.join(destination, os.path.basename(u._path)[:-4] + ".ttf")) if "otf" in self.output: destination = os.path.join(folder, "OTF") if not os.path.exists(destination): os.makedirs(destination) otf = self.makeStaticFont(u, otfFlavor = True) otf.save(os.path.join(destination, os.path.basename(u._path)[:-4] + ".otf")) ufoWithMtiUIData = self.add_ui_mti_features_to_masters() for u in ufoWithMtiUIData: destination = "" folder = os.path.join(self.mtiFolderPath, self.familyName) if "ttf" in self.output: destination = os.path.join(folder, "TTF") if not os.path.exists(destination): os.makedirs(destination) UIttf = self.makeUIVersion() UIttf.save(os.path.join(destination, os.path.basename(u._path) + "UI.ttf")) if "otf" in self.output: destination = os.path.join(folder, "OTF") if not os.path.exists(destination): os.makedirs(destination) UIttf = self.makeUIVersion(otfFlavor = True) UIttf.save(os.path.join(destination, os.path.basename(u._path) + "UI.otf"))
class variableFontsWithMti(): def __init__(self, mtiFolderPath, UIVersionedFeatures=False, makeUIVersion=False): self.mtiFolderPath = mtiFolderPath self.UIVersionedFeaturesExists = UIVersionedFeatures self.makeUIVersion = makeUIVersion def load(self): self.ufos = [os.path.join(self.mtiFolderPath, i) for i in os.listdir( self.mtiFolderPath) if i.endswith(".ufo")] print(">>Load {}.designspace".format(self.familyName)) # print("Start working on", self.familyName) designSpacePath = os.path.join(self.mtiFolderPath, os.path.basename( self.mtiFolderPath)+".designspace") self.designSpaceDocument = DesignSpaceDocument() self.designSpaceDocument.read(designSpacePath) def makeVarFont(self, mti = False): # self.designSpaceDocument.loadSourceFonts(Font) print("\tStart to build Variable Tables") self.vfont, _, _ = varLib.build(compileInterpolatableTTFsFromDS( self.designSpaceDocument, featureCompilerClass = MtiFeatureCompiler, featureWriters = None ), optimize=False) if self.makeUIVersion is False: destination = os.path.join(self.mtiFolderPath, "fonts/VAR") if not os.path.exists(destination): os.makedirs(destination) path = os.path.join(destination, self.familyName+"-VF.ttf") self.vfont.save(path) print("\t"+self.familyName+" Variable Font generated\n") else: destination = os.path.join( self.mtiFolderPath, "fonts/"+self.familyName+"UI/VAR") if not os.path.exists(destination): os.makedirs(destination) path = os.path.join(destination, self.familyName+"UI-VF.ttf") vfontUI = self.renamer_() vfontUI.save(path) print("\t"+self.familyName+"UI Variable Font generated\n") def renamer_(self): renamedFont = self.vfont newName = self.familyName + " UI" # First : GET THE STYLE NAME EITHER IN namerecord *2* # IF the font is a RBIBI font # and in namerecord *17* in other cases for namerecord in renamedFont['name'].names: namerecord.string = namerecord.toUnicode() if namerecord.nameID == 2: WeightName = namerecord.string if namerecord.nameID == 5: version = namerecord.string if namerecord.nameID == 17: WeightName = namerecord.string #Then Change the name everywhere for namerecord in renamedFont['name'].names: namerecord.string = namerecord.toUnicode() # Create the naming of the font Family # (+ StyleName if the style is non RBIBI) if namerecord.nameID == 1: if WeightName in ["Bold", "Regular", "Italic", "Bold Italic"]: namerecord.string = newName else: namerecord.string = newName + " " + WeightName if namerecord.nameID == 3: unicID = namerecord.string.split(";") newUnicID = version + ";"+ unicID[1] +";"+ ''.join( newName.split(' ')) +"-"+ ''.join(WeightName.split(' ')) namerecord.string = newUnicID if namerecord.nameID == 4: namerecord.string = newName + " " + WeightName if namerecord.nameID == 6: namerecord.string = ''.join(newName.split( ' ')) + '-' + ''.join(WeightName.split(' ')) if namerecord.nameID == 16: namerecord.string = newName return renamedFont @property def mti_file(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist") and "UI" not in i: path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") # return self.mti_source @property def simple_mti_file(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist"): path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def mti_file_for_UI_Version(self): for i in os.listdir(self.mtiFolderPath): if i.endswith(".plist") and "UI" in i: path = os.path.join(self.mtiFolderPath, i) return open(path, "rb") @property def masters(self): return self.designSpaceDocument.loadSourceFonts(Font) @property def familyName(self): return self.mtiFolderPath.split("/")[-1] def add_mti_features_to_master_ufos(self): if self.UIVersionedFeaturesExists: mti_source = self.mti_file else: mti_source = self.simple_mti_file mti_paths = readPlist(mti_source) for master in self.masters: key = master.info.familyName.replace( " ", "")+"-"+master.info.styleName.replace(" ", "") for table, path in mti_paths[key].items(): with open(os.path.join(self.mtiFolderPath, path), "rb") as mti_: ufo_path = ( "com.github.googlei18n.ufo2ft.mtiFeatures/%s.mti" % table.strip() ) master.data[ufo_path] = mti_.read() # If we have MTI sources, any Adobe feature files derived from # the Glyphs file should be ignored. We clear it here because # it only contains junk information anyway. master.features.text = "" # Don't save the ufo, to keep them clean from mti data print("\tufos updated with MTI data") def add_ui_mti_features_to_master_ufos(self): mti_source = self.mti_file_for_UI_Version mti_paths = readPlist(mti_source) for master in self.masters: key = master.info.familyName.replace( " ", "")+"UI-"+master.info.styleName.replace(" ", "") for table, path in mti_paths[key].items(): with open(os.path.join(self.mtiFolderPath, path), "rb") as mti_: ufo_path = ( "com.github.googlei18n.ufo2ft.mtiFeatures/%s.mti" % table.strip() ) master.data[ufo_path] = mti_.read() # If we have MTI sources, any Adobe feature files derived from # the Glyphs file should be ignored. We clear it here because # it only contains junk information anyway. master.features.text = "" # Don't save the ufo, to keep them clean from mti data print("\tufos updated with UI versioned MTI data")