Beispiel #1
0
    def test_ignore_single_points(self):
        pen = DummyPen()
        try:
            logging.captureWarnings(True)
            with CapturingLogHandler("py.warnings", level="WARNING") as log:
                quadpen = Cu2QuPen(pen, MAX_ERR, ignore_single_points=True)
        finally:
            logging.captureWarnings(False)
        quadpen.moveTo((0, 0))
        quadpen.endPath()
        quadpen.moveTo((1, 1))
        quadpen.closePath()

        self.assertGreaterEqual(len(log.records), 1)
        self.assertIn("ignore_single_points is deprecated",
                      log.records[0].args[0])

        # single-point contours were ignored, so the pen commands are empty
        self.assertFalse(pen.commands)

        # redraw without ignoring single points
        quadpen.ignore_single_points = False
        quadpen.moveTo((0, 0))
        quadpen.endPath()
        quadpen.moveTo((1, 1))
        quadpen.closePath()

        self.assertTrue(pen.commands)
        self.assertEqual(str(pen).splitlines(), [
            "pen.moveTo((0, 0))",
            "pen.endPath()",
            "pen.moveTo((1, 1))",
            "pen.closePath()"
        ])
Beispiel #2
0
    def setupTable_glyf(self):
        """Make the glyf table."""

        allGlyphs = self.allGlyphs
        if self.convertCubics:
            from cu2qu.pens import Cu2QuPen
            allGlyphs = {}
            for name, glyph in self.allGlyphs.items():
                if isinstance(glyph, StubGlyph):
                    allGlyphs[name] = glyph
                    continue
                newGlyph = glyph.__class__()
                glyph.draw(
                    Cu2QuPen(newGlyph.getPen(),
                             self.cubicConversionError,
                             reverse_direction=True))
                # the width is needed for autoUseMyMetrics method below
                newGlyph.width = glyph.width
                allGlyphs[name] = newGlyph

        self.otf["loca"] = newTable("loca")
        self.otf["glyf"] = glyf = newTable("glyf")
        glyf.glyphs = {}
        glyf.glyphOrder = self.glyphOrder

        for name in self.glyphOrder:
            glyph = allGlyphs[name]
            pen = TTGlyphPen(allGlyphs)
            glyph.draw(pen)
            ttGlyph = pen.glyph()
            if ttGlyph.isComposite() and self.autoUseMyMetrics:
                self.autoUseMyMetrics(ttGlyph, glyph.width, allGlyphs)
            glyf[name] = ttGlyph
Beispiel #3
0
    def test_curveTo_no_points(self):
        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
        quadpen.moveTo((0, 0))

        with self.assertRaisesRegex(
                AssertionError, "illegal curve segment point count: 0"):
            quadpen.curveTo()
    def setupTable_glyf(self):
        """Make the glyf table."""

        allGlyphs = self.allGlyphs
        if self.convertCubics:
            from cu2qu.pens import Cu2QuPen
            allGlyphs = {}
            for name, glyph in self.allGlyphs.items():
                if isinstance(glyph, StubGlyph):
                    allGlyphs[name] = glyph
                    continue
                newGlyph = glyph.__class__()
                glyph.draw(
                    Cu2QuPen(newGlyph.getPen(),
                             self.cubicConversionError,
                             reverse_direction=True))
                allGlyphs[name] = newGlyph

        self.otf["loca"] = newTable("loca")
        self.otf["glyf"] = glyf = newTable("glyf")
        glyf.glyphs = {}
        glyf.glyphOrder = self.glyphOrder

        for name in self.glyphOrder:
            pen = TTGlyphPen(allGlyphs)
            allGlyphs[name].draw(pen)
            glyf[name] = pen.glyph()
Beispiel #5
0
    def test_addComponent(self):
        pen = DummyPen()
        quadpen = Cu2QuPen(pen, MAX_ERR)
        quadpen.addComponent("a", (1, 2, 3, 4, 5.0, 6.0))

        # components are passed through without changes
        self.assertEqual(str(pen).splitlines(), [
            "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
        ])
Beispiel #6
0
def glyphs_to_quadratic(glyphs, max_err, **kwargs):
    quadGlyphs = {}
    for gname in glyphs.keys():
        glyph = glyphs[gname]
        ttPen = TTGlyphPen(glyphs)
        cu2quPen = Cu2QuPen(ttPen, max_err, **kwargs)
        glyph.draw(cu2quPen)
        quadGlyphs[gname] = ttPen.glyph()
    return quadGlyphs
