Ejemplo n.º 1
0
def italicizeGlyph(f,
                   g,
                   angle=10,
                   stemWidth=185,
                   meanYCenter=-825,
                   narrowAmount=1):
    unic = g.unicode  #save unicode

    glyph = f[g.name]
    slope = np.tanh(math.pi * angle / 180)

    # determine how far on the x axis the glyph should slide
    # to compensate for the slant.
    # meanYCenter:
    #   -600 is a magic number that assumes a 2048 unit em square,
    #   and -825 for a 2816 unit em square. (UPM*0.29296875)
    m = Transform(1, 0, slope, 1, 0, 0)
    xoffset, junk = m.transformPoint((0, meanYCenter))
    m = Transform(narrowAmount, 0, slope, 1, xoffset, 0)

    if len(glyph) > 0:
        g2 = italicize(f[g.name], angle, xoffset=xoffset, stemWidth=stemWidth)
        f.insertGlyph(g2, g.name)

    transformFLGlyphMembers(f[g.name], m)

    if unic > 0xFFFF:  #restore unicode
        g.unicode = unic
Ejemplo n.º 2
0
    def getGlyph(self, glyph, skew, rotation, addComponents=False):
        skew = radians(skew)
        rotation = radians(-rotation)

        dest = glyph.copy()

        if not addComponents:
            for component in dest.components:
                pointPen = DecomposePointPen(glyph.getParent(), dest.getPointPen(), component.transformation)
                component.drawPoints(pointPen)
                dest.removeComponent(component)

        for contour in list(dest):
            if contour.open:
                dest.removeContour(contour)

        if skew == 0 and rotation == 0:
            return dest

        for contour in dest:
            for bPoint in contour.bPoints:
                bcpIn = bPoint.bcpIn
                bcpOut = bPoint.bcpOut
                if bcpIn == (0, 0):
                    continue
                if bcpOut == (0, 0):
                    continue
                if bcpIn[0] == bcpOut[0] and bcpIn[1] != bcpOut[1]:
                    bPoint.anchorLabels = ["extremePoint"]
                if rotation and bcpIn[0] != bcpOut[0] and bcpIn[1] == bcpOut[1]:
                    bPoint.anchorLabels = ["extremePoint"]

        cx, cy = 0, 0
        box = glyph.box
        if box:
            cx = box[0] + (box[2] - box[0]) * .5
            cy = box[1] + (box[3] - box[1]) * .5

        t = Transform()
        t = t.skew(skew)
        t = t.translate(cx, cy).rotate(rotation).translate(-cx, -cy)

        # RF3
        if version >= "3.0":
            dest.transformBy(tuple(t))
        # RF1
        else:
            dest.transform(t)

        dest.extremePoints(round=0)
        for contour in dest:
            for point in contour.points:
                if "extremePoint" in point.labels:
                    point.selected = True
                    point.smooth = True
                else:
                    point.selected = False
        dest.removeSelection()
        dest.round()
        return dest
Ejemplo n.º 3
0
def getKernel(radius, amplitude=1, depth=50, angle=0):
    """
    >>> a = getKernel(5)
    >>> a[(0,0)]
    0.03662899097662087
    >>> a[(2,0)]
    0.02371649522786113
    """
    t = Transform()
    t = t.rotate(angle)
    lines = getCircle(0, 0, radius)
    sigma = (radius+1) / math.sqrt(2*math.log(depth))
    grid = {}
    total = 0
    for y, (xMin, xMax) in lines.items():
        for x in range(xMin, xMax+1, 1):
            g = xyGaussian(x,y, amplitude, 0, 0, sigma, sigma)
            grid[(x,y)]=grid.get((x,y), 0)+g
            total += g
    # scale the amplitude based on the total
    grid = {k: float(v)/total for k, v in grid.items()}
    # rotate the grid
    grid = grid
    new = {}
    for k, v in grid.items():
        k_ = t.transformPoint(k)
        new[k_] = v
    grid = new
    return grid
Ejemplo n.º 4
0
 def test_reverseTransform(self):
     t = Transform(2, 0, 0, 3, 1, 6)
     reverse_t = t.reverseTransform((4, 3, 2, 1, 5, 6))
     assert reverse_t == Transform(8, 6, 6, 3, 21, 15)
     t = Transform(4, 3, 2, 1, 5, 6)
     reverse_t = t.transform((2, 0, 0, 3, 1, 6))
     assert reverse_t == Transform(8, 6, 6, 3, 21, 15)
Ejemplo n.º 5
0
def transformationAtCenter(matrix, centerPoint):
    """Helper function for rotate(), scale() and skew() to apply a
    transformation with a specified center point.

        >>> transformationAtCenter((2, 0, 0, 2, 0, 0), (0, 0))
        (2, 0, 0, 2, 0, 0)
        >>> transformationAtCenter((2, 0, 0, 2, 0, 0), (100, 200))
        (2, 0, 0, 2, -100, -200)
        >>> transformationAtCenter((-2, 0, 0, 2, 0, 0), (100, 200))
        (-2, 0, 0, 2, 300, -200)
        >>> t = Transform(*transformationAtCenter((0, 1, 1, 0, 0, 0), (100, 200)))
        >>> t.transformPoint((100, 200))
        (100, 200)
        >>> t.transformPoint((0, 0))
        (-100, 100)
    """
    if centerPoint == (0, 0):
        return matrix

    t = Transform()
    cx, cy = centerPoint
    t = t.translate(cx, cy)
    t = t.transform(matrix)
    t = t.translate(-cx, -cy)
    return tuple(t)
