Ejemplo n.º 1
0
    def _calculateGlyph(self, targetGlyphObject, instanceLocationObject,
                        glyphMasters):
        """
        Build a Mutator object for this glyph.

        *   name:   glyphName
        *   location:   Location object
        *   glyphMasters:    dict with font objects.
        """
        sources = None
        items = []

        for item in glyphMasters:
            locationObject = item['location']
            fontObject = item['font']
            glyphName = item['glyphName']
            if not glyphName in fontObject:
                continue
            glyphObject = MathGlyph(fontObject[glyphName])
            items.append((locationObject, glyphObject))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocationObject)
        if self.roundGeometry:
            try:
                instanceObject = instanceObject.round()
            except AttributeError:
                self.logger.info("MathGlyph object missing round() method.")
        try:
            instanceObject.extractGlyph(targetGlyphObject, onlyGeometry=True)
        except TypeError:
            self.logger.info(
                "MathGlyph object extractGlyph() does not support onlyGeometry attribute."
            )
            instanceObject.extractGlyph(targetGlyphObject)
Ejemplo n.º 2
0
    def addInfo(self, instanceLocation=None, sources=None, copySourceName=None):
        """ Add font info data. """
        if instanceLocation is None:
            instanceLocation = self.locationObject
        infoObject = self.font.info
        infoMasters = []
        if sources is None:
            sources = self.sources
        items = []
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['info']:
                # info in this master was muted, so do not add.
                continue
            items.append((sourceLocation, MathInfo(source.info)))
        try:
            bias, m = buildMutator(items, warpDict=self.warpDict)
        except:
            self.logger.exception("Error processing font info. %s", items)
            return
        instanceObject = m.makeInstance(instanceLocation)
        if self.roundGeometry:
            try:
                instanceObject = instanceObject.round()
            except AttributeError:
                warnings.warn("MathInfo object missing round() method.")
        instanceObject.extractInfo(self.font.info)

        # handle the copyable info fields
        if copySourceName is not None:
            if not copySourceName in sources:
                if self.verbose and self.logger:
                    self.logger.info("Copy info source %s not found, skipping.", copySourceName)
                    return
            copySourceObject, loc = sources[copySourceName]
            self._copyFontInfo(self.font.info, copySourceObject.info)
Ejemplo n.º 3
0
    def addKerning(self, instanceLocation=None, sources=None):
        """
        Calculate the kerning data for this location and add it to this instance.
        
        *   instanceLocation:   Location object
        """
        items = []
        kerningObject = self.font.kerning
        kerningMasters = []
        if instanceLocation is None:
            instanceLocation = self.locationObject

        if sources is None:
            # kerning has no special requests, add the default sources
            sources = self.sources
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['kerning']:
                # kerning in this master was muted, so do not add.
                if self.verbose and self.logger:
                    self.logger.info("Muting kerning data for %s", instanceLocation)
                continue
            items.append((sourceLocation, MathKerning(source.kerning)))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocation)
        if self.roundGeometry:
            instanceObject.round()
        # done with the kerning


        instanceObject.extractKerning(self.font)
Ejemplo n.º 4
0
    def _calculateGlyph(self, targetGlyphObject, instanceLocationObject,
                        glyphMasters):
        """
        Build a Mutator object for this glyph.

        *   name:   glyphName
        *   location:   Location object
        *   glyphMasters:    dict with font objects.
        """
        sources = None
        items = []

        for item in glyphMasters:
            locationObject = item['location']
            fontObject = item['font']
            glyphName = item['glyphName']
            if not glyphName in fontObject:
                continue
            glyphObject = MathGlyph(fontObject[glyphName])
            items.append((locationObject, glyphObject))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocationObject)
        if self.roundGeometry:
            instanceObject = instanceObject.round()
        instanceObject.extractGlyph(targetGlyphObject, onlyGeometry=True)
Ejemplo n.º 5
0
    def _calculateGlyph(self, targetGlyphObject, instanceLocationObject, glyphMasters):
        """
        Build a Mutator object for this glyph.

        *   name:   glyphName
        *   location:   Location object
        *   glyphMasters:    dict with font objects.
        """
        sources = None
        items = []

        for item in glyphMasters:
            locationObject = item['location']
            fontObject = item['font']
            glyphName = item['glyphName']
            if not glyphName in fontObject:
                continue
            glyphObject = MathGlyph(fontObject[glyphName])
            items.append((locationObject, glyphObject))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocationObject)
        if self.roundGeometry:
            instanceObject = instanceObject.round()
        # instanceObject.extractGlyph(targetGlyphObject, onlyGeometry=True)
        instanceObject.extractGlyph(targetGlyphObject)
Ejemplo n.º 6
0
    def addKerning(self, instanceLocation=None, sources=None):
        """
        Calculate the kerning data for this location and add it to this instance.
        
        *   instanceLocation:   Location object
        *   source: dict of {sourcename: (source, sourceLocation)}
        """
        items = []
        kerningObject = self.font.kerning
        kerningMasters = []
        if instanceLocation is None:
            instanceLocation = self.locationObject

        if sources is None:
            # kerning has no special requests, add the default sources
            sources = self.sources
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['kerning']:
                # kerning in this master was muted, so do not add.
                if self.verbose and self.logger:
                    self.logger.info("Muting kerning data for %s",
                                     instanceLocation)
                continue
            items.append((sourceLocation, MathKerning(source.kerning)))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocation)
        if self.roundGeometry:
            instanceObject.round()
        instanceObject.extractKerning(self.font)
Ejemplo n.º 7
0
    def addInfo(self,
                instanceLocation=None,
                sources=None,
                copySourceName=None):
        """ Add font info data. """
        if instanceLocation is None:
            instanceLocation = self.locationObject
        infoObject = self.font.info
        infoMasters = []
        if sources is None:
            sources = self.sources
        items = []
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['info']:
                # info in this master was muted, so do not add.
                continue
            items.append((sourceLocation, MathInfo(source.info)))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocation)
        if self.roundGeometry:
            instanceObject = instanceObject.round()
        instanceObject.extractInfo(self.font.info)

        # handle the copyable info fields
        if copySourceName is not None:
            if not copySourceName in sources:
                if self.verbose and self.logger:
                    self.logger.info(
                        "Copy info source %s not found, skipping.",
                        copySourceName)
                    return
            copySourceObject, loc = sources[copySourceName]
            self._copyFontInfo(self.font.info, copySourceObject.info)
Ejemplo n.º 8
0
    def _calculateGlyph(self, targetGlyphObject, instanceLocationObject, glyphMasters):
        """
        Build a Mutator object for this glyph.

        *   name:   glyphName
        *   location:   Location object
        *   glyphMasters:    dict with font objects.
        """
        sources = None
        items = []

        for item in glyphMasters:
            locationObject = item['location']
            fontObject = item['font']
            glyphName = item['glyphName']
            if not glyphName in fontObject:
                continue
            glyphObject = MathGlyph(fontObject[glyphName])
            items.append((locationObject, glyphObject))
        bias, m = buildMutator(items, warpDict=self.warpDict)
        instanceObject = m.makeInstance(instanceLocationObject)
        if self.roundGeometry:
            try:
                instanceObject = instanceObject.round()
            except AttributeError:
                self.logger.info("MathGlyph object missing round() method.")
        try:
            instanceObject.extractGlyph(targetGlyphObject, onlyGeometry=True)
        except TypeError:
            self.logger.info("MathGlyph object extractGlyph() does not support onlyGeometry attribute.")
            instanceObject.extractGlyph(targetGlyphObject)
Ejemplo n.º 9
0
 def getGlyphMutator(self, glyphName, decomposeComponents=False):
     """ Return a glyph mutator.defaultLoc
         decomposeComponents = True causes the source glyphs to be decomposed first
         before building the mutator. That gives you instances that do not depend
         on a complete font. If you're calculating previews for instance.
     """
     if glyphName in self._glyphMutators:
         return self._glyphMutators[glyphName]
     items = []
     for sourceDescriptor in self.sources:
         loc = Location(sourceDescriptor.location)
         f = self.fonts[sourceDescriptor.name]
         if glyphName in sourceDescriptor.mutedGlyphNames:
             continue
         if not glyphName in f:
             # log this>
             continue
         sourceGlyphObject = f[glyphName]
         if decomposeComponents:
             temp = self.glyphClass()
             p = temp.getPointPen()
             dpp = DecomposePointPen(f, p)
             sourceGlyphObject.drawPoints(dpp)
             temp.width = sourceGlyphObject.width
             temp.name = sourceGlyphObject.name
             #temp.lib = sourceGlyphObject.lib
             processThis = temp
         else:
             processThis = sourceGlyphObject
         items.append((loc, self.mathGlyphClass(processThis)))
     bias, self._glyphMutators[glyphName] = buildMutator(
         items, axes=self._preppedAxes, bias=self.defaultLoc)
     return self._glyphMutators[glyphName]
