Repository navigation
Expand file tree
/
Copy pathmorse_print.py
More file actions
113 lines (96 loc) · 4.29 KB
/
Copy pathmorse_print.py
File metadata and controls
113 lines (96 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env python3
"""Print a message in Morse code on the S01 thermal printer.
Encodes text into graphical dots and dashes (laid out with proper letter/word
spacing) and prints an A-Z reference key underneath.
Examples:
python morse_print.py # a random phrase
python morse_print.py --text "HELLO WORLD"
python morse_print.py --no-print
"""
from __future__ import annotations
import argparse
from pathlib import Path
import random
from PIL import Image, ImageDraw
from print_common import ROOT, Card
MORSE = {
"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": "----.", ".": ".-.-.-", ",": "--..--", "?": "..--..",
"!": "-.-.--", "/": "-..-.", "'": ".----.",
}
PHRASES = ["HELLO WORLD", "STAY CURIOUS", "WHAT HATH GOD WROUGHT", "KEEP IT SIMPLE",
"SOS", "HELLO FROM THE PRINTER", "NICE WORK", "TO THE STARS", "GOOD LUCK"]
H = 9 # symbol height unit (px)
INTRA = H # gap between symbols in a letter
LETTER_GAP = 3 * H
WORD_GAP = 6 * H
LINE_H = round(H * 2.4)
def letter_width(code: str) -> int:
w = sum((H if s == "." else 3 * H) for s in code)
return w + INTRA * (len(code) - 1)
def render_morse(text: str, width: int) -> Image.Image:
words = text.upper().split()
rows: list[list] = [[]] # each row: list of (kind, code) where kind='L'
x = 0
for wi, word in enumerate(words):
letters = [(c, MORSE[c]) for c in word if c in MORSE]
wpx = sum(letter_width(code) for _, code in letters) + LETTER_GAP * (len(letters) - 1)
gap = WORD_GAP if rows[-1] else 0
if x + gap + wpx > width and rows[-1]:
rows.append([])
x = 0
gap = 0
x += gap
for li, (ch, code) in enumerate(letters):
lw = letter_width(code)
if x + lw > width and rows[-1]:
rows.append([])
x = 0
rows[-1].append((x, code))
x += lw + LETTER_GAP
h = len(rows) * LINE_H
img = Image.new("L", (width, h + 4), 255)
d = ImageDraw.Draw(img)
for ri, row in enumerate(rows):
y = ri * LINE_H + 2
for start_x, code in row:
cx = start_x
for s in code:
if s == ".":
d.ellipse((cx, y, cx + H, y + H), fill=0)
cx += H + INTRA
else:
d.rounded_rectangle((cx, y, cx + 3 * H, y + H), radius=H // 2, fill=0)
cx += 3 * H + INTRA
return img
def main() -> int:
parser = argparse.ArgumentParser(description="Print a message in Morse code on the S01 thermal printer.")
parser.add_argument("--text", default=None, help="Message to encode (default: random phrase).")
parser.add_argument("--no-key", action="store_true", help="Skip the A-Z reference key.")
parser.add_argument("--out", type=Path, default=ROOT / "morse.png")
parser.add_argument("--darkness", type=int, choices=range(1, 6), default=3)
parser.add_argument("--bottom-feed", type=int, default=24)
parser.add_argument("--no-print", action="store_true")
args = parser.parse_args()
text = args.text or random.choice(PHRASES)
print(f"Encoding: {text}")
card = Card()
card.title("MORSE CODE")
card.para(text.upper(), size=17, bold=True, center=True)
card.gap(6).image(render_morse(text, card.inner_w), border=False)
if not args.no_key:
card.gap(6).divider().line("KEY", size=13, bold=True, center=True)
letters = [(c, MORSE[c]) for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
width = 13
for i in range(0, len(letters), 3):
row = "".join(f"{c} {code}".ljust(width) for c, code in letters[i:i + 3])
card.line(row.rstrip(), size=13, bold=False)
card.footer("morse code", "- . -")
return card.finish(args.out, args.bottom_feed, args.darkness, do_print=not args.no_print)
if __name__ == "__main__":
raise SystemExit(main())