feat: big title
This commit is contained in:
209
backend/uframe/fonts.py
Normal file
209
backend/uframe/fonts.py
Normal file
@@ -0,0 +1,209 @@
|
||||
"""µFrame Big Text Fonts — multi-line ASCII art letter definitions.
|
||||
|
||||
Each font is a dict mapping characters to a list of strings (one per line).
|
||||
All characters in a font have the same height.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Block font — solid █ with box-drawing. Height: 6 lines.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_BLOCK: dict[str, list[str]] = {
|
||||
"A": [" █████╗ ", "██╔══██╗", "███████║", "██╔══██║", "██║ ██║", "╚═╝ ╚═╝"],
|
||||
"B": ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔══██╗", "██████╔╝", "╚═════╝ "],
|
||||
"C": [" ██████╗", "██╔════╝", "██║ ", "██║ ", "╚██████╗", " ╚═════╝"],
|
||||
"D": ["██████╗ ", "██╔══██╗", "██║ ██║", "██║ ██║", "██████╔╝", "╚═════╝ "],
|
||||
"E": ["███████╗", "██╔════╝", "█████╗ ", "██╔══╝ ", "███████╗", "╚══════╝"],
|
||||
"F": ["███████╗", "██╔════╝", "█████╗ ", "██╔══╝ ", "██║ ", "╚═╝ "],
|
||||
"G": [" ██████╗ ", "██╔════╝ ", "██║ ███╗", "██║ ██║", "╚██████╔╝", " ╚═════╝ "],
|
||||
"H": ["██╗ ██╗", "██║ ██║", "███████║", "██╔══██║", "██║ ██║", "╚═╝ ╚═╝"],
|
||||
"I": ["██╗", "██║", "██║", "██║", "██║", "╚═╝"],
|
||||
"J": [" ██╗", " ██║", " ██║", "██ ██║", "╚█████╔╝", " ╚════╝ "],
|
||||
"K": ["██╗ ██╗", "██║ ██╔╝", "█████╔╝ ", "██╔═██╗ ", "██║ ██╗", "╚═╝ ╚═╝"],
|
||||
"L": ["██╗ ", "██║ ", "██║ ", "██║ ", "███████╗", "╚══════╝"],
|
||||
"M": ["███╗ ███╗", "████╗ ████║", "██╔████╔██║", "██║╚██╔╝██║", "██║ ╚═╝ ██║", "╚═╝ ╚═╝"],
|
||||
"N": ["███╗ ██╗", "████╗ ██║", "██╔██╗ ██║", "██║╚██╗██║", "██║ ╚████║", "╚═╝ ╚═══╝"],
|
||||
"O": [" ██████╗ ", "██╔═══██╗", "██║ ██║", "██║ ██║", "╚██████╔╝", " ╚═════╝ "],
|
||||
"P": ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔═══╝ ", "██║ ", "╚═╝ "],
|
||||
"Q": [" ██████╗ ", "██╔═══██╗", "██║ ██║", "██║▄▄ ██║", "╚██████╔╝", " ╚══▀▀═╝ "],
|
||||
"R": ["██████╗ ", "██╔══██╗", "██████╔╝", "██╔══██╗", "██║ ██║", "╚═╝ ╚═╝"],
|
||||
"S": ["███████╗", "██╔════╝", "███████╗", "╚════██║", "███████║", "╚══════╝"],
|
||||
"T": ["████████╗", "╚══██╔══╝", " ██║ ", " ██║ ", " ██║ ", " ╚═╝ "],
|
||||
"U": ["██╗ ██╗", "██║ ██║", "██║ ██║", "██║ ██║", "╚██████╔╝", " ╚═════╝ "],
|
||||
"V": ["██╗ ██╗", "██║ ██║", "██║ ██║", "╚██╗ ██╔╝", " ╚████╔╝ ", " ╚═══╝ "],
|
||||
"W": ["██╗ ██╗", "██║ ██║", "██║ █╗ ██║", "██║███╗██║", "╚███╔███╔╝", " ╚══╝╚══╝ "],
|
||||
"X": ["██╗ ██╗", "╚██╗██╔╝", " ╚███╔╝ ", " ██╔██╗ ", "██╔╝ ██╗", "╚═╝ ╚═╝"],
|
||||
"Y": ["██╗ ██╗", "╚██╗ ██╔╝", " ╚████╔╝ ", " ╚██╔╝ ", " ██║ ", " ╚═╝ "],
|
||||
"Z": ["███████╗", "╚══███╔╝", " ███╔╝ ", " ███╔╝ ", "███████╗", "╚══════╝"],
|
||||
"0": [" ██████╗ ", "██╔═══██╗", "██║ ██║", "██║ ██║", "╚██████╔╝", " ╚═════╝ "],
|
||||
"1": [" ██╗", "███║", "╚██║", " ██║", " ██║", " ╚═╝"],
|
||||
"2": ["██████╗ ", "╚════██╗", " █████╔╝", "██╔═══╝ ", "███████╗", "╚══════╝"],
|
||||
"3": ["██████╗ ", "╚════██╗", " █████╔╝", " ╚═══██╗", "██████╔╝", "╚═════╝ "],
|
||||
"4": ["██╗ ██╗", "██║ ██║", "███████║", "╚════██║", " ██║", " ╚═╝"],
|
||||
"5": ["███████╗", "██╔════╝", "███████╗", "╚════██║", "███████║", "╚══════╝"],
|
||||
"6": [" ██████╗", "██╔════╝", "██████╗ ", "██╔══██╗", "╚█████╔╝", " ╚════╝ "],
|
||||
"7": ["███████╗", "╚════██║", " ██╔╝", " ██╔╝ ", " ██║ ", " ╚═╝ "],
|
||||
"8": [" █████╗ ", "██╔══██╗", "╚█████╔╝", "██╔══██╗", "╚█████╔╝", " ╚════╝ "],
|
||||
"9": [" █████╗ ", "██╔══██╗", "╚██████║", " ╚═══██║", " █████╔╝", " ╚════╝ "],
|
||||
"-": [" ", " ", "██████╗ ", "╚═════╝ ", " ", " "],
|
||||
" ": [" ", " ", " ", " ", " ", " "],
|
||||
".": [" ", " ", " ", " ", "██╗", "╚═╝"],
|
||||
"!": ["██╗", "██║", "██║", "╚═╝", "██╗", "╚═╝"],
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Thin font — light single-stroke. Height: 3 lines.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_THIN: dict[str, list[str]] = {
|
||||
"A": ["┌─┐", "├─┤", "┘ └"],
|
||||
"B": ["┬─┐", "├─┤", "┴─┘"],
|
||||
"C": ["┌─ ", "│ ", "└─ "],
|
||||
"D": ["┬─┐", "│ │", "┴─┘"],
|
||||
"E": ["┬──", "├─ ", "┴──"],
|
||||
"F": ["┬──", "├─ ", "┘ "],
|
||||
"G": ["┌─ ", "│ ┐", "└─┘"],
|
||||
"H": ["┐ ┌", "├─┤", "┘ └"],
|
||||
"I": ["┬", "│", "┴"],
|
||||
"J": [" ┬", " │", "└─┘"],
|
||||
"K": ["┐ ┌", "├┬┘", "┘└ "],
|
||||
"L": ["│ ", "│ ", "└──"],
|
||||
"M": ["┌┬┐", "│││", "┘ └"],
|
||||
"N": ["┌┐ ", "│└┐", "┘ └"],
|
||||
"O": ["┌─┐", "│ │", "└─┘"],
|
||||
"P": ["┌─┐", "├─┘", "┘ "],
|
||||
"Q": ["┌─┐", "│ │", "└─┤"],
|
||||
"R": ["┌─┐", "├─┤", "┘ └"],
|
||||
"S": ["┌─ ", "└─┐", " ─┘"],
|
||||
"T": ["┬─┬", " │ ", " ┴ "],
|
||||
"U": ["┐ ┌", "│ │", "└─┘"],
|
||||
"V": ["┐ ┌", "│ │", "└┬┘"],
|
||||
"W": ["┐ ┌", "│││", "└┴┘"],
|
||||
"X": ["╲ ╱", " ╳ ", "╱ ╲"],
|
||||
"Y": ["┐ ┌", "└┬┘", " ┴ "],
|
||||
"Z": ["──┐", " ╱ ", "└──"],
|
||||
"0": ["┌─┐", "│ │", "└─┘"],
|
||||
"1": [" ┐", " │", " ┴"],
|
||||
"2": ["─┐", "┌┘", "└─"],
|
||||
"3": ["─┐", " ┤", "─┘"],
|
||||
"4": ["┐ ┐", "└─┤", " ┘"],
|
||||
"5": ["┌─", "└┐", "─┘"],
|
||||
"6": ["┌─", "├┐", "└┘"],
|
||||
"7": ["──┐", " │", " ┘"],
|
||||
"8": ["┌┐", "├┤", "└┘"],
|
||||
"9": ["┌┐", "└┤", "─┘"],
|
||||
"-": [" ", "── ", " "],
|
||||
" ": [" ", " ", " "],
|
||||
".": [" ", " ", "·"],
|
||||
"!": ["│", " ", "·"],
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pixel font — retro bitmap. Height: 3 lines.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_PIXEL: dict[str, list[str]] = {
|
||||
"A": ["▀▀▀▄", "█▀▀█", "▀ ▀"],
|
||||
"B": ["▀▀▀▄", "█▀▀▄", "▀▀▀ "],
|
||||
"C": ["▄▀▀▀", "█ ", "▀▀▀ "],
|
||||
"D": ["▀▀▀▄", "█ █", "▀▀▀ "],
|
||||
"E": ["▀▀▀ ", "█▀ ", "▀▀▀ "],
|
||||
"F": ["▀▀▀ ", "█▀ ", "▀ "],
|
||||
"G": ["▄▀▀ ", "█ ▀█", "▀▀▀ "],
|
||||
"H": ["▀ ▀ ", "█▀▀█", "▀ ▀"],
|
||||
"I": ["▀", "█", "▀"],
|
||||
"J": [" ▀ ", " █ ", "▀▀ "],
|
||||
"K": ["▀ ▄ ", "█▀▄ ", "▀ ▀"],
|
||||
"L": ["▀ ", "█ ", "▀▀▀ "],
|
||||
"M": ["▀▄▄▀", "█▀▀█", "▀ ▀"],
|
||||
"N": ["▀▄ ▀", "█ ▀█", "▀ ▀"],
|
||||
"O": ["▄▀▀▄", "█ █", "▀▀▀ "],
|
||||
"P": ["▀▀▀▄", "█▀▀ ", "▀ "],
|
||||
"Q": ["▄▀▀▄", "█ █", "▀▀▀▄"],
|
||||
"R": ["▀▀▀▄", "█▀▀▄", "▀ ▀"],
|
||||
"S": ["▄▀▀ ", "▀▀▀▄", " ▀▀ "],
|
||||
"T": ["▀▀▀▀", " █ ", " ▀ "],
|
||||
"U": ["▀ ▀", "█ █", "▀▀▀ "],
|
||||
"V": ["▀ ▀", "█ █", " ▀▀ "],
|
||||
"W": ["▀ ▀", "█▄▄█", "▀▀▀▀"],
|
||||
"X": ["▀ ▀", " ▀▀ ", "▀ ▀"],
|
||||
"Y": ["▀ ▀", " ▀▀ ", " ▀ "],
|
||||
"Z": ["▀▀▀▀", " ▄▀ ", "▀▀▀▀"],
|
||||
"0": ["▄▀▀▄", "█ █", "▀▀▀ "],
|
||||
"1": [" ▄", " █", " ▀"],
|
||||
"2": ["▀▀▄", " ▄▀", "▀▀▀"],
|
||||
"3": ["▀▀▄", " ▀▄", "▀▀ "],
|
||||
"4": ["▀ ▀", "▀▀█", " ▀"],
|
||||
"5": ["▀▀▀", "▀▀▄", "▀▀ "],
|
||||
"6": ["▄▀▀", "█▀▄", "▀▀ "],
|
||||
"7": ["▀▀▀", " █", " ▀"],
|
||||
"8": ["▄▀▄", "█▀█", "▀▀ "],
|
||||
"9": ["▄▀▄", "▀▀█", "▀▀ "],
|
||||
"-": [" ", " ▀▀ ", " "],
|
||||
" ": [" ", " ", " "],
|
||||
".": [" ", " ", "▄"],
|
||||
"!": ["█", " ", "▄"],
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Font registry
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
FONTS: dict[str, dict[str, list[str]]] = {
|
||||
"block": _BLOCK,
|
||||
"thin": _THIN,
|
||||
"pixel": _PIXEL,
|
||||
}
|
||||
|
||||
FONT_HEIGHTS: dict[str, int] = {
|
||||
"block": 6,
|
||||
"thin": 3,
|
||||
"pixel": 3,
|
||||
}
|
||||
|
||||
|
||||
def render_big_text(text: str, font_name: str = "block", kerning: int = 1) -> list[str]:
|
||||
"""Render text as multi-line ASCII art using the specified font.
|
||||
|
||||
Args:
|
||||
text: the string to render (uppercase recommended for block/pixel)
|
||||
font_name: "block", "thin", or "pixel"
|
||||
kerning: space between characters (0=tight, 1=normal, 2=wide)
|
||||
|
||||
Returns:
|
||||
List of strings, one per line of the rendered text.
|
||||
"""
|
||||
font = FONTS.get(font_name, _BLOCK)
|
||||
height = FONT_HEIGHTS.get(font_name, 6)
|
||||
text_upper = text.upper()
|
||||
|
||||
# Build each line by concatenating character columns
|
||||
lines: list[str] = ["" for _ in range(height)]
|
||||
spacer = " " * kerning
|
||||
|
||||
for i, ch in enumerate(text_upper):
|
||||
glyph = font.get(ch, font.get("?", [" " * 3] * height))
|
||||
for row in range(height):
|
||||
if row < len(glyph):
|
||||
lines[row] += glyph[row]
|
||||
else:
|
||||
lines[row] += " " * (len(glyph[0]) if glyph else 3)
|
||||
if i < len(text_upper) - 1:
|
||||
lines[row] += spacer
|
||||
|
||||
return lines
|
||||
|
||||
|
||||
def get_text_width(text: str, font_name: str = "block", kerning: int = 1) -> int:
|
||||
"""Calculate the rendered width of big text without rendering it."""
|
||||
font = FONTS.get(font_name, _BLOCK)
|
||||
text_upper = text.upper()
|
||||
width = 0
|
||||
for i, ch in enumerate(text_upper):
|
||||
glyph = font.get(ch, font.get("?", [" " * 3]))
|
||||
width += len(glyph[0]) if glyph else 3
|
||||
if i < len(text_upper) - 1:
|
||||
width += kerning
|
||||
return width
|
||||
Reference in New Issue
Block a user