Beispiel #1
0
def calculate_pathop(pen1, pen2, operation):
    if USE_SKIA_PATHOPS:
        p1 = Path()
        pen1.replay(p1.getPen())
        if operation == BooleanOp.Simplify:
            # ignore pen2
            p1.simplify(fix_winding=True, keep_starting_points=True)
            d0 = RecordingPen()
            p1.draw(d0)
            return d0.value
        if pen2:
            p2 = Path()
            pen2.replay(p2.getPen())
        builder = OpBuilder(fix_winding=True, keep_starting_points=True)
        builder.add(p1, PathOp.UNION)
        if pen2:
            builder.add(p2, BooleanOp.Skia(operation))
        result = builder.resolve()
        d0 = RecordingPen()
        result.draw(d0)
        return d0.value
    else:
        bg2 = BooleanGlyph()
        if pen2:
            pen2.replay(bg2.getPen())
        bg = BooleanGlyph()
        pen1.replay(bg.getPen())
        bg = bg._booleanMath(BooleanOp.BooleanGlyphMethod(operation), bg2)
        dp = RecordingPen()
        bg.draw(dp)
        return dp.value
Beispiel #2
0
    def filter(self, glyph):
        matrix = self.context.matrix
        if matrix == Identity or not (glyph or glyph.components
                                      or glyph.anchors):
            return False  # nothing to do

        modified = self.context.modified
        glyphSet = self.context.glyphSet
        for component in glyph.components:
            base_name = component.baseGlyph
            if base_name in modified:
                continue
            base_glyph = glyphSet[base_name]
            if self.include(base_glyph) and self.filter(base_glyph):
                # base glyph is included but was not transformed yet; we
                # call filter recursively until all the included bases are
                # transformed, or there are no more components
                modified.add(base_name)

        rec = RecordingPen()
        glyph.draw(rec)
        glyph.clearContours()
        glyph.clearComponents()

        outpen = glyph.getPen()
        filterpen = TransformPen(outpen, matrix, modified)
        rec.replay(filterpen)

        # anchors are not drawn through the pen API,
        # must be transformed separately
        for a in glyph.anchors:
            a.x, a.y = matrix.transformPoint((a.x, a.y))

        return True
Beispiel #3
0
def test_rules_are_applied_deterministically(data_dir):
    """Test that a combination of designspace rules that end up mapping
    serveral input glyphs to the same destination glyph result in a correct and
    deterministic series of glyph swaps.

    The example is a font with 2 Q designs that depend on a style axis
        style < 0.5: Q        style >= 0.5: Q.ss01
    and each Q also has an alternative shape in bolder weights (like Skia)
        weight < 780: Q       weight >= 780: Q.alt
        weight < 730: Q.ss01  weight >= 730: Q.ss01.alt

    Then we generate an instance at style = 1, weight = 900. From the rules,
    the default CMAP entry for Q should have the outlines of Q.ss01.alt from
    the black UFO.
    """
    doc = designspaceLib.DesignSpaceDocument.fromfile(
        data_dir / "DesignspaceRuleOrder" / "MyFont.designspace")
    instanciator = fontmake.instantiator.Instantiator.from_designspace(doc)
    instance = instanciator.generate_instance(doc.instances[0])
    pen = RecordingPen()
    instance["Q"].draw(pen)
    instance_recording = pen.value

    black_ufo = ufoLib2.Font.open(data_dir / "DesignspaceRuleOrder" /
                                  "MyFont_Black.ufo")
    pen = RecordingPen()
    black_ufo["Q.ss01.alt"].draw(pen)
    black_ufo_recording = pen.value

    assert instance_recording == black_ufo_recording
Beispiel #4
0
def test_equivalent_paths(pathdef1, pathdef2):
    pen1 = RecordingPen()
    parse_path(pathdef1, pen1)

    pen2 = RecordingPen()
    parse_path(pathdef2, pen2)

    assert pen1.value == pen2.value