Ejemplo n.º 10
0
    def addInfo(self, instanceLocation=None, sources=None, copySourceName=None):
        """ Add font info data. """
        if instanceLocation is None:
            instanceLocation = self.locationObject
        infoObject = self.font.info
        infoMasters = []
        if sources is None:
            sources = self.sources
        items = []
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['info']:
                # info in this master was muted, so do not add.
                if self.verbose and self.logger:
                    self.logger.info("Muting info data for %s", sourceName)
                continue
            items.append((sourceLocation, MathInfo(source.info)))
        bias, m = buildMutator(items)
        instanceObject = m.makeInstance(instanceLocation)
        if self.roundGeometry:
            instanceObject = instanceObject.round()
        instanceObject.extractInfo(self.font.info)

        # handle the copyable info fields
        if copySourceName is not None:
            if not copySourceName in sources:
                if self.verbose and self.logger:
                    self.logger.info("Copy info source %s not found, skipping.", copySourceName)
                    return
            copySourceObject, loc = sources[copySourceName]
            self._copyFontInfo(self.font.info, copySourceObject.info)
Ejemplo n.º 11
0
 def makeMasterKerningCompatible(self):
     """
     Optimize kerning data.
     All masters must have the same kering pairs.
     Build repair mutators for missing kering pairs
     and generate the kerning value within the design space.
     """
     self.generateReport.writeTitle("Making master kerning compatible", "'")
     self.generateReport.indent()
     # collect all kerning pairs
     allPairs = list()
     # collect all groups and all pairs
     allGroups = dict()
     masters = self.fonts.values()
     for master in masters:
         allPairs.extend(master.kerning.keys())
         allGroups.update(master.groups)
     allPairs = set(allPairs)
     # build a kerning mutator
     kerningItems = []
     for sourceDescriptor in self.sources:
         # ignore muted kerning sources
         if sourceDescriptor.muteKerning:
             continue
         master = self.fonts[sourceDescriptor.name]
         location = self.locations[sourceDescriptor.name]
         kerningItems.append((location, self.mathKerningClass(master.kerning, master.groups)))
     _, kerningMutator = buildMutator(kerningItems)
     kerningCache = dict()
     # loop over all pairs
     for pair in allPairs:
         # loop over all masters
         for sourceDescriptor in self.sources:
             font = self.fonts[sourceDescriptor.name]
             missingPairs = []
             missingGroups = []
             if pair not in font.kerning:
                 missingPairs.append(pair)
                 kerningInstance = kerningCache.get(sourceDescriptor.name)
                 if kerningInstance is None:
                     location = self.locations[sourceDescriptor.name]
                     kerningInstance = kerningMutator.makeInstance(Location(location))
                 master.kerning[pair] = kerningInstance[pair]
                 # check pairs on group kerning
                 side1, side2 = pair
                 if side1.startswith(side1Prefix) and side1 not in master.groups:
                     # add a group
                     master.groups[side1] = allGroups[side1]
                     missingGroups.append(side1)
                 if side2.startswith(side2Prefix) and side2 not in master.groups:
                     # add a group
                     master.groups[side2] = allGroups[side2]
                     missingGroups.append(side2)
             if missingPairs:
                 self.generateReport.write("Adding missing kerning pairs in %s %s: %s" % (font.info.familyName, font.info.styleName, ", ".join(["(%s, %s)" % (s1, s2) for s1, s2 in missingPairs])))
             if missingGroups:
                 self.generateReport.write("Adding missing kerning groups in %s %s: %s" % (font.info.familyName, font.info.styleName, ", ".join(missingGroups)))
     self.generateReport.dedent()
     self.generateReport.newLine()
Ejemplo n.º 12
0
 def getInstance(self, location, masters):
     try:
         b, m = buildMutator(masters)
         if m is not None:
             instance = m.makeInstance(location)
             return instance
     except:
         return
Ejemplo n.º 13
0
 def _getInstance(self, location, masters):
     try:
         b, m = buildMutator(masters)
         if m is not None:
             instance = m.makeInstance(location)
             return instance
     except Exception as e:
         self.mutatorErrors.append({'error': e.message})
         return None
Ejemplo n.º 14
0
 def _getInstance(self, location, masters):
     try:
         b, m = buildMutator(masters)
         if m is not None:
             instance = m.makeInstance(location)
             return instance
     except Exception as e:
         self.mutatorErrors.append({'error':e.message})
         return None
Ejemplo n.º 15
0
 def interpolate_font_info(self, instanceLocation, masters, targetFont):
     infoMasters = [
         (infoLocation, MathInfo(masterFont.info))
         for infoLocation, masterFont in masters
     ]
     try:
         bias, iM = buildMutator(infoMasters)
         instanceInfo = iM.makeInstance(instanceLocation)
         instanceInfo.extractInfo(targetFont.info)
     except:
         print(u'Couldn’t interpolate font info')
Ejemplo n.º 16
0
 def interpolate_kerning(self, instanceLocation, masters, targetFont):
     kerningMasters = [
         (kerningLocation, MathKerning(masterFont.kerning))
         for kerningLocation, masterFont in masters
     ]
     try:
         bias, iK = buildMutator(kerningMasters)
         instanceKerning = iK.makeInstance(instanceLocation)
         instanceKerning.extractKerning(targetFont)
     except:
         print(u'Couldn’t interpolate font kerning')
Ejemplo n.º 17
0
 def getInfoMutator(self):
     """ Returns a info mutator """
     if self._infoMutator:
         return self._infoMutator
     infoItems = []
     for sourceDescriptor in self.sources:
         loc = Location(sourceDescriptor.location)
         sourceFont = self.fonts[sourceDescriptor.name]
         infoItems.append((loc, self.mathInfoClass(sourceFont.info)))
     bias, self._infoMutator = buildMutator(infoItems,
                                            axes=self._preppedAxes,
                                            bias=self.defaultLoc)
     return self._infoMutator
Ejemplo n.º 18
0
 def getVariationModel(self, items, axes, bias=None):
     # Return either a mutatorMath or a varlib.model object for calculating.
     try:
         if self.useVarlib:
             # use the varlib variation model
             return dict(), VariationModelMutator(items, self.axes)
         else:
             # use mutatormath model
             axesForMutator = self.getMutatorAxes()
             return buildMutator(items, axes=axesForMutator, bias=bias)
     except:
         error = traceback.format_exc()
         self.problems.append("UFOProcessor.getVariationModel error: %s" %
                              error)
         return None
Ejemplo n.º 19
0
 def getKerningMutator(self):
     """ Return a kerning mutator """
     if self._kerningMutator:
         return self._kerningMutator
     kerningItems = []
     for sourceDescriptor in self.sources:
         loc = Location(sourceDescriptor.location)
         sourceFont = self.fonts[sourceDescriptor.name]
         kerningItems.append((loc,
                              self.mathKerningClass(sourceFont.kerning,
                                                    sourceFont.groups)))
     bias, self._kerningMutator = buildMutator(kerningItems,
                                               axes=self._preppedAxes,
                                               bias=self.defaultLoc)
     return self._kerningMutator
Ejemplo n.º 20
0
 def getGlyphMutator(self, glyphName):
     """ Return a glyph mutator """
     if glyphName in self._glyphMutators:
         return self._glyphMutators[glyphName]
     items = []
     for sourceDescriptor in self.sources:
         loc = Location(sourceDescriptor.location)
         f = self.fonts[sourceDescriptor.name]
         if glyphName in sourceDescriptor.mutedGlyphNames:
             continue
         if not glyphName in f:
             # log this>
             continue
         items.append((loc, self.mathGlyphClass(f[glyphName])))
     bias, self._glyphMutators[glyphName] = buildMutator(
         items, axes=self._preppedAxes, bias=self.defaultLoc)
     return self._glyphMutators[glyphName]
    def interpolateGlyphSet(self, instanceLocation, glyphSet, masters, targetFont, suffix=None):

        incompatibleGlyphs = []

        for glyphName in glyphSet:
            masterGlyphs = [(masterLocation, MathGlyph(masterFont[glyphName])) for masterLocation, masterFont in masters]
            try:
                bias, gM = buildMutator(masterGlyphs)
                newGlyph = RGlyph()
                instanceGlyph = gM.makeInstance(instanceLocation)
                if suffix is not None:
                    glyphName += suffix
                targetFont.insertGlyph(instanceGlyph.extractGlyph(newGlyph), glyphName)
            except:
                incompatibleGlyphs.append(glyphName)
                continue

        return incompatibleGlyphs
