def readInstance( self, key, makeGlyphs=True, makeKerning=True, makeInfo=True, bendLocations=False, ): """ Read a single instance element. key: an (attribute, value) tuple used to find the requested instance. :: <instance familyname="SuperFamily" filename="OutputNameInstance1.ufo" location="location-token-aaa" stylename="Regular"> """ attrib, value = key for instanceElement in self.root.findall('.instances/instance'): if instanceElement.attrib.get(attrib) == value: self._readSingleInstanceElement( instanceElement, makeGlyphs=makeGlyphs, makeKerning=makeKerning, makeInfo=makeInfo, bendLocations=bendLocations, ) return raise MutatorError("No instance found with key: (%s, %s)." % key)
def _makeWarpFromList(self, axisName, warpMap): if not warpMap: warpMap = [(0, 0), (1000, 1000)] self.maps[axisName] = warpMap items = [] for x, y in warpMap: items.append((Location(w=x), y)) m = WarpMutator() items.sort() bias = biasFromLocations([loc for loc, obj in items], True) m.setBias(bias) n = None ofx = [] onx = [] for loc, obj in items: if (loc - bias).isOrigin(): m.setNeutral(obj) break if m.getNeutral() is None: raise MutatorError("Did not find a neutral for this system", m) for loc, obj in items: lb = loc - bias if lb.isOrigin(): continue if lb.isOnAxis(): onx.append((lb, obj - m.getNeutral())) else: ofx.append((lb, obj - m.getNeutral())) for loc, obj in onx: m.addDelta(loc, obj, punch=False, axisOnly=True) for loc, obj in ofx: m.addDelta(loc, obj, punch=True, axisOnly=True) self.warps[axisName] = m
def buildMutator(items): """ Build a mutator with the (location, obj) pairs in items. Determine the bias based on the given locations. """ m = Mutator() # the order itself does not matter, but we should always build in the same order. items.sort() bias = biasFromLocations([loc for loc, obj in items], True) m.setBias(bias) n = None ofx = [] onx = [] for loc, obj in items: if (loc - bias).isOrigin(): m.setNeutral(obj) break if m.getNeutral() is None: raise MutatorError("Did not find a neutral for this system", m) for loc, obj in items: lb = loc - bias if lb.isOrigin(): continue if lb.isOnAxis(): onx.append((lb, obj - m.getNeutral())) else: ofx.append((lb, obj - m.getNeutral())) for loc, obj in onx: m.addDelta(loc, obj, punch=False, axisOnly=True) for loc, obj in ofx: m.addDelta(loc, obj, punch=True, axisOnly=True) return bias, m
def __call__(self, loc): # bend a location according to the defined warps new = loc.copy() for dim, warp in self.warps.items(): if not dim in loc: continue try: new[dim] = warp(loc.get(dim)) except: ex_type, ex, tb = sys.exc_info() raise MutatorError("A warpfunction \"%s\" (for axis \"%s\") raised \"%s\" at location %s"%(warp.__name__, dim, ex, loc.asString()), loc) return new
def buildMutator(items, axes=None, bias=None): """ Build a mutator with the (location, obj) pairs in items. Determine the bias based on the given locations. """ from mutatorMath.objects.bender import Bender items = [(Location(loc), obj) for loc, obj in items] if bias is None: bias = Location() else: bias = Location(bias) m = Mutator() if axes is not None: # make a Bender object # but do not transform the locations from the items bender = Bender(axes) m.setBender(bender) else: bender = noBend # the order itself does not matter, but we should always build in the same order. items = sorted(items) if not bias: bias = biasFromLocations([loc for loc, obj in items], True) m.setBias(bias) n = None ofx = [] onx = [] for loc, obj in items: nn = (loc - bias) if nn.isOrigin(): m.setNeutral(obj) break if m.getNeutral() is None: raise MutatorError("Did not find a neutral for this system", items) for loc, obj in items: lb = loc - bias if lb.isOrigin(): continue if lb.isOnAxis(): onx.append((lb, obj - m.getNeutral())) else: ofx.append((lb, obj - m.getNeutral())) for loc, obj in onx: m.addDelta(loc, obj, punch=False, axisOnly=True) for loc, obj in ofx: m.addDelta(loc, obj, punch=True, axisOnly=True) return bias, m
def addDelta(self, location, aMathObject, deltaName = None, punch=False, axisOnly=True): """ Add a delta at this location. * location: a Location object * mathObject: a math-sensitive object * deltaName: optional string/token * punch: * True: add the difference with the instance value at that location and the delta * False: just add the delta. """ #location = self._bender(location) if punch: r = self.getInstance(location, axisOnly=axisOnly) if r is not None: self[location.asTuple()] = aMathObject-r, deltaName else: raise MutatorError("Could not get instance.") else: self[location.asTuple()] = aMathObject, deltaName
def buildMutator(items, axes=None, bias=None): """ Build a mutator with the (location, obj) pairs in items. Determine the bias based on the given locations. """ from mutatorMath.objects.bender import Bender m = Mutator() if axes is not None: bender = Bender(axes) m.setBender(bender) else: bender = noBend # the order itself does not matter, but we should always build in the same order. items = sorted(items) if not bias: bias = biasFromLocations([bender(loc) for loc, obj in items], True) else: # note: this means that the actual bias might be different from the initial value. bias = bender(bias) m.setBias(bias) n = None ofx = [] onx = [] for loc, obj in items: loc = bender(loc) if (loc-bias).isOrigin(): m.setNeutral(obj) break if m.getNeutral() is None: raise MutatorError("Did not find a neutral for this system", m) for loc, obj in items: locbent = bender(loc) #lb = loc-bias lb = locbent-bias if lb.isOrigin(): continue if lb.isOnAxis(): onx.append((lb, obj-m.getNeutral())) else: ofx.append((lb, obj-m.getNeutral())) for loc, obj in onx: m.addDelta(loc, obj, punch=False, axisOnly=True) for loc, obj in ofx: m.addDelta(loc, obj, punch=True, axisOnly=True) return bias, m
def _makeWarpFromList(self, axisName, warpMap, minimum, maximum): if not warpMap: warpMap = [(minimum,minimum), (maximum,maximum)] self.warps[axisName] = warpMap # check for the extremes, add if necessary if not sum([a==minimum for a, b in warpMap]): warpMap = [(minimum,minimum)] + warpMap if not sum([a==maximum for a, b in warpMap]): warpMap.append((maximum,maximum)) items = [] for x, y in warpMap: items.append((Location(w=x), y)) m = WarpMutator() items.sort() bias = biasFromLocations([loc for loc, obj in items], True) m.setBias(bias) n = None ofx = [] onx = [] for loc, obj in items: if (loc-bias).isOrigin(): m.setNeutral(obj) break if m.getNeutral() is None: raise MutatorError("Did not find a neutral for this system", m) for loc, obj in items: lb = loc-bias if lb.isOrigin(): continue if lb.isOnAxis(): onx.append((lb, obj-m.getNeutral())) else: ofx.append((lb, obj-m.getNeutral())) for loc, obj in onx: m.addDelta(loc, obj, punch=False, axisOnly=True) for loc, obj in ofx: m.addDelta(loc, obj, punch=True, axisOnly=True) self.warps[axisName] = m
def readGlyphElement(self, glyphElement, instanceObject): """ Read the glyph element. :: <glyph name="b" unicode="0x62"/> <glyph name="b"/> <glyph name="b"> <master location="location-token-bbb" source="master-token-aaa2"/> <master glyphname="b.alt1" location="location-token-ccc" source="master-token-aaa3"/> <note> This is an instance from an anisotropic interpolation. </note> </glyph> """ # name glyphName = glyphElement.attrib.get('name') if glyphName is None: raise MutatorError("Glyph object without name attribute.") # mute mute = glyphElement.attrib.get("mute") if mute == "1": instanceObject.muteGlyph(glyphName) # we do not need to stick around after this return # unicode unicodes = glyphElement.attrib.get('unicode') if unicodes == None: unicodes = self.unicodeMap.get(glyphName, None) else: try: unicodes = [int(u, 16) for u in unicodes.split(" ")] except ValueError: raise MutatorError("unicode values %s are not integers" % unicodes) # note note = None for noteElement in glyphElement.findall('.note'): note = noteElement.text break # location instanceLocation = self.locationFromElement(glyphElement) # masters glyphSources = None for masterElement in glyphElement.findall('.masters/master'): fontSourceName = masterElement.attrib.get('source') fontSource, fontLocation = self.sources.get(fontSourceName) if fontSource is None: raise MutatorError("Unknown glyph master: %s" % masterElement) sourceLocation = self.locationFromElement(masterElement) if sourceLocation is None: # if we don't read a location, use the instance location sourceLocation = fontLocation masterGlyphName = masterElement.attrib.get('glyphname') if masterGlyphName is None: # if we don't read a glyphname, use the one we have masterGlyphName = glyphName d = dict(font=fontSource, location=sourceLocation, glyphName=masterGlyphName) if glyphSources is None: glyphSources = [] glyphSources.append(d) # calculate the glyph instanceObject.addGlyph(glyphName, unicodes, instanceLocation, glyphSources, note=note)
def readSources(self): """ Read the source elements. :: <source filename="LightCondensed.ufo" location="location-token-aaa" name="master-token-aaa1"> <info mute="1" copy="1"/> <kerning mute="1"/> <glyph mute="1" name="thirdGlyph"/> </source> """ for sourceCount, sourceElement in enumerate( self.root.findall(".sources/source")): # shall we just read the UFO here? filename = sourceElement.attrib.get('filename') # filename is a path relaive to the documentpath. resolve first. sourcePath = os.path.abspath( os.path.join(os.path.dirname(self.path), filename)) sourceName = sourceElement.attrib.get('name') if sourceName is None: # if the source element has no name attribute # (some authoring tools do not need them) # then we should make a temporary one. We still need it for reference. sourceName = "temp_master.%d" % (sourceCount) self.reportProgress("prep", 'load', sourcePath) if not os.path.exists(sourcePath): raise MutatorError("Source not found at %s" % sourcePath) sourceObject = self._instantiateFont(sourcePath) # read the locations sourceLocationObject = None sourceLocationObject = self.locationFromElement(sourceElement) if sourceLocationObject is None: raise MutatorError("No location defined for source %s" % sourceName) # read lib flag for libElement in sourceElement.findall('.lib'): if libElement.attrib.get('copy') == '1': self.libSource = sourceName # read the groups flag for groupsElement in sourceElement.findall('.groups'): if groupsElement.attrib.get('copy') == '1': self.groupsSource = sourceName # read the info flag for infoElement in sourceElement.findall(".info"): if infoElement.attrib.get('copy') == '1': self.infoSource = sourceName if infoElement.attrib.get('mute') == '1': self.muted['info'].append(sourceName) # read the features flag for featuresElement in sourceElement.findall(".features"): if featuresElement.attrib.get('copy') == '1': if self.featuresSource is not None: self.featuresSource = None else: self.featuresSource = sourceName mutedGlyphs = [] for glyphElement in sourceElement.findall(".glyph"): glyphName = glyphElement.attrib.get('name') if glyphName is None: continue if glyphElement.attrib.get('mute') == '1': if not sourceName in self.muted['glyphs']: self.muted['glyphs'][sourceName] = [] self.muted['glyphs'][sourceName].append(glyphName) for kerningElement in sourceElement.findall(".kerning"): if kerningElement.attrib.get('mute') == '1': self.muted['kerning'].append(sourceName) # store self.sources[sourceName] = sourceObject, sourceLocationObject self.reportProgress("prep", 'done')
def readSources(self): """ Read the source elements. :: <source filename="LightCondensed.ufo" location="location-token-aaa" name="master-token-aaa1"> <info mute="1" copy="1"/> <kerning mute="1"/> <glyph mute="1" name="thirdGlyph"/> </source> """ for sourceElement in self.root.findall(".sources/source"): # shall we just read the UFO here? filename = sourceElement.attrib.get('filename') # filename is a path relaive to the documentpath. resolve first. print("filename " + filename) # sourcePath = os.path.join(os.path.dirname(self.path), filename) sourcePath = filename sourceName = sourceElement.attrib.get('name') if not os.path.exists(sourcePath): raise MutatorError("Source not found at %s" % sourcePath) print("loading from sourcePath " + sourcePath) sourceObject = self._fontClass(sourcePath) # read the locations sourceLocationObject = None for sourceLocationElement in sourceElement.findall('.location'): sourceLocationObject = self.readLocationElement( sourceLocationElement) break if sourceLocationObject is None: raise MutatorError("No location defined for source %s" % sourceName) # read lib flag for libElement in sourceElement.findall('.lib'): if libElement.attrib.get('copy') == '1': if self.libSource is not None: if self.verbose: self.logger.info( "\tError: Lib copy source already defined: %s, %s", sourceName, self.libSource) self.libSource = None else: self.libSource = sourceName # read the groups flag for groupsElement in sourceElement.findall('.groups'): if groupsElement.attrib.get('copy') == '1': if self.groupsSource is not None: if self.verbose: self.logger.info( "\tError: Groups copy source already defined: %s, %s", sourceName, self.groupsSource) self.groupsSource = None else: self.groupsSource = sourceName # read the info flag for infoElement in sourceElement.findall(".info"): if infoElement.attrib.get('copy') == '1': if self.infoSource is not None: if self.verbose: self.logger.info( "\tError: Info copy source already defined: %s, %s", sourceName, self.infoSource) self.infoSource = None else: self.infoSource = sourceName if infoElement.attrib.get('mute') == '1': self.muted['info'].append(sourceName) if self.verbose: self.logger.info("\tFont info from %s is muted.", sourceName) mutedGlyphs = [] for glyphElement in sourceElement.findall(".glyph"): glyphName = glyphElement.attrib.get('name') if glyphName is None: continue if glyphElement.attrib.get('mute') == '1': if not sourceName in self.muted['glyphs']: self.muted['glyphs'][sourceName] = [] self.muted['glyphs'][sourceName].append(glyphName) for kerningElement in sourceElement.findall(".kerning"): if kerningElement.attrib.get('mute') == '1': self.muted['kerning'].append(sourceName) # store self.sources[sourceName] = sourceObject, sourceLocationObject