make fractions look better

This commit is contained in:
Joe Lothan 2026-06-15 18:52:35 -04:00
parent 6efed3be72
commit c1447e5852

325
glyphs.py
View file

@ -1,14 +1,18 @@
"""Custom fraction glyphs for the TM-T88V receipt printer.
Each glyph is a 12-wide x 24-tall pixel bitmap defined as a list of 24 strings.
'#' = pixel on, '.' = pixel off.
Fractions are composed from small digit patterns stacked vertically:
numerator on top, denominator on bottom matching the old ticker tape style.
To customize a glyph, edit its pattern below. Each row must be exactly 12
characters wide and there must be exactly 24 rows per glyph.
To customize:
- Edit DIGIT_PATTERNS to change how a digit looks in ALL fractions using it.
- Or override a specific fraction in GLYPH_OVERRIDES with a full 12x24 grid.
- '#' = pixel on, '.' = pixel off
- Each digit pattern is 12 wide x 11 tall.
- Each full glyph is 12 wide x 24 tall (11 + 2 gap + 11).
"""
# Map each fraction to a character code on the printer.
# Must be in 0x20-0x7E range and not conflict with output chars (A-Z, 0-9, '.', 's', ' ')
# Character codes used on the printer for each fraction.
# Must be 0x20-0x7E and not conflict with output chars (A-Z, 0-9, '.', 's', ' ')
CHAR_MAP = {
"1/8": "a",
"1/4": "b",
@ -30,194 +34,149 @@ EIGHTHS_TO_NAME = {
7: "7/8",
}
# ── Digit patterns (12 wide x 11 tall) ───────────────────────────────────────
# These are composed into the fraction glyphs below.
# fmt: off
GLYPHS = {
"1/8": [
"............", # 0
".........#..", # 1 ── numerator "1"
"........##..", # 2
".........#..", # 3
".........#..", # 4
".........#..", # 5
".........#..", # 6
".........#..", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"..##........", # 16 ── denominator "8"
".#..#.......", # 17
".#..#.......", # 18
"..##........", # 19
".#..#.......", # 20
".#..#.......", # 21
"..##........", # 22
"............", # 23
DIGIT_PATTERNS = {
1: [
".....##.....",
"....###.....",
"...####.....",
".....##.....",
".....##.....",
".....##.....",
".....##.....",
".....##.....",
".....##.....",
".....##.....",
"...######...",
],
"1/4": [
"............", # 0
".........#..", # 1 ── "1"
"........##..", # 2
".........#..", # 3
".........#..", # 4
".........#..", # 5
".........#..", # 6
".........#..", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"....#.......", # 16 ── "4"
"...##.......", # 17
"..#.#.......", # 18
".#..#.......", # 19
".####.......", # 20
"....#.......", # 21
"....#.......", # 22
"............", # 23
2: [
"..########..",
".##......##.",
"..........##",
"..........##",
"........##..",
"......##....",
"....##......",
"..##........",
".##.........",
".##.........",
"############",
],
"3/8": [
"............", # 0
"........##..", # 1 ── "3"
".......#..#.", # 2
"..........#.", # 3
"........##..", # 4
"..........#.", # 5
".......#..#.", # 6
"........##..", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"..##........", # 16 ── "8"
".#..#.......", # 17
".#..#.......", # 18
"..##........", # 19
".#..#.......", # 20
".#..#.......", # 21
"..##........", # 22
"............", # 23
3: [
"..########..",
".##......##.",
"..........##",
"..........##",
".....####...",
"..........##",
"..........##",
"..........##",
".##......##.",
".##......##.",
"..########..",
],
"1/2": [
"............", # 0
".........#..", # 1 ── "1"
"........##..", # 2
".........#..", # 3
".........#..", # 4
".........#..", # 5
".........#..", # 6
".........#..", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"..##........", # 16 ── "2"
".#..#.......", # 17
"....#.......", # 18
"...#........", # 19
"..#.........", # 20
".#..........", # 21
".####.......", # 22
"............", # 23
4: [
".......##...",
"......###...",
".....####...",
"....##.##...",
"...##..##...",
"..##...##...",
".##....##...",
"############",
".......##...",
".......##...",
".......##...",
],
"5/8": [
"............", # 0
".......####.", # 1 ── "5"
".......#....", # 2
".......###..", # 3
"..........#.", # 4
"..........#.", # 5
".......#..#.", # 6
"........##..", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"..##........", # 16 ── "8"
".#..#.......", # 17
".#..#.......", # 18
"..##........", # 19
".#..#.......", # 20
".#..#.......", # 21
"..##........", # 22
"............", # 23
5: [
"############",
"##..........",
"##..........",
"##..........",
"##########..",
"..........##",
"..........##",
"..........##",
"..........##",
".##......##.",
"..########..",
],
"3/4": [
"............", # 0
"........##..", # 1 ── "3"
".......#..#.", # 2
"..........#.", # 3
"........##..", # 4
"..........#.", # 5
".......#..#.", # 6
"........##..", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"....#.......", # 16 ── "4"
"...##.......", # 17
"..#.#.......", # 18
".#..#.......", # 19
".####.......", # 20
"....#.......", # 21
"....#.......", # 22
"............", # 23
7: [
"############",
"##........##",
"..........##",
".........##.",
"........##..",
".......##...",
"......##....",
".....##.....",
"....##......",
"....##......",
"....##......",
],
"7/8": [
"............", # 0
".......####.", # 1 ── "7"
"..........#.", # 2
".........#..", # 3
".........#..", # 4
"........#...", # 5
"........#...", # 6
"........#...", # 7
"........#...", # 8 ── slash
".......#....", # 9
"......#.....", # 10
".....#......", # 11
"....#.......", # 12
"...#........", # 13
"..#.........", # 14
".#..........", # 15
"..##........", # 16 ── "8"
".#..#.......", # 17
".#..#.......", # 18
"..##........", # 19
".#..#.......", # 20
".#..#.......", # 21
"..##........", # 22
"............", # 23
8: [
"..########..",
".##......##.",
".##......##.",
".##......##.",
"..########..",
".##......##.",
".##......##.",
".##......##.",
".##......##.",
".##......##.",
"..########..",
],
}
# fmt: on
def _compose_fraction(num, den):
"""Build a 12x24 glyph: numerator digit stacked over denominator digit.
Layout (24 rows):
rows 0-10: numerator digit (11 rows)
rows 11-12: gap (2 rows)
rows 13-23: denominator digit (11 rows)
"""
blank = "." * 12
rows = list(DIGIT_PATTERNS[num])
rows.extend([blank] * 2)
rows.extend(DIGIT_PATTERNS[den])
return rows
# ── Composed glyphs (auto-generated from digit patterns) ────────────────────
GLYPHS = {
"1/8": _compose_fraction(1, 8),
"1/4": _compose_fraction(1, 4),
"3/8": _compose_fraction(3, 8),
"1/2": _compose_fraction(1, 2),
"5/8": _compose_fraction(5, 8),
"3/4": _compose_fraction(3, 4),
"7/8": _compose_fraction(7, 8),
}
# ── Per-fraction overrides ──────────────────────────────────────────────────
# To hand-craft a specific fraction, add it here as a 24-row list of 12-char
# strings. It will replace the auto-composed version above.
#
# GLYPH_OVERRIDES = {
# "1/2": [
# "............",
# ... # 24 rows total
# ],
# }
GLYPH_OVERRIDES = {}
# Apply overrides
GLYPHS.update(GLYPH_OVERRIDES)
# ── ESC/POS conversion & upload ─────────────────────────────────────────────
def glyph_to_escpos(rows):
"""Convert a visual glyph (24 rows of 12-char strings) to ESC/POS column data.
@ -254,7 +213,7 @@ def price_to_fraction(price):
"""Convert a decimal price to dollar amount + fraction character.
Rounds to the nearest eighth of a dollar, like old ticker tapes.
Returns e.g. "246" or "57a" where 'a' is the custom glyph.
Returns e.g. "246" or "57d" where 'd' is the custom ½ glyph.
"""
dollars = int(price)
eighths = round((price - dollars) * 8)