Ejemplo n.º 22
0
 def getKerningMutator(self):
     """ Return a kerning mutator """
     if self._kerningMutator:
         return self._kerningMutator
     kerningItems = []
     for sourceDescriptor in self.sources:
         if not sourceDescriptor.muteKerning:
             loc = Location(sourceDescriptor.location)
             sourceFont = self.fonts[sourceDescriptor.name]
             # this makes assumptions about the groups of all sources being the same.
             kerningItems.append(
                 (loc,
                  self.mathKerningClass(sourceFont.kerning,
                                        sourceFont.groups)))
     bias, self._kerningMutator = buildMutator(kerningItems,
                                               axes=self._preppedAxes,
                                               bias=self.defaultLoc)
     return self._kerningMutator
Ejemplo n.º 23
0
 def interpolate_glyph_set(self, instanceLocation, glyphSet, masters, targetFont):
     for glyphName in glyphSet:
         masterGlyphs = [
             (masterLocation, MathGlyph(masterFont[glyphName]))
             for masterLocation, masterFont in masters
         ]
         try:
             bias, gM = buildMutator(masterGlyphs)
             newGlyph = RGlyph()
             instanceGlyph = gM.makeInstance(instanceLocation)
             targetFont.insertGlyph(instanceGlyph.extractGlyph(newGlyph), glyphName)
             targetFont[glyphName].unicode = masterFont[glyphName].unicode
             targetFont[glyphName].round()
             self.fix_component_order(masterFont[glyphName], targetFont[glyphName])
         except:
             #print(u'Incompatible glyph: %s' % glyphName)
             targetFont.newGlyph(glyphName)
             continue
     targetFont.glyphOrder = glyphSet
Ejemplo n.º 24
0
    def addInfo(self,
                instanceLocation=None,
                sources=None,
                copySourceName=None):
        """ Add font info data. """
        if instanceLocation is None:
            instanceLocation = self.locationObject
        infoObject = self.font.info
        infoMasters = []
        if sources is None:
            sources = self.sources
        items = []
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['info']:
                # info in this master was muted, so do not add.
                continue
            items.append((sourceLocation, MathInfo(source.info)))
        try:
            bias, m = buildMutator(items, axes=self.axes)
        except:
            if self.logger:
                self.logger.exception("Error processing font info. %s", items)
            return
        instanceObject = m.makeInstance(instanceLocation,
                                        bend=self.bendLocations)
        if self.roundGeometry:
            try:
                instanceObject = instanceObject.round()
            except AttributeError:
                warnings.warn("MathInfo object missing round() method.")
        instanceObject.extractInfo(self.font.info)

        # handle the copyable info fields
        if copySourceName is not None:
            if not copySourceName in sources:
                if self.verbose and self.logger:
                    self.logger.info(
                        "Copy info source %s not found, skipping.",
                        copySourceName)
                    return
            copySourceObject, loc = sources[copySourceName]
            self._copyFontInfo(self.font.info, copySourceObject.info)
    def makeGlyphInstances(self, axesGrid):

        instanceTime = []

        mutatorMasters = self.mutatorMasters
        masterSpots = [spot for spot, masterFont in self.masters]
        nCellsOnHorizontalAxis, nCellsOnVerticalAxis = axesGrid
        matrix = self.w.matrix
        instanceGlyphs = None

        # start = time()
        # count = 0

        if mutatorMasters:

            try:
                bias, mutator = buildMutator(mutatorMasters)
            except:
                mutator = None

            for i in range(nCellsOnHorizontalAxis):
                ch = getKeyForValue(i)

                for j in range(nCellsOnVerticalAxis):

                    if (ch, j) not in masterSpots:

                        if mutator is not None:
                            instanceLocation = Location(horizontal=i, vertical=j)
                            instanceStart = time()
                            instanceGlyph = RGlyph()
                            iGlyph = mutator.makeInstance(instanceLocation)
                            instanceGlyph = iGlyph.extractGlyph(RGlyph())
                            instanceStop = time()
                            instanceTime.append((instanceStop-instanceStart)*1000)
                        else:
                            instanceGlyph = self.errorGlyph

                        cell = getattr(matrix, '%s%s'%(ch, j))
                        cell.glyphView.setGlyph(instanceGlyph)
Ejemplo n.º 26
0
    def _calculateGlyph(self, targetGlyphObject, instanceLocationObject,
                        glyphMasters):
        """
        Build a Mutator object for this glyph.

        *   name:   glyphName
        *   location:   Location object
        *   glyphMasters:    dict with font objects.
        """
        sources = None
        items = []

        for item in glyphMasters:
            locationObject = item['location']
            fontObject = item['font']
            glyphName = item['glyphName']
            if not glyphName in fontObject:
                continue
            glyphObject = MathGlyph(fontObject[glyphName])
            items.append((locationObject, glyphObject))
        bias, m = buildMutator(items, axes=self.axes)
        instanceObject = m.makeInstance(instanceLocationObject,
                                        bend=self.bendLocations)
        if self.roundGeometry:
            try:
                instanceObject = instanceObject.round()
            except AttributeError:
                if self.verbose and self.logger:
                    self.logger.info(
                        "MathGlyph object missing round() method.")

        try:
            instanceObject.extractGlyph(targetGlyphObject, onlyGeometry=True)
        except TypeError:
            # this causes ruled glyphs to end up in the wrong glyphname
            # but defcon2 objects don't support it
            pPen = targetGlyphObject.getPointPen()
            targetGlyphObject.clear()
            instanceObject.drawPoints(pPen)
            targetGlyphObject.width = instanceObject.width
    def placeGlyphMasters(self, glyphName, axesGrid):
        availableFonts = AllFonts()
        masters = []
        nCellsOnHorizontalAxis, nCellsOnVerticalAxis = axesGrid
        matrix = self.w.matrix
        masterGlyph = None

        for matrixLocation in self.masters:
            spot, masterFont = matrixLocation
            ch, j = spot
            i = getValueForKey(ch)

            if (masterFont in availableFonts) and (glyphName is not None) and (glyphName in masterFont):
                if i <= nCellsOnHorizontalAxis and j <= nCellsOnVerticalAxis:
                    l = Location(horizontal=i, vertical=j)
                    masterGlyph = makePreviewGlyph(masterFont[glyphName])
                    if masterGlyph is not None:
                        masters.append((l, masterGlyph))
            elif (masterFont not in availableFonts):
                self.masters.remove(matrixLocation)

            if i < nCellsOnHorizontalAxis and j < nCellsOnVerticalAxis:
                cell = getattr(matrix, '%s%s'%(ch, j))
                cell.glyphView.setGlyph(masterGlyph)
                if masterGlyph is not None:
                    cell.glyphView.getNSView().setContourColor_(MasterColor)
                    cell.masterMask.show(True)
                    fontName = ' '.join([masterFont.info.familyName, masterFont.info.styleName])
                    cell.name.set(fontName)
                elif masterGlyph is None:
                    cell.glyphView.getNSView().setContourColor_(BlackColor)
                    cell.masterMask.show(False)
                    cell.name.set('')

        if len(masters) > 1:
            try:
                bias, mutator = buildMutator(masters)
                self.mutator = mutator
            except:
                self.mutator = None
    def placeGlyphMasters(self, glyphName, axesGrid):
        availableFonts = AllFonts()
        masters = []
        nCellsOnHorizontalAxis, nCellsOnVerticalAxis = axesGrid
        matrix = self.w.matrix
        masterGlyph = None

        for matrixLocation in self.masters:
            spot, masterFont = matrixLocation
            ch, j = spot
            i = getValueForKey(ch)

            if (masterFont in availableFonts) and (glyphName is not None) and (glyphName in masterFont):
                if i <= nCellsOnHorizontalAxis and j <= nCellsOnVerticalAxis:
                    l = Location(horizontal=i, vertical=j)
                    masterGlyph = makePreviewGlyph(masterFont[glyphName])
                    if masterGlyph is not None:
                        masters.append((l, MathGlyph(masterGlyph)))
            elif (masterFont not in availableFonts):
                self.masters.remove(matrixLocation)

            if i < nCellsOnHorizontalAxis and j < nCellsOnVerticalAxis:
                cell = getattr(matrix, '%s%s'%(ch, j))
                cell.glyphView.setGlyph(masterGlyph)
                if masterGlyph is not None:
                    cell.glyphView.getNSView().setContourColor_(MasterColor)
                    cell.masterMask.show(True)
                    fontName = ' '.join([masterFont.info.familyName, masterFont.info.styleName])
                    cell.name.set(fontName)
                elif masterGlyph is None:
                    cell.glyphView.getNSView().setContourColor_(BlackColor)
                    cell.masterMask.show(False)
                    cell.name.set('')

        if len(masters) > 1:
            try:
                bias, mutator = buildMutator(masters)
                self.mutator = mutator
            except:
                self.mutator = None
