예제 #1
0
    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)
예제 #2
0
 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
예제 #3
0
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
예제 #4
0
 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
예제 #5
0
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
예제 #6
0
 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
예제 #7
0
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
예제 #8
0
 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
예제 #9
0
    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)
예제 #10
0
    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')
예제 #11
0
    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