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)
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)
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)
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)
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)
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)
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)
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)
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]
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)
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()
def getInstance(self, location, masters): try: b, m = buildMutator(masters) if m is not None: instance = m.makeInstance(location) return instance except: return
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
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
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')
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')
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
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
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
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
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
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
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)
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
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
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()
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()
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()
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()
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)
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:
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()
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)