Ejemplo n.º 29
0
    def _calculateGlyph(self, targetGlyphObject, instanceLocationObject, glyphMasters):
        """
        Build a Mutator object for this glyph.

        *   name:   glyphName
        *   location:   Location object
        *   glyphMasters:    dict with font objects.
        """
        sources = None
        items = []

        for item in glyphMasters:
            locationObject = item['location']
            fontObject = item['font']
            glyphName = item['glyphName']
            if not glyphName in fontObject:
                continue
            glyphObject = MathGlyph(fontObject[glyphName])
            items.append((locationObject, glyphObject))
        bias, m = buildMutator(items, axes=self.axes)
        instanceObject = m.makeInstance(instanceLocationObject)
        if self.roundGeometry:
            try:
                instanceObject = instanceObject.round()
            except AttributeError:
                if self.verbose and self.logger:
                    self.logger.info("MathGlyph object missing round() method.")


        try:
            instanceObject.extractGlyph(targetGlyphObject, onlyGeometry=True)
        except TypeError:
            # this causes ruled glyphs to end up in the wrong glyphname
            # but defcon2 objects don't support it
            pPen = targetGlyphObject.getPointPen()
            targetGlyphObject.clear()
            instanceObject.drawPoints(pPen)
            targetGlyphObject.width = instanceObject.width
Ejemplo n.º 30
0
    def addKerning(self, instanceLocation=None, sources=None):
        """
        Calculate the kerning data for this location and add it to this instance.
        
        *   instanceLocation:   Location object
        *   source: dict of {sourcename: (source, sourceLocation)}
        """
        items = []
        kerningObject = self.font.kerning
        kerningMasters = []
        if instanceLocation is None:
            instanceLocation = self.locationObject

        if sources is None:
            # kerning has no special requests, add the default sources
            sources = self.sources
        for sourceName, (source, sourceLocation) in sources.items():
            if sourceName in self.muted['kerning']:
                # kerning in this master was muted, so do not add.
                if self.verbose and self.logger:
                    self.logger.info("\tMuting kerning data for %s", instanceLocation)
                continue
            if len(source.kerning.keys())>0:
                items.append((sourceLocation, MathKerning(source.kerning)))
        # items.sort()
        if items:
            m = None
            try:
                bias, m = buildMutator(items, axes=self.axes)
            except:
                if self.logger:
                    self.logger.exception("\tError processing kerning data. %s", items)
                return
            instanceObject = m.makeInstance(instanceLocation)
            if self.roundGeometry:
                instanceObject.round()
            instanceObject.extractKerning(self.font)
    def generateInstanceFont(self, spot, generationInfos):

        if generationInfos['sourceFont']:

            start = time()
            report = []

            doGlyphs = bool(generationInfos['interpolateGlyphs'])
            doKerning = bool(generationInfos['interpolateKerning'])
            doFontInfos = bool(generationInfos['interpolateFontInfos'])
            addGroups = bool(generationInfos['addGroups'])
            doReport = bool(generationInfos['report'])
            UI = bool(generationInfos['openFonts'])

            try:
                masters = self.masters
                baseFont = generationInfos['sourceFont'][0]
                newFont = None
                folderPath = None
                s = re.search('(.*)/(.*)(.ufo)', baseFont.path)
                if s is not None:
                    folderPath = s.group(1)

                masterFonts = [font for _, font in masters]

                i, j = spot
                ch = getKeyForValue(i)
                instanceLocation = Location(horizontal=i, vertical=j)
                instanceName = '%s%s'%(ch.upper(), j+1)
                masterLocations = [(matrixMaster.getLocation(), matrixMaster.getFont()) for matrixMaster in masters]

                progress = ProgressWindow('Generating instance %s%s'%(ch.upper(), j+1), parentWindow=self.w)
                report.append(u'\n*** Generating instance %s ***\n'%(instanceName))

                # Build fontx
                if (doGlyphs == True) or (doKerning == True) or (doFontInfos == True) or (addGroups == True):

                    if hasattr(RFont, 'showUI') or (not hasattr(RFont, 'showUI') and (folderPath is not None)):
                        newFont = RFont(showUI=False)
                    elif not hasattr(RFont, 'showUI') and (folderPath is None):
                        newFont = RFont()
                    newFont.info.familyName = baseFont.info.familyName
                    newFont.info.styleName = '%s%s'%(ch.upper(), j+1)
                    try:
                        newFont.glyphOrder = baseFont.glyphOrder
                    except:
                        try:
                            newFont.glyphOrder = baseFont.lib['public.glyphOrder']
                        except:
                            try:
                                newFont.lib['public.glyphOrder'] = baseFont.lib['public.glyphOrder']
                            except:
                                try:
                                    newFont.lib['public.glyphOrder'] = baseFont.glyphOrder
                                except:
                                    pass
                    if folderPath is not None:
                        instancesFolder = u'%s%s'%(folderPath, '/matrix-instances')
                        if not os.path.isdir(instancesFolder):
                            os.makedirs(instancesFolder)
                        folderPath = instancesFolder
                        path = '%s/%s-%s%s'%(folderPath, newFont.info.familyName, newFont.info.styleName, '.ufo')
                    interpolatedGlyphs = []
                    interpolatedInfo = None
                    interpolatedKerning = None
                    interpolationReports = []

                    report.append(u'+ Created new font')

                # interpolate font infos

                if doFontInfos == True:
                    infoMasters = [(infoLocation, MathInfo(masterFont.info)) for infoLocation, masterFont in masterLocations]
                    try:
                        bias, iM = buildMutator(infoMasters)
                        instanceInfo = iM.makeInstance(instanceLocation)
                        instanceInfo.extractInfo(newFont.info)
                        report.append(u'+ Successfully interpolated font info')
                    except:
                        report.append(u'+ Couldn’t interpolate font info')

                # interpolate kerning

                if doKerning == True:
                    kerningMasters = [(kerningLocation, MathKerning(masterFont.kerning)) for kerningLocation, masterFont in masterLocations]
                    try:
                        bias, kM = buildMutator(kerningMasters)
                        instanceKerning = kM.makeInstance(instanceLocation)
                        instanceKerning.extractKerning(newFont)
                        report.append(u'+ Successfully interpolated kerning')
                        if addGroups == True:
                            for key, value in baseFont.groups.items():
                                newFont.groups[key] = value
                            report.append(u'+ Successfully transferred groups')
                    except:
                        report.append(u'+ Couldn’t interpolate kerning')

                # filter compatible glyphs

                glyphList, strayGlyphs = self.compareGlyphSets(masterFonts)

                if doGlyphs == True:

                    incompatibleGlyphs = self.interpolateGlyphSet(instanceLocation, glyphList, masterLocations, newFont)

                    report.append(u'+ Successfully interpolated %s glyphs'%(len(newFont)))
                    report.append(u'+ Couldn’t interpolate %s glyphs'%(len(incompatibleGlyphs)))

                if (newFont is not None) and hasattr(RFont, 'showUI') and (folderPath is None) and UI:
                    newFont.autoUnicodes()
                    newFont.round()
                    newFont.showUI()
                elif (newFont is not None) and (folderPath is not None):
                    newFont.autoUnicodes()
                    newFont.round()
                    newFont.save(path)
                    report.append(u'\n—> Saved font to UFO at %s\n'%(path))
                    if UI:
                        f = RFont(path)
                elif (newFont is not None):
                    print u'Couldn’t save font to UFO.'
            except:
                print u'Couldn’t finish generating, something happened…'
                return
            finally:
                progress.close()

                if doReport:
                    print '\n'.join(report)
    def generateInstanceFont(self, spot, generationInfos):

        # self.w.spotSheet.close()
        # delattr(self.w, 'spotSheet')

        if generationInfos['sourceFont']:
            baseFont = generationInfos['sourceFont'][0]
            doKerning = generationInfos['interpolateKerning']
            doFontInfos = generationInfos['interpolateFontInfos']
            doReport = generationInfos['printReport']

            progress = ProgressWindow('Generating instance', parentWindow=self.w)

            fonts = [font for _, font in self.masters]

            i, j = spot
            ch = getKeyForValue(i)
            instanceLocation = Location(horizontal=i, vertical=j)
            masterLocations = [(Location(horizontal=getValueForKey(_ch), vertical=_j), masterFont) for (_ch, _j), masterFont in self.masters]

            # Build font
            newFont = RFont(showUI=False)
            newFont.info.familyName = baseFont.info.familyName
            newFont.info.styleName = '%s%s'%(ch.upper(), j+1)
            interpolatedGlyphs = []
            interpolatedInfo = None
            interpolatedKerning = None
            interpolationReports = []

            # interpolate font infos

            if doFontInfos:
                infoMasters = [(location, MathInfo(font.info)) for location, font in masterLocations]
                try:
                    bias, iM = buildMutator(infoMasters)
                    instanceInfo = iM.makeInstance(instanceLocation)
                    instanceInfo.extractInfo(newFont.info)
                except:
                    pass

            # interpolate kerning

            if doKerning:
                kerningMasters = [(location, MathKerning(font.kerning)) for location, font in masterLocations]
                try:
                    bias, kM = buildMutator(kerningMasters)
                    instanceKerning = kM.makeInstance(instanceLocation)
                    instanceKerning.extractKerning(newFont)
                    for key, value in baseFont.groups.items():
                        newFont.groups[key] = value
                except:
                    pass

            # filter compatible glyphs

            fontKeys = [set(font.keys()) for font in fonts]
            glyphList = set()
            for i, item in enumerate(fontKeys):
                if i == 0:
                    glyphList = item
                elif i > 0:
                    glyphList = glyphList & item

            compatibleBaseGlyphList = []
            compatibleCompositeGlyphList = []

            for glyphName in glyphList:
                glyphs = [font[glyphName] for font in fonts]
                compatible = True
                for glyph in glyphs[1:]:
                    comp, report = glyphs[0].isCompatible(glyph)
                    if comp == False:
                        name = '%s <X> %s'%(fontName(glyphs[0].getParent()), fontName(glyph.getParent()))
                        reportLine = (name, report)
                        if reportLine not in interpolationReports:
                            interpolationReports.append(reportLine)
                        compatible = False
                if compatible:
                    compatibleBaseGlyphList.append(glyphName)

            # initiate glyph interpolation

            for glyphName in compatibleBaseGlyphList:
                glyphMasters = [(location, MathGlyph(font[glyphName])) for location, font in masterLocations]
                try:
                    bias, gM = buildMutator(glyphMasters)
                    newGlyph = RGlyph()
                    instanceGlyph = gM.makeInstance(instanceLocation)
                    interpolatedGlyphs.append((glyphName, instanceGlyph.extractGlyph(newGlyph)))
                except:
                    continue

            for name, iGlyph in interpolatedGlyphs:
                newFont.insertGlyph(iGlyph, name)

            progress.close()
            digest = []

            if doReport:
                for fontNames, report in interpolationReports:
                    digest.append(fontNames)
                    digest += [u'– %s'%(reportLine) for reportLine in report]
                    digest.append('\n')
                print '\n'.join(digest)

            newFont.showUI()