Beispiel #7
0
    def test_curveTo_3_points(self):
        pen = DummyPen()
        quadpen = Cu2QuPen(pen, MAX_ERR)
        quadpen.moveTo((0, 0))
        quadpen.curveTo((1, 1), (2, 2), (3, 3))

        self.assertEqual(str(pen).splitlines(), [
            "pen.moveTo((0, 0))",
            "pen.qCurveTo((0.75, 0.75), (2.25, 2.25), (3, 3))",
        ])
Beispiel #8
0
    def test_curveTo_1_point(self):
        pen = DummyPen()
        quadpen = Cu2QuPen(pen, MAX_ERR)
        quadpen.moveTo((0, 0))
        quadpen.curveTo((1, 1))

        self.assertEqual(str(pen).splitlines(), [
            "pen.moveTo((0, 0))",
            "pen.lineTo((1, 1))",
        ])
Beispiel #9
0
    def test_qCurveTo_more_than_1_point(self):
        pen = DummyPen()
        quadpen = Cu2QuPen(pen, MAX_ERR)
        quadpen.moveTo((0, 0))
        quadpen.qCurveTo((1, 1), (2, 2))

        self.assertEqual(str(pen).splitlines(), [
            "pen.moveTo((0, 0))",
            "pen.qCurveTo((1, 1), (2, 2))",
        ])
Beispiel #10
0
def glyphs_to_quadratic(
        glyphs, max_err=MAX_ERR, reverse_direction=REVERSE_DIRECTION):
    quadGlyphs = {}
    for gname in glyphs.keys():
        glyph = glyphs[gname]
        ttPen = TTGlyphPen(glyphs)
        cu2quPen = Cu2QuPen(ttPen, max_err,
                            reverse_direction=reverse_direction)
        glyph.draw(cu2quPen)
        quadGlyphs[gname] = ttPen.glyph()
    return quadGlyphs
Beispiel #11
0
    def test_curveTo_more_than_3_points(self):
        # a 'SuperBezier' as described in fontTools.basePen.AbstractPen
        pen = DummyPen()
        quadpen = Cu2QuPen(pen, MAX_ERR)
        quadpen.moveTo((0, 0))
        quadpen.curveTo((1, 1), (2, 2), (3, 3), (4, 4))

        self.assertEqual(str(pen).splitlines(), [
            "pen.moveTo((0, 0))",
            "pen.qCurveTo((0.75, 0.75), (1.625, 1.625), (2, 2))",
            "pen.qCurveTo((2.375, 2.375), (3.25, 3.25), (4, 4))",
        ])
Beispiel #12
0
    def test__check_contour_closed(self):
        msg = "closePath or endPath is required"
        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
        quadpen.moveTo((0, 0))

        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.moveTo((1, 1))
        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.addComponent("a", (1, 0, 0, 1, 0, 0))

        # it works if contour is closed
        quadpen.closePath()
        quadpen.moveTo((1, 1))
        quadpen.endPath()
        quadpen.addComponent("a", (1, 0, 0, 1, 0, 0))
Beispiel #13
0
def glyphs_to_quadratic(glyphs,
                        max_err=MAX_ERR,
                        reverse_direction=REVERSE_DIRECTION):
    try:
        from cu2qu.pens import Cu2QuPen
        from fontTools.pens.ttGlyphPen import TTGlyphPen
    except ImportError:
        raise ValueError("cannot convert glyphs due to missing libs")
    quadGlyphs = {}
    for gname in glyphs.keys():
        glyph = glyphs[gname]
        ttPen = TTGlyphPen(glyphs)
        cu2quPen = Cu2QuPen(ttPen,
                            max_err,
                            reverse_direction=reverse_direction)
        glyph.draw(cu2quPen)
        quadGlyphs[gname] = ttPen.glyph()
    return quadGlyphs
