feat: add PRINTER_A4 landscape option for A4 printers
Dot-matrix printers have no hardware page-rotation, so when PRINTER_A4 is enabled in the new printer.conf, txt2printr.sh rotates the ascii art 90 degrees in software before sending it, and photobooth.py caps its live-preview viewfinder to an A4-landscape character grid (sized from configurable PRINTER_CPI/PRINTER_LPI) instead of just filling the terminal, so the preview matches what actually gets printed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>master
parent
9d6fa2833f
commit
07cf695840
|
|
@ -55,6 +55,7 @@ class Config:
|
|||
webcam = load_conf("webcam.conf")
|
||||
ascii_ = load_conf("ascii.conf")
|
||||
keys = load_conf("keybinds.conf")
|
||||
printer = load_conf("printer.conf")
|
||||
|
||||
self.device = webcam.get("DEVICE", "/dev/video0")
|
||||
w, _, h = webcam.get("RESOLUTION", "640x480").partition("x")
|
||||
|
|
@ -79,6 +80,10 @@ class Config:
|
|||
self.flip_x = as_bool(ascii_.get("FLIP_X"))
|
||||
self.flip_y = as_bool(ascii_.get("FLIP_Y"))
|
||||
|
||||
self.printer_a4 = as_bool(printer.get("PRINTER_A4"))
|
||||
self.printer_cpi = float(printer.get("PRINTER_CPI", "10") or 10)
|
||||
self.printer_lpi = float(printer.get("PRINTER_LPI", "6") or 6)
|
||||
|
||||
self.key_capture = keys.get("KEY_CAPTURE", " ")
|
||||
self.key_brightness_up = keys.get("KEY_BRIGHTNESS_UP", "+")
|
||||
self.key_brightness_down = keys.get("KEY_BRIGHTNESS_DOWN", "-")
|
||||
|
|
@ -168,9 +173,37 @@ def capture_label(cfg):
|
|||
return "space" if cfg.key_capture == " " else cfg.key_capture
|
||||
|
||||
|
||||
_A4_LONG_MM = 297.0
|
||||
_A4_SHORT_MM = 210.0
|
||||
_MM_PER_IN = 25.4
|
||||
_PRINT_MARGIN_IN = 0.5
|
||||
|
||||
|
||||
def a4_landscape_chars(cpi, lpi):
|
||||
"""(cols, rows) of an A4 sheet printed sideways, at the given pitch."""
|
||||
long_in = _A4_LONG_MM / _MM_PER_IN
|
||||
short_in = _A4_SHORT_MM / _MM_PER_IN
|
||||
cols = max(1, round((long_in - 2 * _PRINT_MARGIN_IN) * cpi))
|
||||
rows = max(1, round((short_in - 2 * _PRINT_MARGIN_IN) * lpi))
|
||||
return cols, rows
|
||||
|
||||
|
||||
def box_dims_for(term_rows, term_cols, a4_target):
|
||||
box_rows, box_cols = max(term_rows - 2, 3), max(term_cols, 10)
|
||||
if a4_target:
|
||||
a4_cols, a4_rows = a4_target
|
||||
box_rows = min(box_rows, a4_rows + 2)
|
||||
box_cols = min(box_cols, a4_cols + 2)
|
||||
return box_rows, box_cols
|
||||
|
||||
|
||||
def main(stdscr):
|
||||
cfg = Config()
|
||||
conv_flags = cfg.converter_flags()
|
||||
a4_target = (
|
||||
a4_landscape_chars(cfg.printer_cpi, cfg.printer_lpi)
|
||||
if cfg.printer_a4 else None
|
||||
)
|
||||
|
||||
curses.curs_set(0)
|
||||
stdscr.nodelay(True)
|
||||
|
|
@ -190,7 +223,7 @@ def main(stdscr):
|
|||
frame_times = []
|
||||
message, message_until = "", 0.0
|
||||
rows, cols = stdscr.getmaxyx()
|
||||
box_dims = (max(rows - 2, 3), max(cols, 10))
|
||||
box_dims = box_dims_for(rows, cols, a4_target)
|
||||
box_win = curses.newwin(box_dims[0], box_dims[1], 0, 0)
|
||||
|
||||
try:
|
||||
|
|
@ -210,7 +243,7 @@ def main(stdscr):
|
|||
jpg_bytes = buf.tobytes()
|
||||
|
||||
rows, cols = stdscr.getmaxyx()
|
||||
box_rows, box_cols = max(rows - 2, 3), max(cols, 10)
|
||||
box_rows, box_cols = box_dims_for(rows, cols, a4_target)
|
||||
inner_rows, inner_cols = max(box_rows - 2, 1), max(box_cols - 2, 1)
|
||||
|
||||
if (box_rows, box_cols) != box_dims:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
# ASCII Photobooth printer configuration
|
||||
# Sourced by txt2printr.sh and photobooth.py.
|
||||
|
||||
# Is the printer loaded with A4 paper for a landscape printout? (true/false)
|
||||
# Needle/dot-matrix printers have no hardware page-rotation command: the
|
||||
# print head only scans across a fixed carriage width while the paper feeds
|
||||
# in one fixed direction, so there is no way to make the physical page
|
||||
# itself "landscape". Instead, when this is true:
|
||||
# - txt2printr.sh rotates the ascii art 90 degrees in software before
|
||||
# sending it to the printer (turn the printed page 90 degrees to read it)
|
||||
# - photobooth.py sizes its live-preview viewfinder to an A4-landscape
|
||||
# character grid instead of just following the terminal size, so what you
|
||||
# see in the preview matches the shape of what gets printed
|
||||
PRINTER_A4=false
|
||||
|
||||
# Printer pitch, used only to size the A4 viewfinder above (characters per
|
||||
# inch / lines per inch). Defaults match common Epson ESC/P draft settings.
|
||||
PRINTER_CPI=10
|
||||
PRINTER_LPI=6
|
||||
|
|
@ -4,6 +4,11 @@
|
|||
#
|
||||
# Usage: ./txt2printr.sh [ascii-art.txt]
|
||||
# Env: PRINTER_DEV - printer device node (default: /dev/lp0)
|
||||
# Reads printer.conf for PRINTER_A4 (landscape rotation).
|
||||
|
||||
dir="$(dirname "$0")"
|
||||
[ -f "$dir/printer.conf" ] && source "$dir/printer.conf"
|
||||
: "${PRINTER_A4:=false}"
|
||||
|
||||
infile="${1:-ascii-img.txt}"
|
||||
# Source - https://stackoverflow.com/a/638980
|
||||
|
|
@ -31,8 +36,33 @@ if [ ! -w "$dev" ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# Rotates the ascii art 90 degrees clockwise so it reads correctly once the
|
||||
# printed page itself is turned 90 degrees counter-clockwise - the printer's
|
||||
# scan/feed directions are fixed, so this is the only way to get a landscape
|
||||
# reading orientation out of it.
|
||||
rotate90() {
|
||||
awk '
|
||||
{ if (length($0) > maxlen) maxlen = length($0); lines[NR] = $0 }
|
||||
END {
|
||||
for (c = 1; c <= maxlen; c++) {
|
||||
row = ""
|
||||
for (r = NR; r >= 1; r--) {
|
||||
ch = substr(lines[r], c, 1)
|
||||
if (ch == "") ch = " "
|
||||
row = row ch
|
||||
}
|
||||
print row
|
||||
}
|
||||
}
|
||||
' "$infile"
|
||||
}
|
||||
|
||||
{
|
||||
printf '\x1b\x40' # ESC @ - reset printer (ESC/P and IBM Proprinter compatible)
|
||||
sed 's/$/\r/' "$infile" # CRLF line endings, needed for raw writes to avoid staircasing
|
||||
printf '\x0c' # form feed - eject the page
|
||||
printf '\x1b\x40' # ESC @ - reset printer (ESC/P and IBM Proprinter compatible)
|
||||
if [ "$PRINTER_A4" = "true" ]; then
|
||||
rotate90 | sed 's/$/\r/' # CRLF line endings, needed for raw writes to avoid staircasing
|
||||
else
|
||||
sed 's/$/\r/' "$infile"
|
||||
fi
|
||||
printf '\x0c' # form feed - eject the page
|
||||
} > "$dev"
|
||||
|
|
|
|||
Loading…
Reference in New Issue