Ejemplo n.º 33
0
 def makeMasterKerningCompatible(self):
     """
     Optimize kerning data.
     All masters must have the same kering pairs.
     Build repair mutators for missing kering pairs
     and generate the kerning value within the design space.
     """
     self.generateReport.writeTitle("Making master kerning compatible", "'")
     self.generateReport.indent()
     # collect all kerning pairs
     allPairs = list()
     # collect all groups and all pairs
     allGroups = dict()
     masters = self.fonts.values()
     for master in masters:
         allPairs.extend(master.kerning.keys())
         allGroups.update(master.groups)
     allPairs = set(allPairs)
     # build a kerning mutator
     kerningItems = []
     for sourceDescriptor in self.sources:
         # ignore muted kerning sources
         if sourceDescriptor.muteKerning:
             continue
         master = self.fonts[sourceDescriptor.name]
         location = self.locations[sourceDescriptor.name]
         kerningItems.append(
             (location, self.mathKerningClass(master.kerning,
                                              master.groups)))
     _, kerningMutator = buildMutator(kerningItems)
     kerningCache = dict()
     # loop over all pairs
     for pair in allPairs:
         # loop over all masters
         for sourceDescriptor in self.sources:
             font = self.fonts[sourceDescriptor.name]
             missingPairs = []
             missingGroups = []
             if pair not in font.kerning:
                 missingPairs.append(pair)
                 kerningInstance = kerningCache.get(sourceDescriptor.name)
                 if kerningInstance is None:
                     location = self.locations[sourceDescriptor.name]
                     kerningInstance = kerningMutator.makeInstance(
                         Location(location))
                     kerningCache[sourceDescriptor.name] = kerningInstance
                 font.kerning[pair] = kerningInstance[pair]
                 # check pairs on group kerning
                 side1, side2 = pair
                 if side1.startswith(
                         side1Prefix) and side1 not in font.groups:
                     # add a group
                     font.groups[side1] = allGroups[side1]
                     missingGroups.append(side1)
                 if side2.startswith(
                         side2Prefix) and side2 not in font.groups:
                     # add a group
                     font.groups[side2] = allGroups[side2]
                     missingGroups.append(side2)
             if missingPairs:
                 self.generateReport.write(
                     "Adding missing kerning pairs in %s %s: %s" %
                     (font.info.familyName, font.info.styleName, ", ".join(
                         ["(%s, %s)" % (s1, s2)
                          for s1, s2 in missingPairs])))
             if missingGroups:
                 self.generateReport.write(
                     "Adding missing kerning groups in %s %s: %s" %
                     (font.info.familyName, font.info.styleName,
                      ", ".join(missingGroups)))
     self.generateReport.dedent()
     self.generateReport.newLine()
Ejemplo n.º 34
0
    def makeMasterGlyphsCompatible(self):
        """
        Update all masters with missing glyphs.
        All Masters must have the same glyphs.
        """
        self.generateReport.writeTitle("Making master glyphs compatible", "'")
        self.generateReport.indent()
        # collect all possible glyph names
        glyphNames = []
        for master in self.fonts.values():
            glyphNames.extend(master.keys())
        glyphNames = set(glyphNames)
        # get the default master
        defaultMaster = self.fonts[self.default.name]
        # loop over all glyphName
        for glyphName in glyphNames:
            # first check if the default master has this glyph
            if glyphName not in defaultMaster:
                # the default does not have the glyph
                # build a repair mutator to generate a glyph
                glyphItems = []
                for sourceDescriptor in self.sources:
                    master = self.fonts[sourceDescriptor.name]
                    if glyphName in sourceDescriptor.mutedGlyphNames:
                        continue
                    if glyphName in master:
                        sourceGlyph = self.mathGlyphClass(master[glyphName])
                        sourceGlyphLocation = self.locations[
                            sourceDescriptor.name]
                        glyphItems.append((sourceGlyphLocation, sourceGlyph))
                _, mutator = buildMutator(glyphItems)
                # use the repair mutator to generate an instance at the default location
                result = mutator.makeInstance(Location(self.defaultLoc))
                # round if necessary
                if self.roundGeometry:
                    result.round()
                self.generateReport.write(
                    "Adding missing glyph '%s' in the default master '%s %s'" %
                    (glyphName, defaultMaster.info.familyName,
                     defaultMaster.info.styleName))
                # add the glyph to the default master
                defaultMaster.newGlyph(glyphName)
                glyph = defaultMaster[glyphName]
                result.extractGlyph(glyph)

            glyphs = []
            # fill all masters with missing glyphs
            # and collect all glyphs from all masters
            # to send them to optimize contour data
            for sourceDescriptor in self.sources:
                master = self.fonts[sourceDescriptor.name]
                if glyphName in master:
                    # found do nothing
                    glyphs.append(master[glyphName])
                else:
                    # get the mutator
                    mutator = self.getGlyphMutator(glyphName)
                    # get the location
                    location = self.locations[sourceDescriptor.name]
                    # generate an instance
                    result = mutator.makeInstance(Location(location))
                    # round if necessary
                    if self.roundGeometry:
                        result.round()

                    self.generateReport.write(
                        "Adding missing glyph '%s' in master '%s %s'" %
                        (glyphName, master.info.familyName,
                         master.info.styleName))
                    # add the glyph to the master
                    master.newGlyph(glyphName)
                    glyph = master[glyphName]
                    result.extractGlyph(glyph)
                    glyphs.append(glyph)
            # optimize glyph contour data from all masters
            self.makeGlyphOutlinesCompatible(glyphs)
        self.generateReport.dedent()
        self.generateReport.newLine()