Beispiel #14
0
    def test__check_contour_is_open(self):
        msg = "moveTo is required"
        quadpen = Cu2QuPen(DummyPen(), MAX_ERR)

        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.lineTo((0, 0))
        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.qCurveTo((0, 0), (1, 1))
        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.curveTo((0, 0), (1, 1), (2, 2))
        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.closePath()
        with self.assertRaisesRegex(AssertionError, msg):
            quadpen.endPath()

        quadpen.moveTo((0, 0))  # now it works
        quadpen.lineTo((1, 1))
        quadpen.qCurveTo((2, 2), (3, 3))
        quadpen.curveTo((4, 4), (5, 5), (6, 6))
        quadpen.closePath()
Beispiel #15
0
    def test_ignore_single_points(self):
        pen = DummyPen()
        quadpen = Cu2QuPen(pen, MAX_ERR, ignore_single_points=True)
        quadpen.moveTo((0, 0))
        quadpen.endPath()
        quadpen.moveTo((1, 1))
        quadpen.closePath()

        # single-point contours were ignored, so the pen commands are empty
        self.assertFalse(pen.commands)

        # redraw without ignoring single points
        quadpen.ignore_single_points = False
        quadpen.moveTo((0, 0))
        quadpen.endPath()
        quadpen.moveTo((1, 1))
        quadpen.closePath()

        self.assertTrue(pen.commands)
        self.assertEqual(
            str(pen).splitlines(), [
                "pen.moveTo((0, 0))", "pen.endPath()", "pen.moveTo((1, 1))",
                "pen.closePath()"
            ])
Beispiel #16
0
    def otf2ttf(self, maxErr=1.0, postFormat=2.0, reverseDirection=True):
        # maxErr = 1.0, approximation error, measured in units per em (UPM).
        # postFormat = 2.0, default `post` table format.
        # reverseDirection = True, assuming the input contours' direction is correctly set (counter-clockwise), we just flip it to clockwise.
        if self.font.sfntVersion != "OTTO" or not self.font.has_key(
                "CFF ") or not self.font.has_key("post"):
            print("WARNING: Invalid CFF-based font. --otf2ttf is now ignored.",
                  file=sys.stderr)
            self.jobs.convert_otf2ttf = False
            return

        # Convert cubic to quadratic
        quadGlyphs = {}
        glyphOrder = self.font.getGlyphOrder()
        glyphSet = self.font.getGlyphSet()
        for glyphName in glyphSet.keys():
            glyph = glyphSet[glyphName]
            ttPen = TTGlyphPen(glyphSet)
            cu2quPen = Cu2QuPen(ttPen, maxErr, reverseDirection)
            glyph.draw(cu2quPen)
            quadGlyphs[glyphName] = ttPen.glyph()

        # Create quadratic `glyf` table
        glyf = newTable("glyf")
        glyf.glyphOrder = glyphOrder
        glyf.glyphs = quadGlyphs
        self.font["glyf"] = glyf

        # Create global instruction table `prep` with basic rendering settings
        hintProg = Program()
        hintProg.fromBytecode([184, 1, 255, 133, 184, 0, 4, 141])
        prep = newTable("prep")
        prep.program = hintProg
        self.font["prep"] = prep

        # Create `gasp` table
        gasp = newTable("gasp")
        gasp.version = 1
        gasp.gaspRange = {65535: 10}
        self.font["gasp"] = gasp

        # Create partial TrueType `maxp` table (v1.0)
        maxp = newTable("maxp")
        maxp.tableVersion = 0x00010000
        maxp.maxZones = 1
        maxp.maxTwilightPoints = 0
        maxp.maxStorage = 0
        maxp.maxFunctionDefs = 0
        maxp.maxInstructionDefs = 0
        maxp.maxStackElements = 0
        maxp.maxSizeOfInstructions = 0
        maxp.maxComponentElements = max(
            len(g.components if hasattr(g, "components") else [])
            for g in glyf.glyphs.values())
        self.font["maxp"] = maxp

        # Create an empty `loca` table, which will be automatically generated upon compile
        self.font["loca"] = newTable("loca")

        # Modify `post` table
        post = self.font["post"]
        post.formatType = postFormat
        post.extraNames = []
        post.mapping = {}
        post.glyphOrder = glyphOrder

        # Change sfntVersion from CFF to TrueType
        self.font.sfntVersion = "\x00\x01\x00\x00"

        # Recalculate missing properties in `head`, `glyf`, `maxp` upon compile
        self.font.recalcBBoxes = True

        # Clean-ups
        del self.font["CFF "]
        if self.font.has_key("VORG"):
            del self.font["VORG"]
        return