From a7d5b9d1bcc9524bd2fc08a09db4ac6d9229af7e Mon Sep 17 00:00:00 2001 From: The_miro Date: Tue, 14 Jul 2026 09:59:06 +0200 Subject: [PATCH] fix: use measured page capacity instead of derived CPI/LPI geometry Real-world testing (pagetest.sh) showed the printer's actual per-page line/column capacity didn't match what the A4-geometry math predicted, and the redundant blank second page was traced to the printer auto-advancing to a new page once content hits the bottom margin, with our own unconditional trailing form-feed then ejecting that already-started blank page on top of it. Replace PRINTER_CPI/PRINTER_LPI with directly-measured PRINTER_MAX_LINES/PRINTER_MAX_COLS in printer.conf (read via pagetest.sh), and have txt2printr.sh skip the trailing form-feed whenever the print job already reaches that line capacity. Co-Authored-By: Claude Sonnet 5 --- photobooth.py | 35 +++++++++++------------------------ printer.conf | 14 ++++++++++---- txt2printr.sh | 25 +++++++++++++++++++------ 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/photobooth.py b/photobooth.py index 723ad0c..8fb5634 100755 --- a/photobooth.py +++ b/photobooth.py @@ -81,8 +81,8 @@ class Config: 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.printer_max_lines = int(printer.get("PRINTER_MAX_LINES", "64") or 64) + self.printer_max_cols = int(printer.get("PRINTER_MAX_COLS", "54") or 54) self.key_capture = keys.get("KEY_CAPTURE", " ") self.key_brightness_up = keys.get("KEY_BRIGHTNESS_UP", "+") @@ -173,34 +173,21 @@ 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): +def a4_landscape_chars(max_lines, max_cols): """(cols, rows) to capture/preview for an A4 landscape printout. txt2printr.sh prints on a normally-fed (portrait) page and rotates the ascii art 90 degrees in software; the reader turns the finished sheet 90 degrees to view it. That second turn cancels the software rotation, so this buffer's own dimensions equal the final visual result - but its - width becomes the printed *line count* after rotation, which must fit - within one page's line capacity along the long (feed) edge. Height is - then derived from the target landscape aspect ratio, corrected for - non-square character cells (cells are cpi/lpi times taller than wide), - so the final printout keeps true A4 proportions instead of just filling - however many character cells happen to fit. + width becomes the printed *line count* after rotation (bounded by + max_lines, the page's real per-page line capacity) and its height + becomes each printed line's length (bounded by max_cols, the real + per-line character capacity). Both are measured directly against the + printer with pagetest.sh rather than derived from paper/pitch math, + which doesn't reliably match real-world margins. """ - long_in = _A4_LONG_MM / _MM_PER_IN - short_in = _A4_SHORT_MM / _MM_PER_IN - max_lines = max(1, round((long_in - 2 * _PRINT_MARGIN_IN) * lpi)) - max_chars = max(1, round((short_in - 2 * _PRINT_MARGIN_IN) * cpi)) - aspect = (long_in / short_in) * (cpi / lpi) - cols = max_lines - rows = max(1, min(max_chars, round(cols / aspect))) - return cols, rows + return max_lines, max_cols def box_dims_for(term_rows, term_cols, a4_target): @@ -216,7 +203,7 @@ def main(stdscr): cfg = Config() conv_flags = cfg.converter_flags() a4_target = ( - a4_landscape_chars(cfg.printer_cpi, cfg.printer_lpi) + a4_landscape_chars(cfg.printer_max_lines, cfg.printer_max_cols) if cfg.printer_a4 else None ) diff --git a/printer.conf b/printer.conf index 7d12b71..c5a61d8 100644 --- a/printer.conf +++ b/printer.conf @@ -13,7 +13,13 @@ # 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 +# Your printer's real per-page capacity in the normal (portrait, unrotated) +# orientation, used to size the A4 viewfinder above and to know when a print +# job already fills the page (see txt2printr.sh). Paper geometry and stated +# pitch don't reliably predict this - measure it directly with pagetest.sh: +# ./pagetest.sh && PRINTER_A4=false ./txt2printr.sh pagetest.txt +# then read off the last line number on page 1 (-> PRINTER_MAX_LINES) and +# how many characters of the 64-wide test lines actually printed before +# being cut off (-> PRINTER_MAX_COLS). +PRINTER_MAX_LINES=64 +PRINTER_MAX_COLS=54 diff --git a/txt2printr.sh b/txt2printr.sh index 42c33e5..1cd0112 100755 --- a/txt2printr.sh +++ b/txt2printr.sh @@ -4,11 +4,13 @@ # # Usage: ./txt2printr.sh [ascii-art.txt] # Env: PRINTER_DEV - printer device node (default: /dev/lp0) -# Reads printer.conf for PRINTER_A4 (landscape rotation). +# Reads printer.conf for PRINTER_A4 (landscape rotation) and PRINTER_MAX_LINES +# (per-page line capacity, measured with pagetest.sh). dir="$(dirname "$0")" [ -f "$dir/printer.conf" ] && source "$dir/printer.conf" : "${PRINTER_A4:=false}" +: "${PRINTER_MAX_LINES:=64}" infile="${1:-ascii-img.txt}" # Source - https://stackoverflow.com/a/638980 @@ -57,12 +59,23 @@ rotate90() { ' "$infile" } -{ - printf '\x1b\x40' # ESC @ - reset printer (ESC/P and IBM Proprinter compatible) +body() { if [ "$PRINTER_A4" = "true" ]; then - rotate90 | sed 's/$/\r/' # CRLF line endings, needed for raw writes to avoid staircasing + rotate90 else - sed 's/$/\r/' "$infile" + cat "$infile" + fi +} + +line_count=$(body | wc -l) + +{ + printf '\x1b\x40' # ESC @ - reset printer (ESC/P and IBM Proprinter compatible) + body | sed 's/$/\r/' # CRLF line endings, needed for raw writes to avoid staircasing + # Skip the form feed once the page is already full: printers commonly + # auto-advance to a new page as soon as content hits the bottom margin, + # so an explicit form feed on top of that just ejects a blank extra page. + if [ "$line_count" -lt "$PRINTER_MAX_LINES" ]; then + printf '\x0c' # form feed - eject the page fi - printf '\x0c' # form feed - eject the page } > "$dev"