Ejemplo n.º 35
0
    def makeMasterGlyphsCompatible(self):
        """
        Update all masters with missing glyphs.
        All Masters must have the same glyphs.
        """
        self.generateReport.writeTitle("Making master glyphs compatible", "'")
        self.generateReport.indent()
        # collect all possible glyph names
        glyphNames = []
        for master in self.masters.values():
            glyphNames.extend(master.keys())
        glyphNames = set(glyphNames)
        # get the default master
        defaultMaster = self.masters[self.default.name]
        # loop over all glyphName
        for glyphName in glyphNames:
            # first check if the default master has this glyph
            if glyphName not in defaultMaster:
                # the default does not have the glyph
                # build a repair mutator to generate a glyph.
                glyphItems = []
                for sourceDescriptor in self.sources:
                    master = self.masters[sourceDescriptor.name]
                    if glyphName in sourceDescriptor.mutedGlyphNames:
                        continue
                    if glyphName in master:
                        sourceGlyph = self.mathGlyphClass(master[glyphName])
                        sourceGlyphLocation = self.locations[
                            sourceDescriptor.name]
                        glyphItems.append((sourceGlyphLocation, sourceGlyph))
                # Note: this needs to be a mutatormath mutator, not a varlib.model.
                # A varlib model can't work without in the missing default.
                # Filling in the default is a bit of a hack: it will make the font work,
                # but it is a bit of a guess.
                _, mutator = buildMutator(glyphItems)
                # use the repair mutator to generate an instance at the default location
                result = mutator.makeInstance(
                    Location(self.newDefaultLocation()))
                # round if necessary
                if self.roundGeometry:
                    result.round()
                self.generateReport.write(
                    "Adding missing glyph '%s' in the default master '%s %s (%s)'"
                    % (glyphName, defaultMaster.font.info.familyName,
                       defaultMaster.font.info.styleName, defaultMaster.name))
                # add the glyph to the default master
                defaultMaster.newGlyph(glyphName)
                glyph = defaultMaster[glyphName]
                result.extractGlyph(glyph, onlyGeometry=True)

            glyphs = []
            # fill all masters with missing glyphs
            # and collect all glyphs from all masters
            # to send them to optimize contour data
            for sourceDescriptor in self.sources:
                master = self.masters[sourceDescriptor.name]
                hasGlyph = False
                if glyphName in master:
                    # Glyph is present in the master.
                    # This checks for points, components and so on.
                    if not checkGlyphIsEmpty(master[glyphName],
                                             allowWhiteSpace=True):
                        glyphs.append(master[glyphName])
                        hasGlyph = True
                if not hasGlyph:
                    # Get the varlibmodel to generate a filler glyph.
                    # These is probably a support with just a few glyphs.
                    try:
                        self.useVarlib = True
                        mutator = self.getGlyphMutator(glyphName)
                        if mutator is None:
                            self.useVarlib = False
                            mutator = self.getGlyphMutator(glyphName)
                            self.useVarlib = True
                        # generate an instance
                        result = mutator.makeInstance(
                            Location(sourceDescriptor.location))
                    except Exception as e:
                        print("Problem in %s" % glyphName)
                        print("\n".join(self.problems))
                        raise e
                    # round if necessary
                    if self.roundGeometry:
                        result.round()
                    self.generateReport.write(
                        "Adding missing glyph '%s' in master '%s %s (%s)'" %
                        (glyphName, master.font.info.familyName,
                         master.font.info.styleName, master.name))
                    # add the glyph to the master
                    master.newGlyph(glyphName)
                    result.extractGlyph(master[glyphName], onlyGeometry=True)
                    glyphs.append(master[glyphName])
            # optimize glyph contour data from all masters
            self.makeGlyphOutlinesCompatible(glyphs)
        if getDefault("Batch.Debug", False):
            for k, m in self.masters.items():
                tempPath = os.path.join(
                    os.path.dirname(m.font.path),
                    "%s_%s" % (k, os.path.basename(m.font.path)))
                m.font.save(tempPath)

        if self.compileGlyphOrder is None:
            self.compileGlyphOrder = defaultMaster.font.lib.get(
                "public.glyphOrder", [])
            for glyphName in sorted(glyphNames):
                if glyphName not in self.compileGlyphOrder:
                    self.compileGlyphOrder.append(glyphName)

        self.generateReport.dedent()
        self.generateReport.newLine()
Ejemplo n.º 36
0
        new.pt = self.pt[0] * factor[0], self.pt[1] * factor[1]
        new.size *= factor[0]
        new.alpha = self.alpha * factor[0]
        return new

    __rmul__ = __mul__


items = [
    (Location(pop=0, snap=0), MathDot((0, 0), name="neutral")),
    (Location(pop=0, snap=1), MathDot((0, 100), name="on-axis-one-A")),
    (Location(pop=1, snap=0), MathDot((100, 0), name="on-axis-two-A")),
    (Location(pop=1, snap=1), MathDot((100, 100), name="off-axis-A")),
]

bias, mb = buildMutator(items)

grid = {}
for loc, (master, xx) in mb.items():
    for axis, value in loc:
        if not axis in grid:
            grid[axis] = []
        if not (axis, value) in grid[axis]:
            grid[axis].append((axis, value))
nodes = list(itertools.product(*grid.values()))
nodes.sort()

corners = {}
for n in nodes:
    l = Location()
    l.fromTuple(n)
Ejemplo n.º 37
0
items = [(dict(w=0), m), (dict(w=1), m)]
a = AxisDescriptor()
a.name = "w"
a.minimum = 0
a.default = 0
a.maximum = 1

# process with varlib.model
mut1 = VariationModelMutator(items, [a])
m1i = mut1.makeInstance(dict(w=1))
print("\n#varlib")
print(m1i.items())

# process with mutator
bias, mut2 = buildMutator(items)
m2i = mut2.makeInstance(dict(w=1))
print("\n#mutator")
print(m2i.items())

# process with the same mathematical operations on a naked mathKerning object
v = None
deltas = [m, m]
scalars = [1.0, 1.0]
assert len(deltas) == len(scalars)
for i, (delta, scalar) in enumerate(zip(deltas, scalars)):
    if not scalar: continue
    contribution = delta * scalar
    if v is None:
        v = contribution
    else:
Ejemplo n.º 38
0
    def makeMasterGlyphsCompatible(self):
        """
        Update all masters with missing glyphs.
        All Masters must have the same glyphs.
        """
        self.generateReport.writeTitle("Making master glyphs compatible", "'")
        self.generateReport.indent()
        # collect all possible glyph names
        glyphNames = []
        for master in self.masters.values():
            glyphNames.extend(master.keys())
        glyphNames = set(glyphNames)
        # get the default master
        defaultMaster = self.masters[self.default.name]
        # loop over all glyphName
        for glyphName in glyphNames:
            # first check if the default master has this glyph
            if glyphName not in defaultMaster:
                # the default does not have the glyph
                # build a repair mutator to generate a glyph.
                glyphItems = []
                for sourceDescriptor in self.sources:
                    master = self.masters[sourceDescriptor.name]
                    if glyphName in sourceDescriptor.mutedGlyphNames:
                        continue
                    if glyphName in master:
                        sourceGlyph = self.mathGlyphClass(master[glyphName])
                        sourceGlyphLocation = self.locations[sourceDescriptor.name]
                        glyphItems.append((sourceGlyphLocation, sourceGlyph))
                # Note: this needs to be a mutatormath mutator, not a varlib.model.
                # A varlib model can't work without in the missing default.
                # Filling in the default is a bit of a hack: it will make the font work,
                # but it is a bit of a guess.
                _, mutator = buildMutator(glyphItems)
                # use the repair mutator to generate an instance at the default location
                result = mutator.makeInstance(Location(self.defaultLoc))
                # round if necessary
                if self.roundGeometry:
                    result.round()
                self.generateReport.write("Adding missing glyph '%s' in the default master '%s %s (%s)'" % (glyphName, defaultMaster.font.info.familyName, defaultMaster.font.info.styleName, defaultMaster.name))
                # add the glyph to the default master
                defaultMaster.newGlyph(glyphName)
                glyph = defaultMaster[glyphName]
                result.extractGlyph(glyph, onlyGeometry=True)

            glyphs = []
            # fill all masters with missing glyphs
            # and collect all glyphs from all masters
            # to send them to optimize contour data
            for sourceDescriptor in self.sources:
                master = self.masters[sourceDescriptor.name]
                hasGlyph = False
                if glyphName in master:
                    # Glyph is present in the master.
                    # This checks for points, components and so on.
                    if not checkGlyphIsEmpty(master[glyphName], allowWhiteSpace=True):
                        glyphs.append(master[glyphName])
                        hasGlyph = True
                if not hasGlyph:
                    # Get the varlibmodel to generate a filler glyph.
                    # These is probably a support with just a few glyphs.
                    try:
                        self.useVarlib = True
                        mutator = self.getGlyphMutator(glyphName)
                        if mutator is None:
                            self.useVarlib = False
                            mutator = self.getGlyphMutator(glyphName)
                            self.useVarlib = True
                        # generate an instance
                        result = mutator.makeInstance(Location(sourceDescriptor.location))
                    except Exception as e:
                        print("Problem in %s" % glyphName)
                        print("\n".join(self.problems))
                        raise e
                    # round if necessary
                    if self.roundGeometry:
                        result.round()
                    self.generateReport.write("Adding missing glyph '%s' in master '%s %s (%s)'" % (glyphName, master.font.info.familyName, master.font.info.styleName, master.name))
                    # add the glyph to the master
                    master.newGlyph(glyphName)
                    result.extractGlyph(master[glyphName], onlyGeometry=True)
                    glyphs.append(master[glyphName])
            # optimize glyph contour data from all masters
            self.makeGlyphOutlinesCompatible(glyphs)
        if getDefault("Batch.Debug", False):
            for k, m in self.masters.items():
                tempPath = m.font.path.replace(".ufo", "_%s.ufo" % k)
                m.font.save(tempPath)

        if self.compileGlyphOrder is None:
            self.compileGlyphOrder = defaultMaster.font.lib.get("public.glyphOrder", [])
            for glyphName in sorted(glyphNames):
                if glyphName not in self.compileGlyphOrder:
                    self.compileGlyphOrder.append(glyphName)

        self.generateReport.dedent()
        self.generateReport.newLine()
