juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

mkfont.py (4655B)


      1 #!/usr/bin/env python3
      2 """Genera comun/gfx/font.c (Latin-1 32..255) desde las fuentes de tools/fonts/:
      3 
      4   font_normal  Terminus 6x12        (ter-u12n.bdf, OFL)
      5   font_bold    Terminus 6x12 engrosada a 7x12 (en 12 px la bold de Terminus es
      6                casi igual a la normal: se le suma la misma letra corrida un pixel)
      7   font_small   Spleen 5x8           (spleen-5x8.bdf, BSD-2)
      8 
      9 Spleen 5x8 solo trae ASCII: las letras del castellano se arman acá (acento en las
     10 dos filas libres arriba de la x) y el resto de Latin-1 sale de la X11 misc-fixed
     11 5x7 (dominio publico, /usr/share/fonts/misc), bajada una fila para alinear la base.
     12 
     13 Uso: python3 comun/tools/mkfont.py > comun/gfx/font.c"""
     14 import gzip
     15 import os
     16 from PIL import PcfFontFile
     17 
     18 HERE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fonts")
     19 
     20 
     21 def bdf(name, h):
     22     """{codigo: set((x, fila))} con fila 0 arriba de la celda de alto h."""
     23     out = {}
     24     asc = None
     25     cp = None
     26     rows = None
     27     for line in open(os.path.join(HERE, name), encoding="latin-1"):
     28         p = line.split()
     29         if not p:
     30             continue
     31         if p[0] == "FONT_ASCENT":
     32             asc = int(p[1])
     33         elif p[0] == "ENCODING":
     34             cp = int(p[1])
     35         elif p[0] == "BBX":
     36             bw, bh, bx, by = map(int, p[1:5])
     37         elif p[0] == "BITMAP":
     38             rows = []
     39         elif p[0] == "ENDCHAR":
     40             if cp is not None and 32 <= cp < 256:
     41                 top = asc - (by + bh)
     42                 pts = set()
     43                 for r, hexrow in enumerate(rows):
     44                     v = int(hexrow, 16)
     45                     nb = len(hexrow) * 4
     46                     for c in range(bw):
     47                         if v >> (nb - 1 - c) & 1:
     48                             pts.add((bx + c, top + r))
     49                 out[cp] = pts
     50             rows = None
     51         elif rows is not None:
     52             rows.append(p[0])
     53     return out
     54 
     55 
     56 def x11(name, shift):
     57     f = PcfFontFile.PcfFontFile(gzip.open("/usr/share/fonts/misc/%s.pcf.gz" % name, "rb"), "iso8859-1")
     58     asc = -f.glyph[ord("A")][1][1]
     59     out = {}
     60     for cp in range(32, 256):
     61         g = f.glyph[cp]
     62         pts = set()
     63         if g and g[3]:
     64             dx, (x0, y0, x1, y1), src, im = g
     65             px = im.load()
     66             for yy in range(im.size[1]):
     67                 for xx in range(im.size[0]):
     68                     if px[xx, yy]:
     69                         pts.add((x0 + xx, asc + y0 + yy + shift))
     70         out[cp] = pts
     71     return out
     72 
     73 
     74 def small():
     75     g = bdf("spleen-5x8.bdf", 8)
     76     old = x11("5x7", 1)
     77     ACUTE, GRAVE = {(2, 0), (1, 1)}, {(1, 0), (2, 1)}
     78     TILDE, DIAER = {(1, 0), (3, 0), (0, 1), (2, 1)}, {(0, 0), (3, 0)}
     79     CIRC = {(1, 0), (2, 0), (0, 1), (3, 1)}
     80     marks = {"á": ("a", ACUTE), "é": ("e", ACUTE), "í": ("i", ACUTE), "ó": ("o", ACUTE), "ú": ("u", ACUTE),
     81              "à": ("a", GRAVE), "è": ("e", GRAVE), "ì": ("i", GRAVE), "ò": ("o", GRAVE), "ù": ("u", GRAVE),
     82              "ä": ("a", DIAER), "ë": ("e", DIAER), "ï": ("i", DIAER), "ö": ("o", DIAER), "ü": ("u", DIAER),
     83              "â": ("a", CIRC), "ê": ("e", CIRC), "î": ("i", CIRC), "ô": ("o", CIRC), "û": ("u", CIRC),
     84              "ñ": ("n", TILDE), "ã": ("a", TILDE), "õ": ("o", TILDE)}
     85     for cp in range(160, 256):
     86         if not g.get(cp):
     87             g[cp] = old[cp]
     88     for ch, (base, m) in marks.items():
     89         g[ord(ch)] = {p for p in g[ord(base)] if p[1] >= 2} | m      # sin el punto de la i
     90     g[ord("¿")] = {(3 - x, 6 - y) for (x, y) in g[ord("?")]}
     91     g[ord("¡")] = {(x, 6 - y) for (x, y) in g[ord("!")]}
     92     g[ord("·")] = {(1, 4), (2, 4)}
     93     return g
     94 
     95 
     96 def emit(cname, g, w, h, src):
     97     print("static const uint8_t %s_bits[224][%d] = {   /* %s */" % (cname, h, src))
     98     for cp in range(32, 256):
     99         bits = [0] * h
    100         for (x, y) in g.get(cp, ()):
    101             if 0 <= y < h and 0 <= x < 8:
    102                 bits[y] |= 0x80 >> x
    103         print("    {" + ",".join("0x%02x" % b for b in bits) + "}, /* %d */" % cp)
    104     print("};")
    105     print("const Font %s = { %d, %d, &%s_bits[0][0] };\n" % (cname, w, h, cname))
    106 
    107 
    108 print("/* font.c - GENERADO por tools/mkfont.py desde tools/fonts/: Terminus 6x12 (normal y")
    109 print(" * engrosada como negrita; OFL) y Spleen 5x8 (chica, BSD-2; Latin-1 completado). Licencias en")
    110 print(" * tools/fonts/. Latin-1 32..255, una fila por byte, bit 7 = columna 0. */")
    111 print('#include "gfx.h"\n')
    112 emit("font_small", small(), 5, 8, "Spleen 5x8")
    113 emit("font_normal", bdf("ter-u12n.bdf", 12), 6, 12, "Terminus 6x12")
    114 emit("font_bold", {cp: s | {(x + 1, y) for (x, y) in s} for cp, s in bdf("ter-u12n.bdf", 12).items()},
    115      7, 12, "Terminus 6x12 engrosada")