def GlyphConstructionBuilder(construction, font):
    # create a construction glyph
    destination = ConstructionGlyph(font)
    # test if the input is a proper string
    try:
        construction = str(construction)
    except:
        return destination
    # parse the note
    destination.note, construction = parseNote(construction)
    # check if there is a = sing
    if glyphNameSplit not in construction:
        return destination
    # remove all spaces and tabs
    construction = removeSpacesAndTabs(construction)
    # escape math formulas inside a ` `  
    construction = forceEscapingMathOperations(construction)
    # extract the name
    destination.name, construction = parseGlyphName(construction)
    # extract glyph attributes
    glyphAttributes, construction = parseGlyphattributes(construction, font)
    # split into base glyphs, ligatures
    baseGlyphs = construction.split(baseGlyphSplit)
    
    advanceWidth = 0
    # start
    for baseGlyph in baseGlyphs:
        # split into mark glyphs
        markGlyphs = baseGlyph.split(markGlyphSplit)
        baseGlyph = None    
        baseMarkGlyph = None
        baseTransformMatrix = [1, 0, 0, 1, 0, 0]
        markTransformMap = {}
        
        advanceHeight = 0
        
        for markGlyph in markGlyphs:
            markGlyph = reEscapeMathOperations(markGlyph)
            component, transformMatrix = parsePositions(baseMarkGlyph, markGlyph, font, markTransformMap, advanceWidth, advanceHeight)
            destination.addComponent(component, transformMatrix)

            markTransformMap[component] = transformMatrix
            
            baseMarkGlyph = component
            
            if baseGlyph is None:
                baseGlyph = component
                baseTransformMatrix = transformMatrix
            
        if baseGlyph in font:
            width = font[baseGlyph].width
            t = Transform(*baseTransformMatrix)
            width, y = t.transformPoint((width-advanceWidth, 0))
            advanceWidth += width
            
    destination.width = advanceWidth
    for key, value in glyphAttributes.items():
        setattr(destination, key, value)
    return destination
Ejemplo n.º 7
0
def makeSVGShape(glyph, name=None, width=None, opacity=None):
    attrs = {
        'id':
        'mathShape',
        'title':
        "None",
        'xmlns':
        "http://www.w3.org/2000/svg",
        'xmlns:xlink':
        "http://www.w3.org/1999/xlink",
        'xml:space':
        'preserve',
        'style':
        "fill-rule:nonzero;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;",
    }
    # try to get the bounds from the bounds layer.
    # if that does not work, get it from the glyph itself.
    bounds = None
    try:
        boundsGlyph = glyph.getLayer('bounds')
        if boundsGlyph is not None:
            bounds = boundsGlyph.box
            # print 'using bounds from bounds layer'
    except:
        pass
        # print 'using bounds from glyph'
    if bounds is None:
        boundsPen = BoundsPen({})
        glyph.draw(boundsPen)
        bounds = boundsPen.bounds

    xOffset = 0
    yOffset = 0
    attrs['id'] = name
    if width is None:
        attrs['width'] = "100%"
    else:
        attrs['width'] = width
    if name is not None:
        attrs['name'] = name
    else:
        attrs['name'] = glyph.name
    if opacity is not None:
        attrs['fill-opacity'] = "%3.3f" % opacity

    t = Transform()
    # print bounds, -(bounds[3]-bounds[1])
    t = t.scale(1, -1)
    t = t.translate(0, -bounds[3])
    vb = (0, 0, glyph.width, bounds[3] - bounds[1])
    attrs['viewBox'] = "%3.3f %3.3f %3.3f %3.3f" % (vb[0], vb[1], vb[2], vb[3])
    attrs['enable-background'] = attrs['viewBox']
    sPen = MathImageSVGPathPen({})
    tPen = TransformPen(sPen, t)
    glyph.draw(tPen)
    path = "<path d=\"%s\"/>" % (sPen.getCommands())
    tag = "<svg %s>%s</svg>" % (" ".join(
        ["%s=\"%s\"" % (k, v) for k, v in attrs.items()]), path)
    return vb, tag
Ejemplo n.º 8
0
 def _get_controlPointBounds(self):
     from fontTools.misc.transform import Transform
     # storage
     glyphRects = {}
     componentReferences = {}
     # scan loaded glyphs
     for glyphName, glyph in self._glyphs.items():
         if glyphName in self._scheduledForDeletion:
             continue
         glyphRect = glyph.controlPointBounds
         if glyphRect:
             glyphRects[glyphName] = glyphRect
     # scan glyphs that have not been loaded
     if self._glyphSet is not None:
         for glyphName, fileName in self._glyphSet.contents.items():
             if glyphName in self._glyphs or glyphName in self._scheduledForDeletion:
                 continue
             glif = self._glyphSet.getGLIF(glyphName)
             points, components = _fetchControlPointBoundsData(glif)
             if points:
                 glyphRects[glyphName] = calcBounds(points)
             for base, transformation in components:
                 xScale, xyScale, yxScale, yScale, xOffset, yOffset = transformation
                 if glyphName not in componentReferences:
                     componentReferences[glyphName] = []
                 componentReferences[glyphName].append((base, xScale, xyScale, yxScale, yScale, xOffset, yOffset))
     # get the transformed component bounding boxes and update the glyphs
     for glyphName, components in componentReferences.items():
         glyphRect = glyphRects.get(glyphName, (None, None, None, None))
         # XXX this doesn't handle nested components
         for base, xScale, xyScale, yxScale, yScale, xOffset, yOffset in components:
             # base glyph doesn't exist
             if base not in glyphRects:
                 continue
             baseRect = glyphRects[base]
             # base glyph has no points
             if None in baseRect:
                 continue
             # transform the base rect
             transform = Transform(xx=xScale, xy=xyScale, yx=yxScale, yy=yScale, dx=xOffset, dy=yOffset)
             xMin, yMin, xMax, yMax = baseRect
             (xMin, yMin), (xMax, yMax) = transform.transformPoints([(xMin, yMin), (xMax, yMax)])
             componentRect = (xMin, yMin, xMax, yMax)
             # update the glyph rect
             if None in glyphRect:
                 glyphRect = componentRect
             else:
                 glyphRect = unionRect(glyphRect, componentRect)
         # store the updated rect
         glyphRects[glyphName] = glyphRect
     # work out the unified rect
     fontRect = None
     for glyphRect in glyphRects.values():
         if fontRect is None:
             fontRect = glyphRect
         elif glyphRect is not None:
             fontRect = unionRect(fontRect, glyphRect)
     # done
     return fontRect
