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 <noreply@anthropic.com>master
parent
796b1c4830
commit
a7d5b9d1bc
|
|
@ -81,8 +81,8 @@ class Config:
|
||||||
self.flip_y = as_bool(ascii_.get("FLIP_Y"))
|
self.flip_y = as_bool(ascii_.get("FLIP_Y"))
|
||||||
|
|
||||||
self.printer_a4 = as_bool(printer.get("PRINTER_A4"))
|
self.printer_a4 = as_bool(printer.get("PRINTER_A4"))
|
||||||
self.printer_cpi = float(printer.get("PRINTER_CPI", "10") or 10)
|
self.printer_max_lines = int(printer.get("PRINTER_MAX_LINES", "64") or 64)
|
||||||
self.printer_lpi = float(printer.get("PRINTER_LPI", "6") or 6)
|
self.printer_max_cols = int(printer.get("PRINTER_MAX_COLS", "54") or 54)
|
||||||
|
|
||||||
self.key_capture = keys.get("KEY_CAPTURE", " ")
|
self.key_capture = keys.get("KEY_CAPTURE", " ")
|
||||||
self.key_brightness_up = keys.get("KEY_BRIGHTNESS_UP", "+")
|
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
|
return "space" if cfg.key_capture == " " else cfg.key_capture
|
||||||
|
|
||||||
|
|
||||||
_A4_LONG_MM = 297.0
|
def a4_landscape_chars(max_lines, max_cols):
|
||||||
_A4_SHORT_MM = 210.0
|
|
||||||
_MM_PER_IN = 25.4
|
|
||||||
_PRINT_MARGIN_IN = 0.5
|
|
||||||
|
|
||||||
|
|
||||||
def a4_landscape_chars(cpi, lpi):
|
|
||||||
"""(cols, rows) to capture/preview for an A4 landscape printout.
|
"""(cols, rows) to capture/preview for an A4 landscape printout.
|
||||||
|
|
||||||
txt2printr.sh prints on a normally-fed (portrait) page and rotates the
|
txt2printr.sh prints on a normally-fed (portrait) page and rotates the
|
||||||
ascii art 90 degrees in software; the reader turns the finished sheet
|
ascii art 90 degrees in software; the reader turns the finished sheet
|
||||||
90 degrees to view it. That second turn cancels the software rotation,
|
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
|
so this buffer's own dimensions equal the final visual result - but its
|
||||||
width becomes the printed *line count* after rotation, which must fit
|
width becomes the printed *line count* after rotation (bounded by
|
||||||
within one page's line capacity along the long (feed) edge. Height is
|
max_lines, the page's real per-page line capacity) and its height
|
||||||
then derived from the target landscape aspect ratio, corrected for
|
becomes each printed line's length (bounded by max_cols, the real
|
||||||
non-square character cells (cells are cpi/lpi times taller than wide),
|
per-line character capacity). Both are measured directly against the
|
||||||
so the final printout keeps true A4 proportions instead of just filling
|
printer with pagetest.sh rather than derived from paper/pitch math,
|
||||||
however many character cells happen to fit.
|
which doesn't reliably match real-world margins.
|
||||||
"""
|
"""
|
||||||
long_in = _A4_LONG_MM / _MM_PER_IN
|
return max_lines, max_cols
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def box_dims_for(term_rows, term_cols, a4_target):
|
def box_dims_for(term_rows, term_cols, a4_target):
|
||||||
|
|
@ -216,7 +203,7 @@ def main(stdscr):
|
||||||
cfg = Config()
|
cfg = Config()
|
||||||
conv_flags = cfg.converter_flags()
|
conv_flags = cfg.converter_flags()
|
||||||
a4_target = (
|
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
|
if cfg.printer_a4 else None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
14
printer.conf
14
printer.conf
|
|
@ -13,7 +13,13 @@
|
||||||
# see in the preview matches the shape of what gets printed
|
# see in the preview matches the shape of what gets printed
|
||||||
PRINTER_A4=false
|
PRINTER_A4=false
|
||||||
|
|
||||||
# Printer pitch, used only to size the A4 viewfinder above (characters per
|
# Your printer's real per-page capacity in the normal (portrait, unrotated)
|
||||||
# inch / lines per inch). Defaults match common Epson ESC/P draft settings.
|
# orientation, used to size the A4 viewfinder above and to know when a print
|
||||||
PRINTER_CPI=10
|
# job already fills the page (see txt2printr.sh). Paper geometry and stated
|
||||||
PRINTER_LPI=6
|
# 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
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@
|
||||||
#
|
#
|
||||||
# Usage: ./txt2printr.sh [ascii-art.txt]
|
# Usage: ./txt2printr.sh [ascii-art.txt]
|
||||||
# Env: PRINTER_DEV - printer device node (default: /dev/lp0)
|
# 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")"
|
dir="$(dirname "$0")"
|
||||||
[ -f "$dir/printer.conf" ] && source "$dir/printer.conf"
|
[ -f "$dir/printer.conf" ] && source "$dir/printer.conf"
|
||||||
: "${PRINTER_A4:=false}"
|
: "${PRINTER_A4:=false}"
|
||||||
|
: "${PRINTER_MAX_LINES:=64}"
|
||||||
|
|
||||||
infile="${1:-ascii-img.txt}"
|
infile="${1:-ascii-img.txt}"
|
||||||
# Source - https://stackoverflow.com/a/638980
|
# Source - https://stackoverflow.com/a/638980
|
||||||
|
|
@ -57,12 +59,23 @@ rotate90() {
|
||||||
' "$infile"
|
' "$infile"
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
body() {
|
||||||
printf '\x1b\x40' # ESC @ - reset printer (ESC/P and IBM Proprinter compatible)
|
|
||||||
if [ "$PRINTER_A4" = "true" ]; then
|
if [ "$PRINTER_A4" = "true" ]; then
|
||||||
rotate90 | sed 's/$/\r/' # CRLF line endings, needed for raw writes to avoid staircasing
|
rotate90
|
||||||
else
|
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
|
fi
|
||||||
printf '\x0c' # form feed - eject the page
|
|
||||||
} > "$dev"
|
} > "$dev"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue