73 lines
2.9 KiB
Python
73 lines
2.9 KiB
Python
"""A half-block wordmark font for the header hero.
|
|
|
|
Every shipped catalogue draws its brand the same way: four-column capitals,
|
|
six pixels tall, emitted as three rows of half blocks (``▀``/``▄``/``█``) — the
|
|
same shape as the original SomaFM logo. The header paints every wordmark with
|
|
the app's active palette gradient, so catalogues differ only in the word they
|
|
spell; the font lives here and each provider's ``hero.py`` is one line of data.
|
|
|
|
Glyphs are 6x4 bitmaps (``M`` is 6x5). Two pixel rows become one text row, so
|
|
a wordmark is always three rows tall and the header keeps a fixed height.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
#: 6-row bitmap per capital; all rows of one glyph are the same width.
|
|
GLYPHS: dict[str, tuple[str, ...]] = {
|
|
"A": (".##.", "#..#", "####", "#..#", "#..#", "#..#"),
|
|
"B": ("###.", "#..#", "###.", "#..#", "#..#", "###."),
|
|
"C": (".##.", "#..#", "#...", "#...", "#..#", ".##."),
|
|
"D": ("###.", "#..#", "#..#", "#..#", "#..#", "###."),
|
|
"E": ("####", "#...", "###.", "#...", "#...", "####"),
|
|
"F": ("####", "#...", "###.", "#...", "#...", "#..."),
|
|
"G": (".##.", "#..#", "#...", "#.##", "#..#", ".##."),
|
|
"H": ("#..#", "#..#", "####", "#..#", "#..#", "#..#"),
|
|
"I": ("###", ".#.", ".#.", ".#.", ".#.", "###"),
|
|
"K": ("#..#", "#.#.", "##..", "##..", "#.#.", "#..#"),
|
|
"L": ("#...", "#...", "#...", "#...", "#...", "####"),
|
|
# 5 wide on purpose: the M is the odd one out in the original wordmark.
|
|
"M": ("#...#", "##.##", "#.#.#", "#.#.#", "#...#", "#...#"),
|
|
"N": ("#..#", "##.#", "##.#", "#.##", "#..#", "#..#"),
|
|
"O": (".##.", "#..#", "#..#", "#..#", "#..#", ".##."),
|
|
"P": ("###.", "#..#", "###.", "#...", "#...", "#..."),
|
|
"R": ("###.", "#..#", "###.", "#.#.", "#..#", "#..#"),
|
|
"S": (".###", "#...", "###.", "...#", "...#", "###."),
|
|
"T": ("###", ".#.", ".#.", ".#.", ".#.", ".#."),
|
|
"U": ("#..#", "#..#", "#..#", "#..#", "#..#", ".##."),
|
|
"V": ("#..#", "#..#", "#..#", "#..#", ".##.", ".##."),
|
|
"W": ("#...#", "#...#", "#.#.#", "#.#.#", "##.##", "#...#"),
|
|
"Y": ("#..#", "#..#", ".##.", "..#.", "..#.", "..#."),
|
|
}
|
|
|
|
ROWS = 3
|
|
_GAP = " "
|
|
|
|
|
|
def _cell(top: str, bottom: str) -> str:
|
|
if top == "#" and bottom == "#":
|
|
return "█"
|
|
if top == "#":
|
|
return "▀"
|
|
if bottom == "#":
|
|
return "▄"
|
|
return " "
|
|
|
|
|
|
def _glyph_rows(char: str) -> tuple[str, ...]:
|
|
bitmap = GLYPHS.get(char)
|
|
if bitmap is None:
|
|
raise KeyError(f"no wordmark glyph for {char!r}")
|
|
return tuple(
|
|
"".join(_cell(bitmap[row * 2][col], bitmap[row * 2 + 1][col]) for col in range(len(bitmap[0])))
|
|
for row in range(ROWS)
|
|
)
|
|
|
|
|
|
def render(text: str) -> tuple[str, ...]:
|
|
"""Spell ``text`` as three rows of half blocks."""
|
|
glyphs = [_glyph_rows(char.upper()) for char in text]
|
|
rows: list[str] = []
|
|
for row in range(ROWS):
|
|
rows.append(_GAP.join(glyph[row] for glyph in glyphs).rstrip())
|
|
return tuple(rows)
|