Exemplo n.º 1
0
    def test_record_and_replay(self):
        pen = RecordingPointPen()
        glyph = _TestGlyph()
        glyph.drawPoints(pen)
        pen.addComponent("a", (2, 0, 0, 2, -10, 5))

        assert pen.value == [
            ("beginPath", (), {
                "identifier": "abc"
            }),
            ("addPoint", ((0.0, 0.0), "line", False, "start"), {
                "identifier": "0000"
            }),
            ("addPoint", ((0.0, 100.0), "line", False, None), {
                "identifier": "0001"
            }),
            ("addPoint", ((50.0, 75.0), None, False, None), {
                "identifier": "0002"
            }),
            ("addPoint", ((60.0, 50.0), None, False, None), {
                "identifier": "0003"
            }),
            ("addPoint", ((50.0, 0.0), "curve", True, "last"), {
                "identifier": "0004"
            }),
            ("endPath", (), {}),
            ("addComponent", ("a", (2, 0, 0, 2, -10, 5)), {}),
        ]

        pen2 = RecordingPointPen()
        pen.replay(pen2)

        assert pen2.value == pen.value
Exemplo n.º 2
0
def test_getDrawToPointPen():
    ftf, ttfGlyphSet = _getFonts("IBMPlexSans-Regular.ttf")
    for glyphName in ["a", "B", "O", "period"]:
        refPen = RecordingPointPen()
        ttfGlyphSet[glyphName].drawPoints(refPen)
        pen = RecordingPointPen()
        ftf.drawGlyphToPointPen(glyphName, pen)
        assert pen.value == refPen.value
Exemplo n.º 3
0
def test_getUpdateInfo(tmpdir):
    ufoSource = getFontPath("MutatorSansBoldWideMutated.ufo")
    ufoPath = shutil.copytree(ufoSource, tmpdir / "test.ufo")
    reader = UFOReader(ufoPath, validate=False)
    glyphSet = reader.getGlyphSet()
    cmap, unicodes, anchors = fetchCharacterMappingAndAnchors(glyphSet, ufoPath)

    state = UFOState(reader, glyphSet, getUnicodesAndAnchors=lambda: (unicodes, anchors))

    feaPath = pathlib.Path(reader.fs.getsyspath("/features.fea"))
    feaPath.touch()

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert needsFeaturesUpdate
    assert not needsGlyphUpdate
    assert not needsInfoUpdate
    assert not needsCmapUpdate

    infoPath = pathlib.Path(reader.fs.getsyspath("/fontinfo.plist"))
    infoPath.touch()

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert not needsFeaturesUpdate
    assert not needsGlyphUpdate
    assert needsInfoUpdate
    assert not needsCmapUpdate

    glyph = Glyph("A", None)
    ppen = RecordingPointPen()
    glyphSet.readGlyph("A", glyph, ppen)
    glyph.anchors[0]["x"] = 123
    glyphSet.writeGlyph("A", glyph, ppen.replay)

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert needsFeaturesUpdate
    assert needsGlyphUpdate
    assert not needsInfoUpdate
    assert not needsCmapUpdate

    glyph = Glyph("A", None)
    ppen = RecordingPointPen()
    glyphSet.readGlyph("A", glyph, ppen)
    glyph.unicodes = [123]
    glyphSet.writeGlyph("A", glyph, ppen.replay)

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert not needsFeaturesUpdate
    assert needsGlyphUpdate
    assert not needsInfoUpdate
    assert needsCmapUpdate
