267 lines
7.6 KiB
Python
267 lines
7.6 KiB
Python
"""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.
|
|
|
|
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.
|
|
"""
|
|
|
|
# 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', ' ')
|
|
CHAR_MAP = {
|
|
"1/8": "a",
|
|
"1/4": "b",
|
|
"3/8": "c",
|
|
"1/2": "d",
|
|
"5/8": "e",
|
|
"3/4": "f",
|
|
"7/8": "g",
|
|
}
|
|
|
|
# Map number of eighths (1-7) to fraction name
|
|
EIGHTHS_TO_NAME = {
|
|
1: "1/8",
|
|
2: "1/4",
|
|
3: "3/8",
|
|
4: "1/2",
|
|
5: "5/8",
|
|
6: "3/4",
|
|
7: "7/8",
|
|
}
|
|
|
|
# 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
|
|
],
|
|
"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
|
|
],
|
|
"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
|
|
],
|
|
"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
|
|
],
|
|
"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
|
|
],
|
|
"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/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
|
|
],
|
|
}
|
|
# fmt: on
|
|
|
|
|
|
def glyph_to_escpos(rows):
|
|
"""Convert a visual glyph (24 rows of 12-char strings) to ESC/POS column data.
|
|
|
|
ESC/POS user-defined chars are column-major: each column is 3 bytes
|
|
(24 vertical pixels), MSB = topmost pixel.
|
|
"""
|
|
data = bytearray()
|
|
for col in range(12):
|
|
for byte_idx in range(3):
|
|
val = 0
|
|
for bit in range(8):
|
|
row = byte_idx * 8 + bit
|
|
if rows[row][col] == "#":
|
|
val |= 0x80 >> bit
|
|
data.append(val)
|
|
return bytes(data)
|
|
|
|
|
|
def upload_fractions(printer):
|
|
"""Upload all custom fraction glyphs to the printer via ESC &."""
|
|
# ESC % 1: enable user-defined character set
|
|
printer._raw(b"\x1b\x25\x01")
|
|
|
|
for name, char in CHAR_MAP.items():
|
|
rows = GLYPHS[name]
|
|
col_data = glyph_to_escpos(rows)
|
|
code = ord(char)
|
|
# ESC & 3 c1 c2 12 [column data]
|
|
# 3 = bytes per column (24 dots), 12 = character width
|
|
printer._raw(b"\x1b\x26\x03" + bytes([code, code, 12]) + col_data)
|
|
|
|
|
|
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.
|
|
"""
|
|
dollars = int(price)
|
|
eighths = round((price - dollars) * 8)
|
|
if eighths == 8:
|
|
dollars += 1
|
|
eighths = 0
|
|
if eighths == 0:
|
|
return str(dollars)
|
|
name = EIGHTHS_TO_NAME[eighths]
|
|
return str(dollars) + CHAR_MAP[name]
|