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")