Ejemplo n.º 9
0
 def skew(self, x=0, y=0, point=None):
     t = Transform()
     if not point:
         point = self.bounds().point("C") # maybe should be getFrame()?
     t = t.translate(point.x, point.y)
     t = t.skew(x, y)
     t = t.translate(-point.x, -point.y)
     return self.transform(t)
Ejemplo n.º 10
0
 def rotate(self, degrees, point=None):
     t = Transform()
     if not point:
         point = self.point("C")
     t = t.translate(point.x, point.y)
     t = t.rotate(math.radians(degrees))
     t = t.translate(-point.x, -point.y)
     return self.transform(t)
Ejemplo n.º 11
0
 def skew(self, x=0, y=0, unalign=True):
     t = Transform()
     if unalign != False:
         point = self.bounds().point("SW")  # maybe should be getFrame()?
         t = t.translate(point.x, point.y)
     t = t.skew(x, y)
     if unalign != False:
         t = t.translate(-point.x, -point.y)
     return self.transform(t)
Ejemplo n.º 12
0
 def rotate(self, degrees, point=None):
     """Rotate this shape by a degree (in 360-scale, counterclockwise)."""
     t = Transform()
     if not point:
         point = self.bounds().point("C")  # maybe should be getFrame()?
     t = t.translate(point.x, point.y)
     t = t.rotate(math.radians(degrees))
     t = t.translate(-point.x, -point.y)
     return self.transform(t, transformFrame=False)
Ejemplo n.º 13
0
 def transform(self, transform, center=(0, 0)):
     cx, cy = center
     t = Transform()
     t = t.translate(cx, cy)
     t = t.transform(transform)
     t = t.translate(-cx, -cy)
     matrix = skia.Matrix()
     matrix.setAffine(t)
     self.path.transform(matrix)
Ejemplo n.º 14
0
 def scale(self, scaleX, scaleY=None, point=None):
     """Scale this shape by a percentage amount (1-scale)."""
     t = Transform()
     if point != False:
         point = self.bounds().point("C") if point == None else point # maybe should be getFrame()?
         t = t.translate(point.x, point.y)
     t = t.scale(scaleX, scaleY or scaleX)
     if point != False:
         t = t.translate(-point.x, -point.y)
     return self.transform(t)
Ejemplo n.º 15
0
def adjust_anchors(anchor_data, ufo, component):
    """Adjust anchors to which a mark component may have been attached."""

    glyph = ufo[component.baseGlyph]
    t = Transform(*component.transformation)
    for anchor in glyph.anchors:
        # only adjust if this anchor has data and the component also contains
        # the associated mark anchor (e.g. "_top" for "top")
        if (anchor.name in anchor_data and
            any(a.name == '_' + anchor.name for a in glyph.anchors)):
            anchor_data[anchor.name] = t.transformPoint((anchor.x, anchor.y))
Ejemplo n.º 16
0
 def rotate(self, degrees, point=None):
     if Transform:
         t = Transform()
         if not point:
             point = self.mid
         t = t.translate(point.x, point.y)
         t = t.rotate(math.radians(degrees))
         t = t.translate(-point.x, -point.y)
         return self.transform(t)
     else:
         raise Exception("fontTools not installed")
Ejemplo n.º 17
0
def adjust_anchors(anchor_data, ufo, component):
    """Adjust anchors to which a mark component may have been attached."""

    glyph = ufo[component.baseGlyph]
    t = Transform(*component.transformation)
    for anchor in glyph.anchors:
        # only adjust if this anchor has data and the component also contains
        # the associated mark anchor (e.g. "_top" for "top")
        if (anchor.name in anchor_data and
            any(a.name == '_' + anchor.name for a in glyph.anchors)):
            anchor_data[anchor.name] = t.transformPoint((anchor.x, anchor.y))
Ejemplo n.º 18
0
def makeSVGShape(glyph, name=None, width=None, opacity=None):
    attrs = {
        'id': 'mathShape',
        'title': "None",
        'xmlns': "http://www.w3.org/2000/svg",
        'xmlns:xlink' : "http://www.w3.org/1999/xlink",
        'xml:space':'preserve',
        'style': "fill-rule:nonzero;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;",
    }
    # try to get the bounds from the bounds layer.
    # if that does not work, get it from the glyph itself.
    bounds = None
    try:
        boundsGlyph = glyph.getLayer('bounds')
        if boundsGlyph is not None:
            bounds = boundsGlyph.box
            # print 'using bounds from bounds layer'
    except:
        pass
        # print 'using bounds from glyph'
    if bounds is None:
        boundsPen = BoundsPen({})
        glyph.draw(boundsPen)
        bounds = boundsPen.bounds

    xOffset = 0
    yOffset = 0
    attrs['id']= name;
    if width is None:
        attrs['width'] = "100%"
    else:
        attrs['width'] = width
    if name is not None:
        attrs['name'] = name
    else:
        attrs['name'] = glyph.name
    if opacity is not None:
        attrs['fill-opacity'] = "%3.3f"%opacity


    t = Transform()
    # print bounds, -(bounds[3]-bounds[1])
    t = t.scale(1,-1)
    t = t.translate(0, -bounds[3])
    vb = (0, 0, glyph.width, bounds[3]-bounds[1])
    attrs['viewBox'] = "%3.3f %3.3f %3.3f %3.3f"%(vb[0],vb[1],vb[2],vb[3])
    attrs['enable-background']  = attrs['viewBox'] 
    sPen = MathImageSVGPathPen({})
    tPen = TransformPen(sPen, t)
    glyph.draw(tPen)
    path = "<path d=\"%s\"/>"%(sPen.getCommands())
    tag = "<svg %s>%s</svg>"%(" ".join(["%s=\"%s\""%(k,v) for k, v in attrs.items()]), path)
    return vb, tag