Beispiel #5
0
def test_getDrawToPen():
    ftf, ttfGlyphSet = _getFonts("IBMPlexSans-Regular.ttf")
    for glyphName in ["a", "B", "O", "period"]:
        refPen = RecordingPen()
        ttfGlyphSet[glyphName].draw(refPen)
        pen = RecordingPen()
        ftf.drawGlyphToPen(glyphName, pen)
        assert pen.value == refPen.value
Beispiel #6
0
 def test_draw_vs_drawpoints(self):
     font = TTFont(sfntVersion="\x00\x01\x00\x00")
     font.importXML(GLYF_TTX)
     glyfTable = font['glyf']
     pen1 = RecordingPen()
     pen2 = RecordingPen()
     glyfTable["glyph00003"].draw(pen1, glyfTable)
     glyfTable["glyph00003"].drawPoints(PointToSegmentPen(pen2), glyfTable)
     self.assertEqual(pen1.value, pen2.value)
Beispiel #7
0
def spikeGlyph(aGlyph, segmentLength=20, spikeLength=40, patternFunc=None):
    from fontTools.pens.recordingPen import RecordingPen
    recorder = RecordingPen()
    spikePen = SpikePen(recorder, spikeLength=spikeLength, patternFunc=patternFunc)
    filterPen = FlattenPen(spikePen, approximateSegmentLength=segmentLength, segmentLines=True)
    aGlyph.draw(filterPen)
    aGlyph.clear()
    recorder.replay(aGlyph.getPen())
    return aGlyph
Beispiel #8
0
def makeShadow(g, extrusionX, extrusionY):
    destPen = RecordingPen()
    myPen = TranslationPen(destPen)
    g.draw(myPen)
    destPen.replay(g.getPen())
    if g.rightMargin%2==0:
        g.rightMargin+=int(extrusionX-20) #20 is compensation for frontWidth in the TranslationPen constructor
    else:
        g.rightMargin+=int(extrusionX-19)
    g.changed()
def thresholdGlyph(aGlyph, threshold=10):
    """
    Convenience function that applies the **ThresholdPen** to a glyph in place.
    """
    from fontTools.pens.recordingPen import RecordingPen
    recorder = RecordingPen()
    filterpen = ThresholdPen(recorder, threshold)
    aGlyph.draw(filterpen)
    aGlyph.clear()
    recorder.replay(aGlyph.getPen())
    return aGlyph
def thresholdGlyph(aGlyph, threshold=10):
    """
    Convenience function that applies the **ThresholdPen** to a glyph in place.
    """
    from fontTools.pens.recordingPen import RecordingPen
    recorder = RecordingPen()
    filterpen = ThresholdPen(recorder, threshold)
    aGlyph.draw(filterpen)
    aGlyph.clear()
    recorder.replay(aGlyph.getPen())
    return aGlyph
Beispiel #11
0
 def explode(self):
     """Read each contour into its own DATPen; returns a DATPens"""
     dp = RecordingPen()
     ep = ExplodingPen(dp)
     self.replay(ep)
     dps = self.multi_pen_class()
     for p in ep._pens:
         dp = type(self)()
         dp.value = p
         dp.attrs = deepcopy(self.attrs)
         dps.append(dp)
     return dps
Beispiel #12
0
def flattenGlyph(aGlyph, threshold=10, segmentLines=True):
    """
    Convenience function that applies the **FlattenPen** pen to a glyph in place.
    """
    if len(aGlyph) == 0:
        return aGlyph
    from fontTools.pens.recordingPen import RecordingPen
    recorder = RecordingPen()
    filterpen = FlattenPen(recorder, approximateSegmentLength=threshold, segmentLines=segmentLines)
    aGlyph.draw(filterpen)
    aGlyph.clear()
    recorder.replay(aGlyph.getPen())
    return aGlyph
def samplingGlyph(aGlyph, steps=10):
    """
    Convenience function that applies the **SamplingPen** pen to a glyph in place.
    """
    if len(aGlyph) == 0:
        return aGlyph
    from fontTools.pens.recordingPen import RecordingPen
    recorder = RecordingPen()
    filterpen = SamplingPen(recorder, steps=steps)
    aGlyph.draw(filterpen)
    aGlyph.clear()
    recorder.replay(aGlyph.getPen())
    return aGlyph
