Exemple #1
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
Exemple #2
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
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
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))
Exemple #5
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))
Exemple #6
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))
Exemple #7
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))
Exemple #8
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))
Exemple #9
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))
Exemple #10
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))
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))
Exemple #12
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)
Exemple #13
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
Exemple #14
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
Exemple #15
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
Exemple #16
0
    def outline(self, transform=None, evenOdd=False):
        """Converts the current contours to ``FT_Outline``.

        Args:
            transform: An optional 6-tuple containing an affine transformation,
                or a ``Transform`` object from the ``fontTools.misc.transform``
                module.
            evenOdd: Pass ``True`` for even-odd fill instead of non-zero.
        """
        transform = transform or Transform()
        if not hasattr(transform, "transformPoint"):
            transform = Transform(*transform)
        n_contours = len(self.contours)
        n_points = sum((len(contour.points) for contour in self.contours))
        points = []
        for contour in self.contours:
            for point in contour.points:
                point = transform.transformPoint(point)
                points.append(
                    FT_Vector(FT_Pos(otRound(point[0] * 64)),
                              FT_Pos(otRound(point[1] * 64))))
        tags = []
        for contour in self.contours:
            for tag in contour.tags:
                tags.append(tag)
        contours = []
        contours_sum = 0
        for contour in self.contours:
            contours_sum += len(contour.points)
            contours.append(contours_sum - 1)
        flags = FT_OUTLINE_EVEN_ODD_FILL if evenOdd else FT_OUTLINE_NONE
        return FT_Outline(
            (ctypes.c_short)(n_contours),
            (ctypes.c_short)(n_points),
            (FT_Vector * n_points)(*points),
            (ctypes.c_ubyte * n_points)(*tags),
            (ctypes.c_short * n_contours)(*contours),
            (ctypes.c_int)(flags),
        )
Exemple #17
0
 def _draw_nib_face(self, pt):
     if self.trace:
         x, y = pt
         nib = []
         t = Transform().translate(x, y).rotate(self.angle)
         for seg in self.nib_drawing_path:
             seg_path = []
             for p in seg:
                 seg_path.append(t.transformPoint(p))
             nib.append(seg_path)
         self.path.append(nib)
     else:
         save()
         translate(pt[0], pt[1])
         rotate(degrees(self.angle))
         newPath()
         moveTo(self.nib_face_path[0])
         for p in self.nib_face_path[1:]:
             lineTo(p)
         closePath()
         drawPath()
         restore()
Exemple #18
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:
        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
Exemple #19
0
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:
            flipX = True
            positionX = positionX.replace(flipMarkGlyphSplit, "")

        if flipMarkGlyphSplit in positionY:
            flipY = 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
Exemple #20
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()
def GlyphConstructionBuilder(construction, font, characterMap=None):
    # 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)

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

        previousBaseGlyph = baseGlyph

    destination.width = advanceWidth
    for key, value in glyphAttributes.items():
        setattr(destination, key, value)

    if characterMap and destination.name in characterMap:
        destination.unicodes = [characterMap[destination.name]]

    if shouldDecompose:
        destination._shouldDecompose = True
    return destination
Exemple #22
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))
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))
Exemple #24
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()
Exemple #25
0
    def buffer(self,
               width=None,
               height=None,
               transform=None,
               contain=False,
               evenOdd=False):
        """Renders the current contours within a bitmap buffer.

        Args:
            width: Image width of the bitmap in pixels. If omitted, it
                automatically fits to the bounding box of the contours.
            height: Image height of the bitmap in pixels. If omitted, it
                automatically fits to the bounding box of the contours.
            transform: An optional 6-tuple containing an affine transformation,
                or a ``Transform`` object from the ``fontTools.misc.transform``
                module. The bitmap size is not affected by this matrix.
            contain: If ``True``, the image size will be automatically expanded
                so that it fits to the bounding box of the paths. Useful for
                rendering glyphs with negative sidebearings without clipping.
            evenOdd: Pass ``True`` for even-odd fill instead of non-zero.

        Returns:
            A tuple of ``(buffer, size)``, where ``buffer`` is a ``bytes``
            object of the resulted bitmap and ``size`` is a 2-tuple of its
            dimension.

        :Notes:
            The image size should always be given explicitly if you need to get
            a proper glyph image. When ``width`` and ``height`` are omitted, it
            forcifully fits to the bounding box and the side bearings get
            cropped. If you pass ``0`` to both ``width`` and ``height`` and set
            ``contain`` to ``True``, it expands to the bounding box while
            maintaining the origin of the contours, meaning that LSB will be
            maintained but RSB won’t. The difference between the two becomes
            more obvious when rotate or skew transformation is applied.

        :Example:
            .. code-block::

                >> pen = FreeTypePen(None)
                >> glyph.draw(pen)
                >> buf, size = pen.buffer(width=500, height=1000)
                >> type(buf), len(buf), size
                (<class 'bytes'>, 500000, (500, 1000))

        """
        transform = transform or Transform()
        if not hasattr(transform, "transformPoint"):
            transform = Transform(*transform)
        contain_x, contain_y = contain or width is None, contain or height is None
        if contain_x or contain_y:
            dx, dy = transform.dx, transform.dy
            bbox = self.bbox
            p1, p2, p3, p4 = (
                transform.transformPoint((bbox[0], bbox[1])),
                transform.transformPoint((bbox[2], bbox[1])),
                transform.transformPoint((bbox[0], bbox[3])),
                transform.transformPoint((bbox[2], bbox[3])),
            )
            px, py = (p1[0], p2[0], p3[0], p4[0]), (p1[1], p2[1], p3[1], p4[1])
            if contain_x:
                if width is None:
                    dx = dx - min(*px)
                    width = max(*px) - min(*px)
                else:
                    dx = dx - min(min(*px), 0.0)
                    width = max(width, max(*px) - min(min(*px), 0.0))
            if contain_y:
                if height is None:
                    dy = dy - min(*py)
                    height = max(*py) - min(*py)
                else:
                    dy = dy - min(min(*py), 0.0)
                    height = max(height, max(*py) - min(min(*py), 0.0))
            transform = Transform(*transform[:4], dx, dy)
        width, height = math.ceil(width), math.ceil(height)
        buf = ctypes.create_string_buffer(width * height)
        bitmap = FT_Bitmap(
            (ctypes.c_int)(height),
            (ctypes.c_int)(width),
            (ctypes.c_int)(width),
            (ctypes.POINTER(ctypes.c_ubyte))(buf),
            (ctypes.c_short)(256),
            (ctypes.c_ubyte)(FT_PIXEL_MODE_GRAY),
            (ctypes.c_char)(0),
            (ctypes.c_void_p)(None),
        )
        outline = self.outline(transform=transform, evenOdd=evenOdd)
        err = FT_Outline_Get_Bitmap(freetype.get_handle(),
                                    ctypes.byref(outline),
                                    ctypes.byref(bitmap))
        if err != 0:
            raise FT_Exception(err)
        return buf.raw, (width, height)
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
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