Ejemplo n.º 19
0
 def test_reverseTransform(self):
     t = Transform(2, 0, 0, 3, 1, 6)
     reverse_t = t.reverseTransform((4, 3, 2, 1, 5, 6))
     assert reverse_t == Transform(8, 6, 6, 3, 21, 15)
     t = Transform(4, 3, 2, 1, 5, 6)
     reverse_t = t.transform((2, 0, 0, 3, 1, 6))
     assert reverse_t == Transform(8, 6, 6, 3, 21, 15)
def _adjust_anchors(anchor_data, glyphSet, component):
    """
    Adjust base anchors to which a mark component may have been attached, by
    moving the base anchor attached to a mark anchor to the position of
    the mark component's base anchor.
    """

    glyph = glyphSet[component.baseGlyph]
    t = Transform(*component.transformation)
    for anchor in glyph.anchors:
        # only adjust if this anchor has data and the component also contains
        # the associated mark anchor (e.g. "_top" for "top")
        if anchor.name in anchor_data and any(a.name == "_" + anchor.name
                                              for a in glyph.anchors):
            anchor_data[anchor.name] = t.transformPoint((anchor.x, anchor.y))
 def filter(self, glyph):
     if not glyph.components:
         return False
     ufo2ft.util.deepCopyContours(self.context.glyphSet, glyph, glyph,
                                  Transform())
     glyph.clearComponents()
     return True
Ejemplo n.º 22
0
def SelectedComponentsQPainterPathFactory(glyph):
    pen = OnlyComponentsQtPen(glyph.layer)
    pointPen = PointToSegmentPen(pen)
    selectedPen = OnlyComponentsQtPen(glyph.layer)
    selectedPointPen = PointToSegmentPen(selectedPen)
    originPts = []
    for component in glyph.components:
        if component.selected:
            component.drawPoints(selectedPointPen)
            t = Transform(*component.transformation)
            originPts.append(t.transformPoint((0, 0)))
        else:
            component.drawPoints(pointPen)
    pen.path.setFillRule(Qt.WindingFill)
    selectedPen.path.setFillRule(Qt.WindingFill)
    return (pen.path, selectedPen.path, originPts)
Ejemplo n.º 23
0
def propogateAnchors(layer):
    for component in layer.components:
        clayer = component.layer or component.component.layers[0]
        propogateAnchors(clayer)
        for anchor in clayer.anchors:
            names = [a.name for a in layer.anchors]
            name = anchor.name
            if name.startswith("_") or name in names:
                continue
            x, y = anchor.position.x, anchor.position.y
            if component.transform != DEFAULT_TRANSFORM:
                t = Transform(*component.transform.value)
                x, y = t.transformPoint((x, y))
            new = GSAnchor(name)
            new.position.x, new.position.y = (x, y)
            layer.anchors[name] = new
Ejemplo n.º 24
0
def condenseFont(font, scale=.8, stemWidth=185):
    f = font.copy()

    xscale = scale
    CAPS = ("A B C.cn D.cn E F G.cn H I J K L M N O.cn P Q.cn R S T U.cn V W X "
            "Y Z one two three four five six seven eight nine zero").split()
    LC = ("a.cn b.cn c.cn d.cn e.cn f g.cn h i j k l m n o.cn p.cn q.cn r s t "
          "u v w x y z").split()
    # for g in [f[name] for name in LC]:
    for g in f:
        if len(g) > 0:
            # print g.name
            if g.name in lessCondensed:
                scale = xscale * 1.1
            if g.name in uncondensed:
                continue
            if g.name in moreCondensed:
                scale = xscale * .90
            # g2 = condenseGlyph(g, xscale)
            # g.clear()
            # g2.drawPoints(g.getPointPen())
        m = Transform(xscale, 0, 0, 1, 20, 0)
        g.transform(m)
        transformFLGlyphMembers(g, m, transformAnchors=False)
        if g.width != 0:
            g.width += 40
    return f
Ejemplo n.º 25
0
def build_font(srcs, metadata, filename):
    ascent = 880
    descent = 120
    upem = ascent + descent
    scale = upem / 360.0
    transform = Transform(scale, 0, 0, -scale, 0, ascent)
    glyphs = collect_glyphs(srcs, transform=transform)

    builder = FontBuilder(1000, isTTF=False)
    builder.setupGlyphOrder([glyph.name for glyph in glyphs])
    builder.setupCharacterMap({0: ".notdef"})
    psname = metadata["psName"]
    builder.setupCFF(psname, {"FullName": psname},
                     {glyph.name: glyph.charstring
                      for glyph in glyphs}, {})
    builder.setupHorizontalMetrics(
        {glyph.name: glyph.get_hmetrics()
         for glyph in glyphs})
    builder.setupHorizontalHeader(ascent=ascent, descent=-descent)
    builder.setupNameTable({})
    builder.setupOS2()
    builder.setupPost()
    builder.setupVerticalMetrics(
        {glyph.name: glyph.get_vmetrics(ascent=ascent)
         for glyph in glyphs})
    builder.setupVerticalOrigins({}, ascent)
    builder.setupVerticalHeader(ascent=ascent, descent=-descent)
    builder.save(filename)