Beispiel #14
0
def samplingGlyph(aGlyph, steps=10):
    """
    Convenience function that applies the **SamplingPen** pen to a glyph in place.
    """
    if len(aGlyph) == 0:
        return aGlyph
    from fontTools.pens.recordingPen import RecordingPen
    recorder = RecordingPen()
    filterpen = SamplingPen(recorder, steps=steps)
    aGlyph.draw(filterpen)
    aGlyph.clear()
    recorder.replay(aGlyph.getPen())
    return aGlyph
Beispiel #15
0
 def explode(self, into_set=False):
     """Read each contour into its own DATPen (or DATPenSet if `into_set` is True); returns a DATPenSet"""
     dp = RecordingPen()
     ep = ExplodingPen(dp)
     self.replay(ep)
     dps = DATPenSet()
     for p in ep.pens:
         dp = DATPen()
         dp.value = p
         dp.attrs = deepcopy(self.attrs)
         if into_set:
             dps.append(DATPenSet([dp]))
         else:
             dps.append(dp)
     return dps
Beispiel #16
0
def post():
    phrase = request.form['data']
    logger.info('got post request from app: phrase = "{}"'.format(phrase))
    seq = get_model_output(phrase)
    logger.info('receieved model output')
    paths = []

    shape = shape_dict.get(seq[0], 0)
    if shape:
        # TODO: 入れ子の考慮
        seq = seq[1:(3 if shape not in {3, 4} else 4)]

    for char in seq:
        recording_pen = RecordingPen()
        glyph = get_glyph(glyph_set, cmap, char)
        if glyph:
            glyph.draw(recording_pen)
            paths.append(recording_pen.value)

    logger.info('return kanji path data to app')
    return jsonify({
        "shape": shape,
        "paths": {i: {
            "path": path
        }
                  for i, path in enumerate(paths)}
    })
def test_reverse_point_pen(contour, expected):
    try:
        from ufoLib.pointPen import (ReverseContourPointPen, PointToSegmentPen,
                                     SegmentToPointPen)
    except ImportError:
        pytest.skip("ufoLib not installed")

    recpen = RecordingPen()
    pt2seg = PointToSegmentPen(recpen, outputImpliedClosingLine=True)
    revpen = ReverseContourPointPen(pt2seg)
    seg2pt = SegmentToPointPen(revpen)
    for operator, operands in contour:
        getattr(seg2pt, operator)(*operands)

    # for closed contours that have a lineTo following the moveTo,
    # and whose points don't overlap, our current implementation diverges
    # from the ReverseContourPointPen as wrapped by ufoLib's pen converters.
    # In the latter case, an extra lineTo is added because of
    # outputImpliedClosingLine=True. This is redundant but not incorrect,
    # as the number of points is the same in both.
    if (contour and contour[-1][0] == "closePath" and contour[1][0] == "lineTo"
            and contour[1][1] != contour[0][1]):
        expected = expected[:-1] + [("lineTo", contour[0][1])] + expected[-1:]

    assert recpen.value == expected
Beispiel #18
0
 def addSmoothPoints(self, length=100):
     """WIP"""
     rp = RecordingPen()
     fp = SmoothPointsPen(rp)
     self.replay(fp)
     self.value = rp.value
     return self
Beispiel #19
0
 def _build_CFF_contour_list(self):
     if self._contourlist is None:
         pen = RecordingPen()
         self.naked().draw(pen)
         contours = pen.value
         lastcontour = []
         self._contourlist = []
         startPt = (0, 0)
         lastPt = (0, 0)
         index = 0
         for c in contours:
             if c[0] == "moveTo":
                 startPt = c[1][0]
             elif c[0] == "closePath":
                 if startPt != lastPt:
                     lastcontour.append(
                         defcon.Point(startPt, segmentType="line"))
                 contour = self.contourClass(wrap=lastcontour, index=index)
                 self._contourlist.append(contour)
                 index = index + 1
                 lastcontour = []
             elif c[0] == "curveTo":
                 lastcontour.append(
                     defcon.Point(c[1][0], segmentType="offcurve"))
                 lastcontour.append(
                     defcon.Point(c[1][1], segmentType="offcurve"))
                 lastcontour.append(
                     defcon.Point(c[1][2], segmentType="curve"))
                 lastPt = c[1][2]
             elif c[0] == "lineTo":
                 lastcontour.append(
                     defcon.Point(c[1][0], segmentType="line"))
                 lastPt = c[1][0]
             elif c[0] == "qCurveTo":
                 self.raiseNotImplementedError()
