Vsuvka: TTF do pygame

... Petr Blahoš, 4. 12. 2023 Font Python

Minule jsem měl jistou myšlenku na animování kontur znaků. To se ale nezdařilo, tak raději zkusím něco jiného.

Hoří

Příprava prostředí

Zpočátku jsem použil wxPython ze dvou důvodů:

  • Mám s ním dost velké zkušenosti
  • Věděl jsem, že ve fonttools je WxPen, což usnadňovalo věci

Ale wxPython přece jen není dobrý k manipulaci s obrázky, a to teď budeme potřebovat. Použijeme pygame, a to hlavně proto, že je jednoduché přistupovat k pixelům, ale také vytvářet objekty, které si budou žít vlastním životem. Ale chybí nám pen.

Na začátek musím vysvětlit, že budu potřebovat vykreslit obrys znaků (neboli získat čáry), ale taky vykreslit plný znak. Vykreslení čar se dělá poměrně snadno. Znak se skládá z rovných čar, kvadratických křivek a kubických Bézierových křivek. To je jednoduché. Horší je to s vykreslením ploch. Na to už je potřeba implementovat algoritmus pro vyplnění cesty, a ten nemůžu rychle najít. Zkusíme to jinak: fontTools mají SVGPathPen. pygame umí vykreslit SVG. Tak si zkusíme vytvořit SVG a ten vykreslit pomocí pygame.

Když použijeme známým způsobem SVGPathPen, dostaneme z něj seznam příkazů pro vykreslení cesty, např. M91 464V624H591V464Z. To musíme něčím obalit, abychom dostali kompletní svg. Např. takto:

    glyph = self.font.getGlyphSet()[glyph_name]
    pen = SVGPathPen(self.font.getGlyphSet())
    glyph.draw(pen)
    s = '<g transform="translate(%d %d) scale(1 -1)"><path d="%s" fill="#FFF" /></g>\n' % (
        0, self.ascent,
        pen.getCommands(),
    )
    svg = "\n".join([
        """<?xml version="1.0" encoding="UTF-8"?>""",
        """<svg width="%d" height="%d" xmlns="http://www.w3.org/2000/svg">"""
        % (glyph.width, self.ascent - self.descent),
        s + "</svg>",
    ])

Všimněte si přidaného fill="#FFF". To říká, že chceme cestu vyplnit bílou barvou. Pokud bychom chtěli naopak vykreslit čáru, přidali bychom stroke="#FFF" stroke-width="50".

Když už máme SVG, můžeme ho vykreslit:

# SVG do bitmapy:
img = pygame.image.load(io.BytesIO(svg_stroke.encode("utf-8")))
# Bitmap do jakéhokoliv povrchu:
surface.blit(img, (0, 0))

Pokud to chcete zkusit celé bez vlastního přičinění, kód najdete zde.

Ochutnávka

Abyste viděli, co vás čeká příště:

Bubliny

Dolů a nahoru

Zleva doprava

Hoří


Komentáře byly zrušeny
V EU teď máme složitou situaci s Cookies. Na komentáře jsem používal jistou službu třetí strany. Ta však používá Cookies poměrně, ehm, benevolentně. Tak jsem se rozhodl komentáře zrušit. Pokud chcete, můžete mi napsat přímo