Ejemplo n.º 26
0
class Component(object):
    baseGlyph = attr.ib(type=str)
    transformation = attr.ib(
        default=Identity,
        converter=lambda t: t if isinstance(t, Transform) else Transform(*t),
        type=Transform,
    )
    identifier = attr.ib(default=None, type=Optional[str])

    # -----------
    # Pen methods
    # -----------

    def draw(self, pen):
        pointPen = PointToSegmentPen(pen)
        self.drawPoints(pointPen)

    def drawPoints(self, pointPen):
        try:
            pointPen.addComponent(
                self.baseGlyph, self.transformation, identifier=self.identifier
            )
        except TypeError:
            pointPen.addComponent(self.baseGlyph, self.transformation)
            warnings.warn(
                "The addComponent method needs an identifier kwarg. "
                "The component's identifier value has been discarded.",
                UserWarning,
            )
Ejemplo n.º 27
0
    def decompose_glyphs(self, ufos):
        """Move components of UFOs' glyphs to their outlines."""

        for ufo in ufos:
            print('>> Decomposing glyphs for ' + self._font_name(ufo))
            for glyph in ufo:
                self._deep_copy_contours(ufo, glyph, glyph, Transform())
                glyph.clearComponents()
Ejemplo n.º 28
0
 def _getBounds(self, boundsAttr):
     layer = self.layer
     if layer is None:
         return None
     if self.baseGlyph not in layer:
         return None
     glyph = layer[self.baseGlyph]
     bounds = getattr(glyph, boundsAttr)
     if bounds is None:
         return None
     if self.transformation == _defaultTransformation:
         return bounds
     xMin, yMin, xMax, yMax = bounds
     t = Transform(*self.transformation)
     points = [(xMin, yMin), (xMax, yMax)]
     (xMin, yMin), (xMax, yMax) = t.transformPoints(points)
     return xMin, yMin, xMax, yMax
 def __init__(self, outPen, transformation):
     if not hasattr(transformation, "transformPoint"):
         from fontTools.misc.transform import Transform
         transformation = Transform(*transformation)
     self._transformation = transformation
     self._transformPoint = transformation.transformPoint
     self._outPen = outPen
     self._stack = []
Ejemplo n.º 30
0
    def addComponent(self, baseGlyph, transformation, identifier=None, **kwargs):
        if baseGlyph in self.modified:
            # multiply the component's transformation matrix with the inverse
            # of the filter's transformation matrix to compensate for the
            # transformation already applied to the base glyph
            transformation = Transform(*transformation).transform(self._inverted)

        super().addComponent(baseGlyph, transformation, identifier=identifier, **kwargs)
Ejemplo n.º 31
0
 def _getBounds(self, boundsAttr):
     layer = self.layer
     if layer is None:
         return None
     if self.baseGlyph not in layer:
         return None
     glyph = layer[self.baseGlyph]
     bounds = getattr(glyph, boundsAttr)
     if bounds is None:
         return None
     if self.transformation == _defaultTransformation:
         return bounds
     xMin, yMin, xMax, yMax = bounds
     t = Transform(*self.transformation)
     points = [(xMin, yMin), (xMax, yMax)]
     (xMin, yMin), (xMax, yMax) = t.transformPoints(points)
     return xMin, yMin, xMax, yMax
Ejemplo n.º 32
0
def _adjust_anchors(anchor_data, ufo, parent, component):
    """Adjust anchors to which a mark component may have been attached."""
    glyph = ufo[component.baseGlyph]
    t = Transform(*component.transformation)
    _componentAnchor = _componentAnchorFromLib(parent, component)
    for anchor in glyph.anchors:
        # adjust either if component is attached to a specific named anchor
        # (e.g. top_2 for a ligature glyph)
        # rather than to the standard anchors (top/bottom)
        if _componentAnchor and _componentAnchor in anchor_data:
            anchor_data[_componentAnchor] = t.transformPoint(
                (anchor.x, anchor.y))
        # ... or this anchor has data and the component also contains
        # the associated mark anchor (e.g. "_top" for "top") ...
        elif anchor.name in anchor_data and any(a.name == "_" + anchor.name
                                                for a in glyph.anchors):
            anchor_data[anchor.name] = t.transformPoint((anchor.x, anchor.y))
Ejemplo n.º 33
0
def get_anchor_data(anchor_data, ufo, components, anchor_name):
    """Get data for an anchor from a list of components."""

    anchors = []
    for component in components:
        for anchor in ufo[component.baseGlyph].anchors:
            if anchor.name == anchor_name:
                anchors.append((anchor, component))
                break
    if len(anchors) > 1:
        for i, (anchor, component) in enumerate(anchors):
            t = Transform(*component.transformation)
            name = '%s_%d' % (anchor.name, i + 1)
            anchor_data[name] = t.transformPoint((anchor.x, anchor.y))
    elif anchors:
        anchor, component = anchors[0]
        t = Transform(*component.transformation)
        anchor_data[anchor.name] = t.transformPoint((anchor.x, anchor.y))
Ejemplo n.º 34
0
 def addComponent(self, glyphName, transformation):
     self._outPen.addComponent(
         glyphName,
         Transform(
             *transformation[:4],
             self.roundFunc(transformation[4]),
             self.roundFunc(transformation[5]),
         ),
     )