Ejemplo n.º 39
0
    def makeInstance(self, instanceDescriptor, doRules=False, glyphNames=None):
        """ Generate a font object for this instance """
        font = self._instantiateFont(None)
        self._preppedAxes = self._prepAxesForBender()
        # make fonty things here
        loc = Location(instanceDescriptor.location)
        # groups,
        if hasattr(self.fonts[self.default.name],
                   "kerningGroupConversionRenameMaps"):
            renameMap = self.fonts[
                self.default.name].kerningGroupConversionRenameMaps
            self.problems.append("renameMap %s" % renameMap)
        else:
            renameMap = {}
        font.kerningGroupConversionRenameMaps = renameMap
        # make the kerning
        if instanceDescriptor.kerning:
            try:
                self.getKerningMutator().makeInstance(loc).extractKerning(font)
            except:
                self.problems.append("Could not make kerning for %s" % loc)
        # make the info
        if instanceDescriptor.info:
            try:
                self.getInfoMutator().makeInstance(loc).extractInfo(font.info)
                info = self._infoMutator.makeInstance(loc)
                info.extractInfo(font.info)
                font.info.familyName = instanceDescriptor.familyName
                font.info.styleName = instanceDescriptor.styleName
                font.info.postScriptFontName = instanceDescriptor.postScriptFontName
                font.info.styleMapFamilyName = instanceDescriptor.styleMapFamilyName
                font.info.styleMapStyleName = instanceDescriptor.styleMapStyleName
                # localised names need to go to the right openTypeNameRecords
                # records = []
                # nameID = 1
                # platformID =
                # for languageCode, name in instanceDescriptor.localisedStyleMapFamilyName.items():
                #    # Name ID 1 (font family name) is found at the generic styleMapFamily attribute.
                #    records.append((nameID, ))

            except:
                self.problems.append("Could not make fontinfo for %s" % loc)
        # copied info
        for sourceDescriptor in self.sources:
            if sourceDescriptor.copyInfo:
                # this is the source
                self._copyFontInfo(self.fonts[sourceDescriptor.name].info,
                                   font.info)
            if sourceDescriptor.copyLib:
                # excplicitly copy the font.lib items
                for key, value in self.fonts[
                        sourceDescriptor.name].lib.items():
                    font.lib[key] = value
            if sourceDescriptor.copyFeatures:
                featuresText = self.fonts[sourceDescriptor.name].features.text
                if isinstance(featuresText, str):
                    font.features.text = u"" + featuresText
                elif isinstance(featuresText, unicode):
                    font.features.text = featuresText
        # glyphs
        if glyphNames:
            selectedGlyphNames = glyphNames
        else:
            selectedGlyphNames = self.glyphNames
        # add the glyphnames to the font.lib['public.glyphOrder']
        if not 'public.glyphOrder' in font.lib.keys():
            font.lib['public.glyphOrder'] = selectedGlyphNames
        for glyphName in selectedGlyphNames:
            try:
                glyphMutator = self.getGlyphMutator(glyphName)
            except:
                self.problems.append("Could not make mutator for glyph %s" %
                                     glyphName)
                continue
            if glyphName in instanceDescriptor.glyphs.keys():
                # reminder: this is what the glyphData can look like
                # {'instanceLocation': {'custom': 0.0, 'weight': 824.0},
                #  'masters': [{'font': 'master.Adobe VF Prototype.Master_0.0',
                #               'glyphName': 'dollar.nostroke',
                #               'location': {'custom': 0.0, 'weight': 0.0}},
                #              {'font': 'master.Adobe VF Prototype.Master_1.1',
                #               'glyphName': 'dollar.nostroke',
                #               'location': {'custom': 0.0, 'weight': 368.0}},
                #              {'font': 'master.Adobe VF Prototype.Master_2.2',
                #               'glyphName': 'dollar.nostroke',
                #               'location': {'custom': 0.0, 'weight': 1000.0}},
                #              {'font': 'master.Adobe VF Prototype.Master_3.3',
                #               'glyphName': 'dollar.nostroke',
                #               'location': {'custom': 100.0, 'weight': 1000.0}},
                #              {'font': 'master.Adobe VF Prototype.Master_0.4',
                #               'glyphName': 'dollar.nostroke',
                #               'location': {'custom': 100.0, 'weight': 0.0}},
                #              {'font': 'master.Adobe VF Prototype.Master_4.5',
                #               'glyphName': 'dollar.nostroke',
                #               'location': {'custom': 100.0, 'weight': 368.0}}],
                #  'unicodes': [36]}
                glyphData = instanceDescriptor.glyphs[glyphName]
            else:
                glyphData = {}
            font.newGlyph(glyphName)
            font[glyphName].clear()
            if glyphData.get('mute', False):
                # mute this glyph, skip
                continue
            glyphInstanceLocation = Location(
                glyphData.get("instanceLocation", instanceDescriptor.location))
            try:
                uniValues = glyphMutator[()][0].unicodes
            except IndexError:
                uniValues = []
            glyphInstanceUnicodes = glyphData.get("unicodes", uniValues)
            note = glyphData.get("note")
            if note:
                font[glyphName] = note
            masters = glyphData.get("masters", None)
            if masters:
                items = []
                for glyphMaster in masters:
                    sourceGlyphFont = glyphMaster.get("font")
                    sourceGlyphName = glyphMaster.get("glyphName", glyphName)
                    m = self.fonts.get(sourceGlyphFont)
                    if not sourceGlyphName in m:
                        continue
                    sourceGlyph = MathGlyph(m[sourceGlyphName])
                    sourceGlyphLocation = Location(glyphMaster.get("location"))
                    items.append((sourceGlyphLocation, sourceGlyph))
                bias, glyphMutator = buildMutator(items,
                                                  axes=self._preppedAxes,
                                                  bias=self.defaultLoc)
            try:
                glyphInstanceObject = glyphMutator.makeInstance(
                    glyphInstanceLocation)
            except IndexError:
                # alignment problem with the data?
                print("Error making instance %s" % glyphName)
                continue
            font.newGlyph(glyphName)
            font[glyphName].clear()
            if self.roundGeometry:
                try:
                    glyphInstanceObject = glyphInstanceObject.round()
                except AttributeError:
                    pass
            try:
                glyphInstanceObject.extractGlyph(font[glyphName],
                                                 onlyGeometry=True)
            except TypeError:
                # this causes ruled glyphs to end up in the wrong glyphname
                # but defcon2 objects don't support it
                pPen = font[glyphName].getPointPen()
                font[glyphName].clear()
                glyphInstanceObject.drawPoints(pPen)
            font[glyphName].width = glyphInstanceObject.width
            font[glyphName].unicodes = glyphInstanceUnicodes
        if doRules:
            resultNames = processRules(self.rules, loc, self.glyphNames)
            for oldName, newName in zip(self.glyphNames, resultNames):
                if oldName != newName:
                    swapGlyphNames(font, oldName, newName)
        # copy the glyph lib?
        #for sourceDescriptor in self.sources:
        #    if sourceDescriptor.copyLib:
        #        pass
        #    pass
        # store designspace location in the font.lib
        font.lib['designspace'] = list(instanceDescriptor.location.items())
        return font
    def generateInstanceFont(self, spot, generationInfos):

        # self.w.spotSheet.close()
        # delattr(self.w, 'spotSheet')

        if generationInfos['sourceFont']:

            try:
                masters = self.masters
                baseFont = generationInfos['sourceFont'][0]
                folderPath = None
                s = re.search('(.*)/(.*)(.ufo)', baseFont.path)
                if s is not None:
                    folderPath = s.group(1)
                doKerning = generationInfos['interpolateKerning']
                doFontInfos = generationInfos['interpolateFontInfos']
                doReport = generationInfos['printReport']
                noUI = True

                progress = ProgressWindow('Generating instance', parentWindow=self.w)

                masterFonts = [font for _, font in masters]

                i, j = spot
                ch = getKeyForValue(i)
                instanceLocation = Location(horizontal=i, vertical=j)
                masterLocations = [(Location(horizontal=getValueForKey(_ch), vertical=_j), masterFont) for (_ch, _j), masterFont in masters]

                # Build font
                if hasattr(RFont, 'showUI') or (not hasattr(RFont, 'showUI') and (folderPath is not None)):
                    newFont = RFont(showUI=False)
                elif not hasattr(RFont, 'showUI') and (folderPath is None):
                    newFont = RFont()
                newFont.info.familyName = baseFont.info.familyName
                newFont.info.styleName = '%s%s'%(ch.upper(), j+1)
                try:
                    newFont.glyphOrder = baseFont.glyphOrder
                except:
                    try:
                        newFont.glyphOrder = baseFont.lib['public.glyphOrder']
                    except:
                        try:
                            newFont.lib['public.glyphOrder'] = baseFont.lib['public.glyphOrder']
                        except:
                            try:
                                newFont.lib['public.glyphOrder'] = baseFont.glyphOrder
                            except:
                                pass
                if folderPath is not None:
                    path = '%s/%s-%s%s'%(folderPath, newFont.info.familyName, newFont.info.styleName, '.ufo')
                interpolatedGlyphs = []
                interpolatedInfo = None
                interpolatedKerning = None
                interpolationReports = []

                # interpolate font infos

                if doFontInfos:
                    infoMasters = [(infoLocation, MathInfo(masterFont.info)) for infoLocation, masterFont in masterLocations]
                    try:
                        bias, iM = buildMutator(infoMasters)
                        instanceInfo = iM.makeInstance(instanceLocation)
                        instanceInfo.extractInfo(newFont.info)
                    except:
                        pass

                # interpolate kerning

                if doKerning:
                    kerningMasters = [(kerningLocation, MathKerning(masterFont.kerning)) for kerningLocation, masterFont in masterLocations]
                    try:
                        bias, kM = buildMutator(kerningMasters)
                        instanceKerning = kM.makeInstance(instanceLocation)
                        instanceKerning.extractKerning(newFont)
                        for key, value in baseFont.groups.items():
                            newFont.groups[key] = value
                    except:
                        pass

                # filter compatible glyphs

                fontKeys = [set(masterFont.keys()) for masterFont in masterFonts]
                glyphList = set()
                for i, item in enumerate(fontKeys):
                    if i == 0:
                        glyphList = item
                    elif i > 0:
                        glyphList = glyphList & item

                incompatibleGlyphs = []

                for glyphName in glyphList:
                    glyphs = [(MathGlyph(masterFont[glyphName]), masterFont, masterLocation) for masterLocation, masterFont in masterLocations]
                    allCompatible = True
                    refMasterGlyph = glyphs[0][0]
                    refMasterFont = glyphs[0][1]
                    refMasterLocation = glyphs[0][2]
                    masterGlyphs = [(refMasterLocation, refMasterGlyph)]
                    for masterGlyph, _masterFont, _masterLocation in glyphs[1:]:
                        compatible = refMasterGlyph.isCompatible(masterGlyph)
                        if compatible == False:
                            incompatibleGlyphs.append((glyphName, refMasterFont, _masterFont))
                            allCompatible = False
                        elif compatible == True:
                            masterGlyphs.append((_masterLocation, masterGlyph))

                    if allCompatible:
                        try:
                            bias, gM = buildMutator(masterGlyphs)
                            newGlyph = RGlyph()
                            instanceGlyph = gM.makeInstance(instanceLocation)
                            interpolatedGlyphs.append((glyphName, instanceGlyph.extractGlyph(newGlyph)))
                        except:
                            continue

                for name, interpolatedGlyph in interpolatedGlyphs:
                    newFont.insertGlyph(interpolatedGlyph, name)

                progress.close()
                interpolationReports = []
                digest = []

                if doReport:
                    for glyphName, firstFont, secondFont in incompatibleGlyphs:
                        firstGlyph = firstFont[glyphName]
                        secondGlyph = secondFont[glyphName]
                        comp, report = firstGlyph.isCompatible(secondGlyph)
                        names = '%s <X> %s'%(fontName(firstFont), fontName(secondFont))
                        reportID = (name, report)
                        if reportID not in interpolationReports:
                            digest.append(names)
                            digest += [u'– %s'%(reportLine) for reportLine in report]
                            digest.append('\n')
                            interpolationReports.append(reportID)
                    print '\n'.join(digest)


                if hasattr(RFont, 'showUI') and (folderPath is None):
                    newFont.showUI()
                elif (folderPath is not None):
                    newFont.save(path)
                    f = RFont(path)
            except:
                try:
                    progress.close()
                except:
                    print u'Couldn’t finish generating, something happened…'
                    return
        new.pt = self.pt[0]*factor[0], self.pt[1]*factor[1]
        new.size *= factor[0]      
        new.alpha = self.alpha*factor[0]
        return new
        
    __rmul__ = __mul__    


items = [
   (Location(pop=0, snap=0), MathDot((0,0), name="neutral")),
   (Location(pop=0, snap=1), MathDot((0, 100), name="on-axis-one-A")),
   (Location(pop=1, snap=0), MathDot((100, 0), name="on-axis-two-A")),
   (Location(pop=1, snap=1), MathDot((100, 100), name="off-axis-A")),
]

bias, mb = buildMutator(items)

grid = {}
for loc, (master, xx) in mb.items():
    for axis, value in loc:
        if not axis in grid:
            grid[axis] = []
        if not (axis,value) in grid[axis]:
            grid[axis].append((axis,value))
nodes = list(itertools.product(*grid.values()))
nodes.sort()

corners = {}
for n in nodes:
    l = Location()
    l.fromTuple(n)