Beispiel #20
0
 def test_bit6_draw_to_pen_issue1771(self):
     # https://github.com/fonttools/fonttools/issues/1771
     font = TTFont(sfntVersion="\x00\x01\x00\x00")
     # glyph00003 contains a bit 6 flag on the first point,
     # which triggered the issue
     font.importXML(GLYF_TTX)
     glyfTable = font['glyf']
     pen = RecordingPen()
     glyfTable["glyph00003"].draw(pen, glyfTable=glyfTable)
     expected = [('moveTo', ((501, 1430),)),
                 ('lineTo', ((683, 1430),)),
                 ('lineTo', ((1172, 0),)),
                 ('lineTo', ((983, 0),)),
                 ('lineTo', ((591, 1193),)),
                 ('lineTo', ((199, 0),)),
                 ('lineTo', ((12, 0),)),
                 ('lineTo', ((501, 1430),)),
                 ('closePath', ()),
                 ('moveTo', ((249, 514),)),
                 ('lineTo', ((935, 514),)),
                 ('lineTo', ((935, 352),)),
                 ('lineTo', ((249, 352),)),
                 ('lineTo', ((249, 514),)),
                 ('closePath', ())]
     self.assertEqual(pen.value, expected)
def traceFont(font, char):
    glyphSet = font.getGlyphSet()
    cmap = font.getBestCmap()
    glyph = getGlyph(glyphSet, cmap, char)
    recordingPen = RecordingPen()
    glyph.draw(recordingPen)
    return recordingPen.value
Beispiel #22
0
 def test_draw(self):
     from fontTools.pens.recordingPen import RecordingPen
     component = self.getComponent_generic()
     component.transformation = (1, 2, 3, 4, 5, 6)
     pen = RecordingPen()
     component.draw(pen)
     expected = [('addComponent', ('A', (1.0, 2.0, 3.0, 4.0, 5.0, 6.0)))]
     self.assertEqual(pen.value, expected)
Beispiel #23
0
 def __init__(self, g, inc=0.0015):
     if isinstance(g, RecordingPen):
         self.pen = g
     else:
         self.pen = RecordingPen()
         g.draw(self.pen)
     self.inc = inc
     self.length = self.calcCurveLength()
Beispiel #24
0
 def test_pen_closePath(self):
     # Test CFF2/T2 charstring: it does NOT end in "endchar"
     # https://github.com/fonttools/fonttools/issues/2455
     cs = self.stringToT2CharString(
         "100 100 rmoveto -50 -150 200 0 -50 150 rrcurveto")
     pen = RecordingPen()
     cs.draw(pen)
     self.assertEqual(pen.value[-1], ('closePath', ()))
Beispiel #25
0
 def Record(recording, offset=1):
     op = OutlinePen(None, offset=offset, optimizeCurve=True)
     replayRecording(recording.value, op)
     op.drawSettings(drawInner=True, drawOuter=True)
     g = op.getGlyph()
     rp2 = RecordingPen()
     g.draw(rp2)
     return rp2
Beispiel #26
0
def generate_glyph_image(font):
    for index, label in enumerate(LABELS):
        bitmap_output_path = path.join(BITMAP_DIR,
                                       str(index) + '_' + label,
                                       font['post_script_name'] + ".png")
        if path.exists(bitmap_output_path):
            continue

        # bitmap
        canvas = Image.new("RGB", (IMAGE_WIDTH, IMAGE_HEIGHT), "black")
        draw = ImageDraw.Draw(canvas)
        ifont = ImageFont.truetype(font['path'], IMAGE_WIDTH - 10)
        w, h = draw.textsize(label, font=ifont)
        draw.text(((IMAGE_WIDTH - w) / 2, (IMAGE_HEIGHT - h) / 2),
                  label,
                  font=ifont,
                  fill="white")
        canvas.save(bitmap_output_path)

    # vector
    vector_output_path = path.join(PREPROCESSED_DIR,
                                   font['post_script_name'] + '.ttx')
    if path.exists(vector_output_path):
        return
    ttfont = TTFont(font['path'])
    glyph_set = ttfont.getGlyphSet()
    cmap = ttfont.getBestCmap()
    ttfont.saveXML(vector_output_path)
    ascender = ttfont['OS/2'].sTypoAscender
    descender = ttfont['OS/2'].sTypoDescender
    height = ascender - descender

    for index, label in enumerate(LABELS):
        glyph_name = cmap[ord(label)]
        glyph = glyph_set[glyph_name]
        width = glyph.width
        pen = RecordingPen()
        glyph.draw(pen)

        # [[x, y, isPenDown, isControlPoint, isContourEnd, isGlyphEnd], ...]
        matrix = []
        for command in pen.value:
            name = command[0]
            points = command[1]
            print('name:', name)
            print('points:', points)
            # if name == 'closePath':
            #     pass
            # if name == 'moveTo':
            #     matrix.append((points[0][0], points[0][1], 0, 0, 0, 0))
            # elif name == 'qCurveTo':
            #     matrix.append((points[0][0], points[0][1], 1, 1, 0, 0))
            #     matrix.append((points[1][0], points[1][1], 1, 0, 0, 0))
            # elif name == 'lineTo':
            #     matrix.append((points[1][0], points[1][1], 1, 0, 0, 0))

        os.exit()
Beispiel #27
0
 def _addOutlinePathToGlyph(self, glyph):
     if self.cocoa:
         pen = CocoaPen(self.glyphSet)
         glyph.draw(pen)
         glyph.outline = pen.path
     else:
         pen = RecordingPen()
         glyph.draw(pen)
         glyph.outline = pen
Beispiel #28
0
 def getOutline(self, cocoa=True):
     if cocoa:
         pen = CocoaPen(None)  # by now there are no more composites
         self.draw(pen)
         return pen.path
     else:
         pen = RecordingPen()
         self.draw(pen)
         return pen
Beispiel #29
0
 def transform(self, transform, transformFrame=True):
     """Perform an arbitrary transformation on the pen, using the fontTools `Transform` class."""
     op = RecordingPen()
     tp = TransformPen(op, transform)
     self.replay(tp)
     self.value = op.value
     if transformFrame and self.frame:
         self.frame = self.frame.transform(transform)
     return self
Beispiel #30
0
 def getOutline(self, cocoa=True):
     if cocoa:
         return makePathFromArrays(self.getPoints(), self.tags,
                                   self.contours)
     else:
         #print(self.tags)
         rp = RecordingPen()
         self.draw(rp)
         return rp
Beispiel #31
0
    def test_from_svg_file(self):
        pen = RecordingPen()
        with NamedTemporaryFile(delete=False) as tmp:
            tmp.write(tobytes(SVG_DATA))
        try:
            svg = SVGPath(tmp.name)
            svg.draw(pen)
        finally:
            os.remove(tmp.name)

        assert pen.value == EXPECTED_PEN_COMMANDS
Beispiel #32
0
def test_exponents():
    # It can be e or E, the plus is optional, and a minimum of +/-3.4e38 must be supported.
    pen = RecordingPen()
    parse_path("M-3.4e38 3.4E+38L-3.4E-38,3.4e-38", pen)
    expected = [
        ("moveTo", ((-3.4e+38, 3.4e+38), )),
        ("lineTo", ((-3.4e-38, 3.4e-38), )),
        ("endPath", ()),
    ]

    assert pen.value == expected
 def test_addComponent(self):
     pen = RecordingPen()
     pen.addComponent("a", (2, 0, 0, 3, -10, 5))
     assert pen.value == [("addComponent", ("a", (2, 0, 0, 3, -10, 5)))]