Ejemplo n.º 35
0
 def translate(self, x, y=None, transformFrame=True):
     """Translate this shape by `x` and `y` (pixel values)."""
     if y is None:
         y = x
     img = self.img()
     if img:
         img["rect"] = img["rect"].offset(x, y)
     return self.transform(Transform(1, 0, 0, 1, x, y),
                           transformFrame=transformFrame)
Ejemplo n.º 36
0
def _flattenComponent(glyphSet, component):
    """Returns a list of tuples (baseGlyph, transform) of nested component."""

    glyph = glyphSet[component.baseGlyph]
    # Any contour will cause components to be decomposed
    if not glyph.components or len(glyph) > 0:
        transformation = Transform(*component.transformation)
        return [(component.baseGlyph, transformation)]

    all_flattened_components = []
    for nested in glyph.components:
        flattened_components = _flattenComponent(glyphSet, nested)
        for i, (name, tr) in enumerate(flattened_components):
            flat_tr = Transform(*component.transformation)
            flat_tr = flat_tr.translate(tr.dx, tr.dy)
            flat_tr = flat_tr.transform((tr.xx, tr.xy, tr.yx, tr.yy, 0, 0))
            flattened_components[i] = (name, flat_tr)
        all_flattened_components.extend(flattened_components)
    return all_flattened_components
Ejemplo n.º 37
0
    def decompose_glyphs(self, ufos, glyph_filter=lambda g: True):
        """Move components of UFOs' glyphs to their outlines."""

        for ufo in ufos:
            logger.info('Decomposing glyphs for ' + self._font_name(ufo))
            for glyph in ufo:
                if not glyph.components or not glyph_filter(glyph):
                    continue
                self._deep_copy_contours(ufo, glyph, glyph, Transform())
                glyph.clearComponents()
Ejemplo n.º 38
0
 def getGlyph(self, glyph, skew, rotation, addComponents=False):
     skew = radians(skew)
     rotation = radians(-rotation)
     
     dest = glyph.copy()
     if skew == 0 and rotation == 0:
         return dest
     for contour in dest:
         for bPoint in contour.bPoints:
             bcpIn = bPoint.bcpIn
             bcpOut = bPoint.bcpOut
             if bcpIn == (0, 0):
                 continue
             if bcpOut == (0, 0):
                 continue
             if bcpIn[0] == bcpOut[0] and bcpIn[1] != bcpOut[1]:
                 bPoint.anchorLabels = ["extremePoint"]
             if rotation and bcpIn[0] != bcpOut[0] and bcpIn[1] == bcpOut[1]:
                 bPoint.anchorLabels = ["extremePoint"]
     
     cx, cy = 0, 0
     box = dest.box
     if box:
         cx = box[0] + (box[2] - box[0]) * .5
         cy = box[1] + (box[3] - box[1]) * .5
         
     t = Transform()
     t = t.skew(skew)
     t = t.translate(cx, cy).rotate(rotation).translate(-cx, -cy)
     
     dest.transform(t)
     
     dest.extremePoints(round=0)
     for contour in dest:
         for point in contour.points:
             if "extremePoint" in point.labels:
                 point.selected = True
                 point.smooth = True
             else:
                 point.selected = False
     dest.removeSelection()
     dest.round() 
     return dest
Ejemplo n.º 39
0
 def addComponent(self, baseGlyphName, transformation, **kwargs):
     self._outPen.addComponent(
         baseGlyphName,
         Transform(
             *transformation[:4],
             self.roundFunc(transformation[4]),
             self.roundFunc(transformation[5]),
         ),
         **kwargs,
     )
Ejemplo n.º 40
0
 def _getBounds(self, boundsAttr):
     glyph = self.getParent()
     if glyph is None:
         return None
     font = glyph.getParent()
     if font is None:
         return None
     if self.baseGlyph not in font:
         return None
     glyph = font[self.baseGlyph]
     bounds = getattr(glyph, boundsAttr)
     if bounds is None:
         return None
     if self.transformation == _defaultTransformation:
         return bounds
     xMin, yMin, xMax, yMax = bounds
     t = Transform(*self.transformation)
     points = [(xMin, yMin), (xMax, yMax)]
     (xMin, yMin), (xMax, yMax) = t.transformPoints(points)
     return xMin, yMin, xMax, yMax
Ejemplo n.º 41
0
def propagate_anchors(ufo):
    """Copy anchors from parent glyphs' components to the parent."""

    from fontTools.misc.transform import Transform

    def get_anchor(glyph, name):
        return next((a for a in glyph.anchors if a.name == name), None)

    for parent in ufo:
        added_here = {}

        # don't propagate anchors for mark glyphs
        if any(a.name.startswith('_') for a in parent.anchors):
            continue

        # try to get anchors from base (first) components
        glyph = parent
        transformation = Transform()
        while glyph.components:
            component = glyph.components[0]
            glyph = ufo[component.baseGlyph]
            transformation = transformation.transform(component.transformation)
            for anchor in glyph.anchors:
                if get_anchor(parent, anchor.name) is None:
                    added_here[anchor.name] = transformation.transformPoint(
                        (anchor.x, anchor.y))

        # adjust anchors to which a mark has been attached
        for component in parent.components[1:]:
            glyph = ufo[component.baseGlyph]
            transformation = Transform(*component.transformation)
            for anchor in glyph.anchors:
                if (anchor.name in added_here and
                    get_anchor(glyph, '_' + anchor.name) is not None):
                    added_here[anchor.name] = transformation.transformPoint(
                        (anchor.x, anchor.y))

        for name, (x, y) in added_here.items():
            anchor_dict = {'name': name, 'x': x, 'y': y}
            parent.appendAnchor(glyph.anchorClass(anchorDict=anchor_dict))
