Esempio n. 1
0
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)
Esempio n. 2
0
    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)
Esempio n. 4
0
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
Esempio n. 5
0
    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,
        )
Esempio n. 6
0
    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")