How to control the page parameters (margins, brochurisation) of `man -t` PostScript output?
An awesome shell script written some time ago by a friend: livre
.
You'll be interested in the --book
and --inner
options.
#!/bin/sh
#---------------
# A parametrized replacement for psnup -2 using pstops.
#
# The script computes bounding boxes using gs and deduces optimized reductions
# on two pages per sheet with given margins or scaling. Pages can be arranged
# for various kinds of folding or binding.
#---------------
# Requires: gs, bc, pstops, psbook, pdftops
#---------------
VERSION=2009-12-02
# Output parameters
PAPER=a4
WIDTH=597 # 210mm
HEIGHT=845 # 297mm
MARGIN=30
INNER=1
SCALE=
TWO=false
BIND=top
BBRANGE=-
SIG=
IN=
OUT=
DASHQ=-q
VERBOSE=false
BB_ODD=
BB_EVEN=
# Parse the command line
while [ $# -gt 0 ]; do
case "$1" in
--help)
cat <<EOF
usage: livre.sh [options] input output
The input can be in PostScript or PDF, possibly gzipped.
options:
--margin SIZE compute scaling to get SIZE-point margins (default: 30)
--scale FACTOR use the given scaling FACTOR (overrides --margin)
--inner FACTOR set inner margin to FACTOR times the outer one (default: 1)
--two input is two-sided
--top output should be bound at the top (default)
--left output should be bound on the left
--book output should be folded into a booklet
--sig N select the signature for psbook (implies --book)
--bbrange PAGES only use the specified PAGES for bounding box computation
--bbox BBOX provide the bounding box explictly, disable its computation
(use this twice if the input is two-sided)
--verbose do not use quiet mode
--version print version number and exit
EOF
exit 0
;;
--version)
echo $VERSION
exit 0
;;
--margin)
shift
MARGIN="$1"
;;
--scale)
shift
SCALE="$1"
;;
--inner)
shift
INNER="$1"
;;
--two*)
TWO=true
;;
--top|--left|--book)
BIND=${1#--}
;;
--sig)
shift
SIG="-s$1"
BIND=book
;;
--bbrange)
shift
BBRANGE="$1"
;;
--bbox)
shift
if [ -z "$BB_ODD" ]; then
BB_ODD="$1"
else
TWO=true
BB_EVEN="$1"
fi
;;
--verbose)
DASHQ=
VERBOSE=true
;;
-*)
echo "unknown option: $1" >&2
exit 1
;;
*)
if [ -z "$IN" ]
then IN="$1"
elif [ -z "$OUT" ]
then OUT="$1"
else echo "unused argument: $1" >&2
fi
esac
shift
done
if [ -z "$IN" ]; then
echo "missing input file" >&2
exit 1
fi
# Make a teporary file if needed
TMP=
make_ps ()
{
case $(file -bL "$IN") in
"PostScript document"*)
;;
"PDF document"*)
$VERBOSE && echo "converting to PS..." >&2
TMP2=$(mktemp)
pdftops "$IN" "$TMP2"
test -n "$TMP" && rm "$TMP"
TMP="$TMP2"
IN="$TMP"
;;
"gzip compressed "*)
$VERBOSE && echo "unzipping..." >&2
TMP2=$(mktemp)
gunzip < "$IN" > "$TMP2"
test -n "$TMP" && rm "$TMP"
TMP="$TMP2"
IN="$TMP"
make_ps
;;
*)
echo "Unknown file type!" >&2
exit 1
esac
}
make_ps
# Extract the bounding box for all pages of a given file.
read_bbox()
{
gs -sDEVICE=bbox -sPAPERSIZE=$PAPER -r300x300 -q -dBATCH -dNOPAUSE "$1" 2>&1 | awk '
function min(x,y) { if (x < y) return x; else return y }
function max(x,y) { if (x > y) return x; else return y }
BEGIN {
left = top = 10000;
right = bottom = 0
}
/%%BoundingBox:/ {
left = min(left, $2);
top = min(top, $3);
right = max(right, $4);
bottom = max(bottom, $5);
}
END { print left, top, right, bottom }
'
}
# Compute the maximum scaling factor given the bounding box
max_scale()
{
bc <<EOF
scale = 3
hfactor = (($HEIGHT - (2 + $INNER) * $MARGIN) / 2) / ($3 - $1)
vfactor = ($WIDTH - 2 * $MARGIN) / ($4 - $2)
if (hfactor < vfactor) print hfactor else print vfactor
EOF
}
# Make a pstops specification
spec_left()
{
bc <<EOF
scale = 3
factor = $1
shift_x = $WIDTH / 2 + ($3 + $5) * factor / 2
vmargin = ($HEIGHT - 2 * ($4 - $2) * factor) / (2 + $INNER)
shift_y = vmargin - $2 * factor + $6 * (($4 - $2) * factor + $INNER * vmargin)
print "L@", factor, "(", shift_x, ",", shift_y, ")"
EOF
}
spec_right()
{
bc <<EOF
scale = 3
factor = $1
shift_x = $WIDTH / 2 - ($3 + $5) * factor / 2
vmargin = ($HEIGHT - 2 * ($4 - $2) * factor) / (2 + $INNER)
shift_y = vmargin + $4 * factor + $6 * (($4 - $2) * factor + $INNER * vmargin)
print "R@", factor, "(", shift_x, ",", shift_y, ")"
EOF
}
# Compute the bounding boxes for even and odd pages
if [ -z "$BB_ODD" ]; then
$VERBOSE && echo "computing the bounding box..." >&2
if $TWO; then
BB_ODD=$(psselect -o -p"$BBRANGE" "$IN" 2>/dev/null | read_bbox -)
BB_EVEN=$(psselect -e -p"$BBRANGE" "$IN" 2>/dev/null | read_bbox -)
else
if [ "$BBRANGE" = "-" ]; then
BB_ODD=$(read_bbox "$IN")
else
BB_ODD=$(psselect -p"$BBRANGE" "$IN" 2>/dev/null | read_bbox -)
fi
fi
fi
test -z "$BB_EVEN" && BB_EVEN="$BB_ODD"
if $VERBOSE; then
if $TWO; then
echo "bounding box (odd): $BB_ODD"
echo "bounding box (even): $BB_ODD"
else
echo "bounding box: $BB_ODD"
fi
fi
# Deduce the scaling factor if needed
if [ -z "$SCALE" ]; then
if $TWO; then
SCALE=$(bc <<EOF
scale=3
s1=$(max_scale $BB_ODD)
s2=$(max_scale $BB_EVEN)
if (s1 < s2) print s1 else print s2
EOF
)
else
SCALE=$(max_scale $BB_ODD)
fi
fi
$VERBOSE && echo "scale: $SCALE" >&2
# Process the file according to the chosen style
command()
{
$VERBOSE && echo "-- $*"
$*
}
case $BIND in
top)
command pstops $DASHQ -p$PAPER "2:\
0$(spec_left $SCALE $BB_ODD 0)+1$(spec_left $SCALE $BB_EVEN 1)" "$IN" "$OUT"
;;
left)
command pstops $DASHQ -p$PAPER "4:\
0$(spec_left $SCALE $BB_ODD 0)+1$(spec_left $SCALE $BB_EVEN 1),\
2$(spec_right $SCALE $BB_ODD 1)+3$(spec_right $SCALE $BB_EVEN 0)" "$IN" "$OUT"
;;
book)
psbook $DASHQ $SIG $IN | command pstops $DASHQ -p$PAPER "4:\
0$(spec_left $SCALE $BB_EVEN 0)+1$(spec_left $SCALE $BB_ODD 1),\
2$(spec_right $SCALE $BB_EVEN 1)+3$(spec_right $SCALE $BB_ODD 0)" /dev/stdin "$OUT"
esac
test -n "$TMP" && rm "$TMP" || true