Ejemplo n.º 42
0
def italicizeGlyph(f, g, angle=10, stemWidth=185):
    unic = g.unicode #save unicode

    glyph = f[g.name]
    slope = np.tanh(math.pi * angle / 180)

    # determine how far on the x axis the glyph should slide
    # to compensate for the slant. -600 is a magic number
    # that assumes a 2048 unit em square
    MEAN_YCENTER = -600
    m = Transform(1, 0, slope, 1, 0, 0)
    xoffset, junk = m.transformPoint((0, MEAN_YCENTER))
    m = Transform(.97, 0, slope, 1, xoffset, 0)
    
    if len(glyph) > 0:
        g2 = italicize(f[g.name], angle, xoffset=xoffset, stemWidth=stemWidth)
        f.insertGlyph(g2, g.name)
        
    transformFLGlyphMembers(f[g.name], m)

    if unic > 0xFFFF: #restore unicode
        g.unicode = unic
Ejemplo n.º 43
0
 def test_rotate(self):
     t = Transform()
     assert t.rotate(math.pi / 2) == Transform(0, 1, -1, 0, 0, 0)
     t = Transform()
     assert t.rotate(-math.pi / 2) == Transform(0, -1, 1, 0, 0, 0)
     t = Transform()
     assert tuple(t.rotate(math.radians(30))) == pytest.approx(
         tuple(Transform(0.866025, 0.5, -0.5, 0.866025, 0, 0)))
Ejemplo n.º 44
0
def transformationAtCenter(matrix, centerPoint):
    """Helper function for rotate(), scale() and skew() to apply a transformation
    with a specified center point.

        >>> transformationAtCenter((2, 0, 0, 2, 0, 0), (0, 0))
        (2, 0, 0, 2, 0, 0)
        >>> transformationAtCenter((2, 0, 0, 2, 0, 0), (100, 200))
        (2, 0, 0, 2, -100, -200)
        >>> transformationAtCenter((-2, 0, 0, 2, 0, 0), (100, 200))
        (-2, 0, 0, 2, 300, -200)
        >>> t = Transform(*transformationAtCenter((0, 1, 1, 0, 0, 0), (100, 200)))
        >>> t.transformPoint((100, 200))
        (100, 200)
        >>> t.transformPoint((0, 0))
        (-100, 100)
    """
    if centerPoint == (0, 0):
        return matrix
    t = Transform()
    cx, cy = centerPoint
    t = t.translate(cx, cy)
    t = t.transform(matrix)
    t = t.translate(-cx, -cy)
    return tuple(t)
Ejemplo n.º 45
0
 def test_toPS(self):
     t = Transform().scale(2, 3).translate(4, 5)
     assert t.toPS() == '[2 0 0 3 8 15]'
Ejemplo n.º 46
0
 def test_transformPoints(self):
     t = Transform(2, 0, 0, 3, 0, 0)
     assert t.transformPoints(
         [(0, 0), (0, 100), (100, 100), (100, 0)]
     ) == [(0, 0), (0, 300), (200, 300), (200, 0)]
def GlyphConstructionBuilder(construction, font):
    # create a construction glyph
    destination = ConstructionGlyph(font)
    # test if the input is a proper string
    try:
        construction = str(construction)
    except Exception:
        return destination
    # parse decomposing
    shouldDecompose, construction = parseShouldDecompose(construction)
    # parse the note
    destination.note, construction = parseNote(construction)
    # check if there is a = sing
    if glyphNameSplit not in construction:
        return destination
    # remove all spaces and tabs
    construction = removeSpacesAndTabs(construction)
    # escape math formulas inside a ` `
    construction = forceEscapingMathOperations(construction)
    # extract the name
    destination.name, construction = parseGlyphName(construction)
    # extract glyph attributes
    glyphAttributes, construction = parseGlyphattributes(construction, font)
    # split into base glyphs, ligatures
    baseGlyphs = construction.split(baseGlyphSplit)

    advanceWidth = 0
    previousBaseGlyph = None
    # start
    for baseGlyph in baseGlyphs:
        applyKerning, baseGlyph = parseApplyKerning(baseGlyph)
        # split into mark glyphs
        markGlyphs = baseGlyph.split(markGlyphSplit)
        baseGlyph = None
        baseMarkGlyph = None
        baseTransformMatrix = [1, 0, 0, 1, 0, 0]
        markTransformMap = {}

        advanceHeight = 0

        for markGlyph in markGlyphs:
            markGlyph = reEscapeMathOperations(markGlyph)
            component, transformMatrix = parsePositions(baseMarkGlyph, markGlyph, font, markTransformMap, advanceWidth, advanceHeight)

            baseMarkGlyph = component

            if baseGlyph is None:
                baseGlyph = component
                if applyKerning:
                    kern = kernValueForGlyphPair(font, (previousBaseGlyph, baseGlyph))
                    if kern:
                        t = Transform(*transformMatrix).translate(kern, 0)
                        transformMatrix = t[:]

                baseTransformMatrix = transformMatrix

            destination.addComponent(component, transformMatrix)
            markTransformMap[component] = transformMatrix

        if baseGlyph in font:
            width = font[baseGlyph].width
            t = Transform(*baseTransformMatrix)
            width, y = t.transformPoint((width - advanceWidth, 0))
            advanceWidth += width

        previousBaseGlyph = baseGlyph

    destination.width = advanceWidth
    for key, value in glyphAttributes.items():
        setattr(destination, key, value)
    if shouldDecompose:
        destination._shouldDecompose = True
    return destination
Ejemplo n.º 48
0
 def test_scale(self):
     t = Transform()
     assert t.scale(5) == Transform(5, 0, 0, 5, 0, 0)
     assert t.scale(5, 6) == Transform(5, 0, 0, 6, 0, 0)
Ejemplo n.º 49
0
 def test_inverse(self):
     t = Transform().translate(2, 3).scale(4, 5)
     assert t.transformPoint((10, 20)) == (42, 103)
     it = t.inverse()
     assert it.transformPoint((42, 103)) == (10.0, 20.0)
     assert Transform().inverse() == Transform()
Ejemplo n.º 50
0
def transform_bbox(bbox, matrix):
	t = Transform(*matrix)
	ll_x, ll_y = t.transformPoint((bbox[0], bbox[1]))
	tr_x, tr_y = t.transformPoint((bbox[2], bbox[3]))
	return normRect((ll_x, ll_y, tr_x, tr_y))
Ejemplo n.º 51
0
 def test_examples(self):
     t = Transform()
     assert repr(t) == "<Transform [1 0 0 1 0 0]>"
     assert t.scale(2) == Transform(2, 0, 0, 2, 0, 0)
     assert t.scale(2.5, 5.5) == Transform(2.5, 0, 0, 5.5, 0, 0)
     assert t.scale(2, 3).transformPoint((100, 100)) == (200, 300)
Ejemplo n.º 52
0
 def test_translate(self):
     t = Transform()
     assert t.translate(20, 30) == Transform(1, 0, 0, 1, 20, 30)
Ejemplo n.º 53
0
 def test_transform(self):
     t = Transform(2, 0, 0, 3, 1, 6)
     assert t.transform((4, 3, 2, 1, 5, 6)) == Transform(8, 9, 4, 3, 11, 24)
def parsePositions(baseGlyph, markGlyph, font, markTransformMap, advanceWidth, advanceHeight):
    xx, xy, yx, yy, x, y = 1, 0, 0, 1, advanceWidth, advanceHeight

    baseGlyphX = baseGlyphY = baseGlyph
    markFixedX = markFixedY = False

    flipX = flipY = False

    if positionSplit in markGlyph:
        markGlyph, position = markGlyph.split(positionSplit)

        if positionXYSplit in position:
            positions = position.split(positionXYSplit)
            if len(positions) == 6:
                xx, xy, yx, yy, positionX, positionY = positions
                xx = float(xx)
                xy = float(xy)
                yx = float(yx)
                yy = float(yy)
            elif len(positions) == 2:
                positionX, positionY = positions
            else:
                raise GlyphBuilderError("mark positions should have 6 or 2 options")
        else:
            positionX = positionY = position

        if positionBaseSplit in positionX:
            baseGlyphX, positionX = positionX.split(positionBaseSplit)

        if positionBaseSplit in positionY:
            baseGlyphY, positionY = positionY.split(positionBaseSplit)

        if flipMarkGlyphSplit in positionX:
            flipY = True
            positionX = positionX.replace(flipMarkGlyphSplit, "")

        if flipMarkGlyphSplit in positionY:
            flipX = True
            positionY = positionY.replace(flipMarkGlyphSplit, "")

        if positionX and positionY:
            baseX = baseY = 0
            markX = markY = 0

            if markGlyph not in font:
                if glyphSuffixSplit in markGlyph:
                    markGlyph = markGlyph.split(glyphSuffixSplit)[0]

            markPoint1, markAngle1, markFixedX = parsePosition(markGlyph, font, positionX, direction="x", prefix="_")
            markPoint2, markAngle2, markFixedY = parsePosition(markGlyph, font, positionY, direction="y", prefix="_")
            intersection = _intersectAngles(markPoint1, markAngle1, markPoint2, markAngle2)
            if intersection is not None:
                markX, markY = intersection

            if baseGlyphX in font and baseGlyphY in font:
                basePoint1, baseAngle1, _ = parsePosition(baseGlyphX, font, positionX, direction="x", isBase=True)
                basePoint2, baseAngle2, _ = parsePosition(baseGlyphY, font, positionY, direction="y", isBase=True)
                intersection = _intersectAngles(basePoint1, baseAngle1, basePoint2, baseAngle2)
                if intersection is not None:
                    baseX, baseY = intersection

            # calculate the offset
            if not markFixedX:
                x += baseX - markX
            else:
                x += markX

            if not markFixedY:
                y += baseY - markY
            else:
                y += markY

        if not markFixedX:
            baseTransform = markTransformMap.get(baseGlyphX)
            if baseTransform:
                x += baseTransform[4] - advanceWidth

        if not markFixedY:
            baseTransform = markTransformMap.get(baseGlyphY)
            if baseTransform:
                y += baseTransform[5] - advanceHeight

    transformMatrix = (xx, xy, yx, yy, x, y)

    if flipX:
        bounds = font[markGlyph].bounds
        if bounds:
            minx, miny, maxx, maxy = bounds
            bt = Transform(*transformMatrix)
            minx, miny = bt.transformPoint((minx, miny))
            maxx, maxy = bt.transformPoint((maxx, maxy))
            t = Transform()
            t = t.translate(0, miny)
            t = t.scale(1, -1)
            t = t.translate(0, -maxy)
            t = t.transform(bt)
            transformMatrix = t[:]

    if flipY:
        bounds = font[markGlyph].bounds
        if bounds:
            minx, miny, maxx, maxy = bounds
            bt = Transform(*transformMatrix)
            minx, miny = bt.transformPoint((minx, miny))
            maxx, maxy = bt.transformPoint((maxx, maxy))
            t = Transform()
            t = t.translate(minx, 0)
            t = t.scale(-1, 1)
            t = t.translate(-maxx, 0)
            t = t.transform(bt)
            transformMatrix = t[:]
    return markGlyph, transformMatrix