Exemplo n.º 4
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 = RecordingPointPen()
        glyph.drawPoints(rec)
        glyph.clearContours()
        glyph.clearComponents()

        outpen = glyph.getPointPen()
        filterpen = TransformPointPen(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
Exemplo n.º 5
0
def scaleGlyph(font, glyph, scale):
    """Scales the glyph, but keeps it centered around its original bounding
    box."""
    from fontTools.pens.recordingPen import RecordingPointPen
    from fontTools.pens.transformPen import TransformPointPen
    from fontTools.misc.transform import Identity

    width = glyph.width
    bbox = glyph.getBounds(font)
    x = (bbox.xMin + bbox.xMax) / 2
    y = (bbox.yMin + bbox.yMax) / 2
    matrix = Identity
    matrix = matrix.translate(-x * scale + x, -y * scale + y)
    matrix = matrix.scale(scale)

    rec = RecordingPointPen()
    glyph.drawPoints(rec)
    glyph.clearContours()
    glyph.clearComponents()

    pen = TransformPointPen(glyph.getPointPen(), matrix)
    rec.replay(pen)

    if width == 0:
        glyph.width = width

    return matrix
Exemplo n.º 6
0
def checkGlyphAlternates(project):
    """Check whether alternate glyphs have base glyphs, and whether they are
    different from the base glyph.
    """
    glyphSet = project.characterGlyphGlyphSet
    glyphNames = sorted(glyphSet.getGlyphNamesAndUnicodes())
    for baseName, altNames in groupby(glyphNames, key=lambda gn: gn.split(".")[0]):
        altNames = list(altNames)
        if len(altNames) == 1:
            continue
        glyphs = [glyphSet.getGlyph(glyphName) for glyphName in altNames]
        locations = set()
        for g in glyphs:
            locations.update(tuplifyLocation(vg.location) for vg in g.variations)
        locations = [dict(loc) for loc in sorted(locations)]
        locations.insert(0, {})

        for loc in locations:
            outlines = defaultdict(list)
            for g in glyphs:
                rpen = RecordingPointPen()
                try:
                    project.drawPointsCharacterGlyph(g.name, loc, rpen)
                except InterpolationError as e:
                    yield f"Skipping '{g.name}' {e}"
                else:
                    outlines[tuplifyOutline(rpen.value)].append(g.name)
            for sameNames in outlines.values():
                if len(sameNames) > 1:
                    sameNames = [f"'{n}'" for n in sameNames]
                    sameNames = ", ".join(sameNames[:-1]) + " and " + sameNames[-1]
                    yield (
                        f"Glyphs {sameNames} are identical "
                        f"at location {formatLocation(loc)}"
                    )
Exemplo n.º 7
0
 def test_bit6_draw_to_pointpen(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 = RecordingPointPen()
     glyfTable["glyph00003"].drawPoints(pen, glyfTable=glyfTable)
     expected = [
         ('beginPath', (), {}),
         ('addPoint', ((501, 1430), 'line', False, None), {}),
         ('addPoint', ((683, 1430), 'line', False, None), {}),
         ('addPoint', ((1172, 0), 'line', False, None), {}),
         ('addPoint', ((983, 0), 'line', False, None), {}),
     ]
     self.assertEqual(pen.value[:len(expected)], expected)
Exemplo n.º 8
0
    def test_read_ensure_x_y(self):
        """Ensure that a proper GlifLibError is raised when point coordinates are
		missing, regardless of validation setting."""

        s = """<?xml version='1.0' encoding='utf-8'?>
		<glyph name="A" format="2">
			<outline>
				<contour>
					<point x="545" y="0" type="line"/>
					<point x="638" type="line"/>
				</contour>
			</outline>
		</glyph>
		"""
        pen = RecordingPointPen()

        with pytest.raises(GlifLibError, match="Required y attribute"):
            readGlyphFromString(s, _Glyph(), pen)

        with pytest.raises(GlifLibError, match="Required y attribute"):
            readGlyphFromString(s, _Glyph(), pen, validate=False)
Exemplo n.º 9
0
path = BezierPath()
path.moveTo((100, 100))
path.curveTo((200, 100), (300, 200), (300, 300))
path.lineTo((100, 300))
path.closePath()
path.oval(0, 0, 200, 90)
path.moveTo((250, 250))
path.arc((250, 250), 200, 0, 120, False)
# path.skew() will trigger bad results
# https://github.com/justvanrossum/drawbot-skia/issues/7
# path.skew(10, 20)

fill(None)
stroke(0)
strokeWidth(2)
drawPath(path)

pen = RecordingPen()
path.drawToPen(pen)

path = BezierPath()
pen.replay(path)

stroke(None)
fill(0, 0.3)
drawPath(path)

ppen = RecordingPointPen()
path.drawToPointPen(ppen)