91 lines
3.1 KiB
Bash
Executable File
91 lines
3.1 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Sends an ascii-art text file to a parallel port needle/dot-matrix printer.
|
|
#
|
|
# Usage: ./txt2printr.sh [ascii-art.txt]
|
|
# Env: PRINTER_DEV - printer device node (default: /dev/lp0)
|
|
# ALREADY_ROTATED - skip the text-rotation below because the caller
|
|
# already rotated the source image itself before
|
|
# converting it to ascii (photobooth.py does this
|
|
# for better quality; set by it automatically)
|
|
# 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}"
|
|
: "${ALREADY_ROTATED:=false}"
|
|
|
|
infile="${1:-ascii-img.txt}"
|
|
# Source - https://stackoverflow.com/a/638980
|
|
# Posted by John Feminella, modified by community. See post 'Timeline' for change history
|
|
# Retrieved 2026-07-14, License - CC BY-SA 4.0
|
|
|
|
if [ -n "$PRINTER_DEV" ]; then
|
|
dev="$PRINTER_DEV"
|
|
elif [ -e /dev/lp0 ]; then
|
|
dev=/dev/lp0
|
|
elif [ -e /dev/usb/lp0 ]; then
|
|
dev=/dev/usb/lp0
|
|
else
|
|
dev=/dev/stdout
|
|
fi
|
|
|
|
if [ ! -f "$infile" ]; then
|
|
echo "txt2printr: file not found: $infile" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -w "$dev" ]; then
|
|
echo "txt2printr: cannot write to printer device: $dev" >&2
|
|
echo "txt2printr: set PRINTER_DEV to override, or check permissions/parport module" >&2
|
|
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 a fallback for callers (e.g. the
|
|
# bash webcam2ascii.sh/exec-cycle.sh pipeline) that can't rotate the source
|
|
# image itself first. Rearranging already-rendered ascii characters ignores
|
|
# non-square character cells and reads as distorted, so photobooth.py instead
|
|
# rotates the source image before conversion and sets ALREADY_ROTATED to
|
|
# skip this.
|
|
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"
|
|
}
|
|
|
|
body() {
|
|
if [ "$PRINTER_A4" = "true" ] && [ "$ALREADY_ROTATED" != "true" ]; then
|
|
rotate90
|
|
else
|
|
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
|
|
} > "$dev"
|