
| Current Path : /bin/X11/ |
Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64 |
| Current File : //bin/X11/pdfxup |
#!/bin/bash
shopt -s extglob
shopt -s lastpipe
VERSION="1.50"
VDATE="2019/12/31"
## see release notes at the end of this file.
: ${GS=`which gs`}
if [ ! $? ]; then
echo "ghostscript not found; aborting.";
exit 1;
fi
: ${PDFLATEX=`which pdflatex`}
if [ ! $? ]; then
echo "pdflatex not found; aborting.";
exit 1;
fi
## default values for all options.
## Can be modified from command line
## For instance, run "VERB=4 pdfxup ..."
function defaultvalues()
{
: ${dfpdfxupCOLS=2}
: ${dfpdfxupROWS=1}
: ${dfpdfxupLANDSC=1}
: ${dfpdfxupPAP="a4"}
: ${dfpdfxupBOOKLET=0}
: ${dfpdfxupCLIP=1}
: ${dfpdfxupOUTF="pdfxup.pdf"}
: ${dfpdfxupIHM="5pt"}
: ${dfpdfxupIVM="5pt"}
: ${dfpdfxupIM="5pt"}
: ${dfpdfxupHM="5pt"}
: ${dfpdfxupVM="5pt"}
: ${dfpdfxupM="5pt"}
: ${dfpdfxupIHS="1pt"}
: ${dfpdfxupIVS="1pt"}
: ${dfpdfxupIS="1pt"}
: ${dfpdfxupFW=".4pt"}
: ${dfpdfxupPAGES="-"}
: ${dfpdfxupBB="-"}
: ${dfpdfxupNOBB=""}
: ${dfpdfxupKBB="0"}
: ${dfpdfxupGBB="0"}
: ${dfpdfxupVERB=1}
: ${dfpdfxupDEBUG=0}
: ${dfpdfxupWMPERIOD=1}
}
function usage()
{
defaultvalues;
echo "pdfxup: n-up pages of a PDF document, preserving readability
usage: `basename $0` [OPTIONS] file
Available OPTIONS are:
-x n n columns per page [default: \"$dfpdfxupCOLS\"]
-y n n lines per page [default: \"$dfpdfxupROWS\"]
-l [0|1] landscape-mode [default: \"$dfpdfxupLANDSC\"]
-b [0|1|le|se] booklet-mode [default: \"$dfpdfxupBOOKLET\"]
-c [0|1] clip pages to bounding box [default: \"$dfpdfxupCLIP\"]
-im n inner margins [default: \"$dfpdfxupIM\"]
-m n margins [default: \"$dfpdfxupM\"]
-is n interm. spaces [default: \"$dfpdfxupIS\"]
-fw n frame width [default: \"$dfpdfxupFW\"]
-o file write output to file [default: \"$dfpdfxupOUTF\"]
-p pages only include these pages [default: \"$dfpdfxupPAGES\" (all)]
-nobb pages pages to omit when computing b.box [default: \"$dfpdfxupNOBB\" (none)]
-bb pages pages to use for computing b.box [default: \"$dfpdfxupBB\" (all)]
-g [0|1] only computes bounding box [default: \"$dfpdfxupGBB\"]
-s x y X Y force bounding box [default: unset]
-V [0-3] select verbosity [default: \"$dfpdfxupVERB\"]
-w file add watermarking [default: none]
-wp n repeat last n pages of watermark file [default: \"$dfpdfxupWMPERIOD\"]
-i ask before overwriting/removing files
-d debug mode: keep intermediary files
-v show version number and exit";
##
## Some options are not presented, for the sake of brevity...
##
## -ihm n inner horizontal margin [default: \"$dfpdfxupIHM\"]
## -ivm n inner vertical margin [default: \"$dfpdfxupIVM\"]
## -hm n horizontal margin [default: \"$dfpdfxupHM\"]
## -vm n vertical margin [default: \"$dfpdfxupVM\"]
## -ihs n interm. horizontal space [detault: \"$dfpdfxupIHS\"]
## -ivs n interm. vertical space [detault: \"$dfpdfxupIVS\"]
## -kbb keep original bounding box [default: \"$dfpdfxupKBB\"]
## -ps s output paper size [default: \"$dfpdfxupPAP\"]
## -q run quietly (equiv. '-V=0')
## -h show this help message
##
##
##
exit 0;
}
function setdefaultvalues()
{
COLS=$dfpdfxupCOLS;
ROWS=$dfpdfxupROWS;
LANDSC=$dfpdfxupLANDSC;
BOOKLET=$dfpdfxupBOOKLET;
CLIP=$dfpdfxupCLIP;
PAP=$dfpdfxupPAP;
OUTF=$dfpdfxupOUTF
IHM=$dfpdfxupIHM;
IVM=$dfpdfxupIVM;
IM=$dfpdfxupIM;
HM=$dfpdfxupHM;
VM=$dfpdfxupVM;
M=$dfpdfxupM;
IHS=$dfpdfxupIHS;
IVS=$dfpdfxupIVS;
IS=$dfpdfxupIS;
FW=$dfpdfxupFW;
## don't overwrite VERB if set on command line
: ${VERB=$dfpdfxupVERB};
DEBUG=$dfpdfxupDEBUG;
WATERMARK="";
WATERMARKPERIOD=$dfpdfxupWMPERIOD;
KBB=$dfpdfxupKBB;
GBB=$dfpdfxupGBB;
SBB=0;
x0=-1
y0=-1
h0=-1
w0=-1
## the names for h and w should actually be X and Y: they are not width and height,
## but coordinates of upper right corner.
## Notice: PAGES, BB and NOBB will be set to default values if empty after
## processing options
}
## myecho handles several levels of verbosity
function myecho()
{
ECHO=0;
case $1 in
+([0-9])\+)
if [[ $VERB -ge ${1%+} ]]; then ECHO=1; fi
;;
+([0-9]))
if [[ $VERB -eq $1 ]]; then ECHO=1; fi
;;
+([0-9])-)
if [[ $VERB -le ${1%-} ]]; then ECHO=1; fi
;;
esac
if [[ $ECHO == 1 ]]; then
case $2 in
-*)
echo $2 "$3"
;;
*)
echo "$2"
;;
esac
fi
}
## function to debug option processing
function showopts()
{
if [[ OPTS -eq 0 ]]; then
OPTS=1;
fi
myecho 4+ " * $1"
}
## transforms given dimension (in cm, mm, in) in pt
function dimtopt()
{
dim=$1;
case $dim in
*pt)
;;
*mm)
dim=${dim%mm};
eval dim=$((dim*2845/1000))pt;
;;
*cm)
dim=${dim%cm};
eval dim=$((dim*2845/100))pt;
;;
*in)
dim=${dim%in};
eval dim=$((dim*7228/100))pt;
;;
*[!0-9]*)
## should not occur... has been filtered out by main 'case'
myecho 1+ " illegal unit of measure in option '$3'; ignoring";
dim=$2;
;;
*)
dim=${dim}pt;
;;
esac
}
## check valid unit for given dimension
function testdim()
{
dim=$1;
case $dim in
+([0-9])@(pt|in|cm|mm))
;;
+([0-9]))
dim=${dim}pt
;;
+([0-9])*)
echo " illegal unit of measure in option '$3'; ignoring";
dim=$2;
;;
*)
echo " not a valid dimension in option '$3'; ignoring";
dim=$2;
;;
esac
}
## sets variable $in to 1 if $1 is in list of ranges $2
function ifinrangelist()
{
n=$1;
list=$2;
in=0;
for i in ${list//,/$IFS}; do
case $i in
+([0-9]))
first=$i;
last=$i;;
-+([0-9]))
first=1;
last=`echo $i|tr -d -`;;
+([0-9])-)
first=`echo $i|tr -d -`;
last=$nbp;;
+([0-9])-+([0-9]))
first=`echo $i|cut -d- -f1`;
last=`echo $i|cut -d- -f2`;;
-)
first=1;
last=$nbp;;
*)
myecho 1+ " error in range of pages (option '$3' contains '$i')";
esac
if [[ $n -ge $first && $n -le $last ]]; then
in=1;
return;
fi
done
return;
}
## normalize list + count number of pages to be displayed
function cleancslor()
{
list=$1;
result="";
for i in ${list//,/$IFS}; do
case $i in
+([0-9]))
result+="$i,";
nbpages+=1;;
-+([0-9]))
result+="1$i,";
nbpages+=${i#-};;
+([0-9])-)
result+="$i$nbp,";
nbpages+=$(expr $nbp + 1 - ${i%-});;
+([0-9])-+([0-9]))
result+="$i,";
nbpages+=$(expr 1 + `echo $i|cut -d- -f2` - `echo $i|cut -d- -f1`);;
-)
result+="1-$nbp,";
nbpages+=$nbp;;
+([0-9])%+([0-9]))
## explicitly list all values...
## (simpler, but admitedly less efficient,
## than handling real modulos)
declare -i cptr;
cptr=`echo $i|cut -d% -f1`;
step=`echo $i|cut -d% -f2`;
while [[ $cptr -le $nbp ]]; do
result+="$cptr,";
nbpages+=1;
cptr+=$step;
done;;
*)
## anything else is discarded
;;
esac
done
}
ARGS=$@;
if [ $# -eq 0 ]; then
usage;
fi
defaultvalues;
setdefaultvalues;
filename="temp-pdfxup-`date +%s`";
OPTS=0;
## go through all arguments and options
myecho 4+ "-> processing options";
myecho 4+ " selected options: ";
while [ $# != 0 ]; do
case $1 in
-x|--columns)
COLS=$2;
showopts "columns=$COLS";
shift 2;;
-x?(=)+([0-9]))
COLS=`echo $1|sed -re "s/-x=?//"`;
showopts "columns=$COLS";
shift;;
-y|--rows)
ROWS=$2;
showopts "rows=$ROWS";
shift 2;;
-y?(=)+([0-9]))
ROWS=`echo $1|sed -re "s/-y=?//"`;
showopts "rows=$ROWS";
shift;;
-l|--landscape)
case $2 in
1|yes|y|true)
LANDSC=1;
SHIFT=2;
;;
0|no|n|false)
LANDSC=0;
SHIFT=2;
;;
-*)
LANDSC=1;
SHIFT=1;
;;
*)
LANDSC=1;
#echo "Normal use of '$1' option is: '$1 [0|1]'";
#echo "Assuming you want landscape outupt...";
SHIFT=1;
esac
if [[ $LANDSC -eq 1 ]]; then
showopts "landscape=true";
else
showopts "landscape=false";
fi
shift $SHIFT;;
-l*)
ANS=`echo $1|sed -re "s/-l=?//"`;
case $ANS in
1|yes|y|true)
LANDSC=1;
;;
0|no|n|false)
LANDSC=0;
;;
*)
LANDSC=1;
#echo "Normal use of '$1' option is: '$1 [0|1]'";
#echo "Assuming you want landscape outupt...";
esac
if [[ $LANDSC -eq 1 ]]; then
showopts "landscape=true";
else
showopts "landscape=false";
fi
shift;;
-nl|--portrait|--no-landscape|--nolandscape)
LANDSC=0;
showopts "landscape=false";
shift;;
-b|--booklet)
case $2 in
se|short-edge)
BOOKLET="se";
SHIFT=2;
;;
1|yes|y|true|le|long-edge)
BOOKLET=1;
SHIFT=2;
;;
0|no|n|false)
BOOKLET=0;
SHIFT=2;
;;
-*)
BOOKLET=1;
SHIFT=1;
;;
*)
BOOKLET=1;
#echo "Normal use of '$1' option is: '$1 [0|1]'";
#echo "Assuming you want booklet outupt...";
SHIFT=1;
esac
if [[ $BOOKLET != 0 ]]; then
FW=0pt
# this is the default, but can be changed by passing -fw option
fi
if [[ $BOOKLET -eq 1 ]]; then
showopts "booklet (long-edge)";
else if [[ $BOOKLET -eq "se" ]]; then
showopts "booklet (short edge)";
fi
fi
shift $SHIFT;;
-b[^b]*|--booklet*)
ANS=`echo $1|sed -re "s/--?b(ooklet)?=?//"`;
case $ANS in
se|short-edge)
BOOKLET="se";
;;
1|yes|y|true|le|long-edge)
BOOKLET=1;
;;
0|no|n|false)
BOOKLET=0;
;;
*)
BOOKLET=1;
#echo "Normal use of '$1' option is: '$1 [0|1]'";
#echo "Assuming you want booklet outupt...";
esac
if [[ $BOOKLET != 0 ]]; then
FW=0pt
# this is the default, but can be changed by passing -fw option
fi
if [[ $BOOKLET -eq 1 ]]; then
showopts "booklet (long-edge)";
else if [[ $BOOKLET -eq "se" ]]; then
showopts "booklet (short edge)";
fi
fi
shift;;
-c|--clip)
case $2 in
1|yes|y|true)
CLIP=1;
SHIFT=2;
;;
0|no|n|false)
CLIP=0;
SHIFT=2;
;;
*)
CLIP=1;
SHIFT=1;
esac
if [[ $CLIP -eq 1 ]]; then
showopts "clip=true";
else
showopts "clip=false";
fi
shift $SHIFT;;
-c*|--clip=*)
ANS=`echo $1|sed -re "s/--?c(lip)?=?//"`;
case $ANS in
1|yes|y|true)
CLIP=1;
;;
0|no|n|false)
CLIP=0;
;;
esac
if [[ $CLIP -eq 1 ]]; then
showopts "clip=true";
else
showopts "clip=false";
fi
shift;;
-ps|--paper|--paper-size)
PAP=$2;
showopts "paper size=$PAP";
shift 2;;
-ps=*|--paper=*|--paper-size=*)
## '=' is compulsory, as we expect a string...
ANS=`echo $1|sed -re "s/(-ps=|--paper=|--paper-size=)//"`;
PAP=$ANS;
showopts "paper size=$PAP";
shift;;
-p|--pages|--page)
PAGES+="$2,";
#showopts "pages=$PAGES";
shift 2;;
-p*|--page*)
ANS=`echo $1|sed -re "s/--?p(ages?)?=?//"`;
PAGES=+="$ANS,";
#showopts "pages=$PAGES";
shift;;
-o|--out|--output-file|--outfile)
OUTF=$2;
showopts "output file=$OUTF";
shift 2;;
-o*|--out=*|--output-file=*|--outfile=*)
ANS=`echo $1|sed -re "s/--?o(ut(put-)?(file)?)?=?//"`;
OUTF=$ANS;
showopts "output file=$OUTF";
shift;;
-ihm|--innerhmargin)
dimtopt $2 $dfpdfxupIHM "$1 $2";
IHM=$dim;
showopts "inner horizontal margin=$IHM";
shift 2;;
-ihm?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-ihm=?//"`;
dimtopt $ANS $dfpdfxupIHM $1;
IHM=$dim;
showopts "inner horizontal margin=$IHM";
shift;;
-ivm|--innervmargin)
dimtopt $2 $dfpdfxupIVM "$1 $2";
IVM=$dim;
showopts "inner vertical margin=$IVM";
shift 2;;
-ivm?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-ivm=?//"`;
dimtopt $ANS $dfpdfxupIVM $1;
IVM=$dim;
showopts "inner vertical margin=$IVM";
shift;;
-im|--innermargins)
dimtopt $2 $dfpdfxupIM "$1 $2";
IHM=$dim;
IVM=$dim;
showopts "inner margins=$IHM";
shift 2;;
-im?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-im=?//"`;
dimtopt $ANS $dfpdfxupIM $1;
IHM=$dim;
IVM=$dim;
showopts "inner margins=$IHM";
shift;;
-hm|--hmargin)
testdim $2 $dfpdfxupHM "$1 $2";
HM=$dim;
showopts "horizontal margin=$HM";
shift 2;;
-hm?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-hm=?//"`;
testdim $ANS $dfpdfxupHM $1;
HM=$dim;
showopts "horizontal margin=$HM";
shift;;
-vm|--vmargin)
testdim $2 $dfpdfxupVM "$1 $2";
VM=$dim;
showopts "vertical margin=$VM";
shift 2;;
-vm?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-vm=?//"`;
testdim $ANS $dfpdfxupVM $1;
VM=$dim;
showopts "vertical margin=$VM";
shift;;
-m|--margins)
testdim $2 $dfpdfxupM "$1 $2";
HM=$dim;
VM=$dim;
showopts "margins=$HM";
shift 2;;
-m?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-m=?//"`;
testdim $ANS $dfpdfxupM $1;
HM=$dim;
VM=$dim;
showopts "margins=$HM";
shift;;
-ihs|--inthspace)
testdim $2 $dfpdfxupIHS "$1 $2";
IHS=$dim;
showopts "horizontal space=$IHS";
shift 2;;
-ihs?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-ihs=?//"`;
testdim $ANS $dfpdfxupIHS $1;
IHS=$dim;
showopts "horizontal space=$IHS";
shift;;
-ivs|--intvspace)
testdim $2 $dfpdfxupIVS "$1 $2";
IVS=$dim;
showopts "vertical space=$IVS";
shift 2;;
-ivs?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-ivs=?//"`;
testdim $ANS $dfpdfxupIVS $1;
IVS=$dim;
showopts "vertical space=$IVS";
shift;;
-is|--intspaces)
testdim $2 $dfpdfxupIS "$1 $2";
IHS=$dim;
IVS=$dim;
showopts "space=$IHS";
shift 2;;
-is?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-is=?//"`;
testdim $ANS $dfpdfxupIS $1;
IHS=$dim;
IVS=$dim;
showopts "space=$IHS";
shift;;
-fw|--framewidth)
testdim $2 $dfpdfxupFW "$1 $2";
FW=$dim;
showopts "frame rule width=$FW";
shift 2;;
-fw?(=)+([0-9])*)
ANS=`echo $1|sed -re "s/-fw=?//"`;
testdim $ANS $dfpdfxupFW $1;
FW=$dim;
showopts "frame rule width=$FW";
shift;;
-i)
MVopt="-i";
RMopt="-i";
showopts "interactive clean up: true";
shift;;
-nobb|--nobb|-no-bb|--no-bb)
NOBB+="$2,";
shift 2;;
-nobb*|--no-bb*)
ANS=`echo $1|sed -re "s/--?no-?bb=?//"`;
NOBB+="$ANS,";
shift;;
-bb|--bb|--bounding-box)
BB+="$2,";
shift 2;;
-bb*|--bb*|--bounding-box)
ANS=`echo $1|sed -re "s/--?b(ounding-?)?b(ox)?=?//"`;
BB+="$ANS,";
shift;;
-kbb|--keepbb|--keep-bb|--original-bb)
case $2 in
1|yes|y|true)
KBB=1;
SHIFT=2;
;;
0|no|n|false)
KBB=0;
SHIFT=2;
;;
-*)
KBB=1;
SHIFT=1;
;;
*)
KBB=1;
SHIFT=1;
esac
if [[ $KBB -eq 1 ]]; then
showopts "keep original bounding box=true";
else
showopts "keep original bounding box=false";
fi
shift $SHIFT;;
-kbb*|--keepbb*|--keep-bb*|--original-bb*)
ANS=`echo $1|sed -re "s/--?(k(eep-?)?bb|orig[^=]*bb)=?//"`;
case $ANS in
1|yes|y|true)
KBB=1;
;;
0|no|n|false)
KBB=0;
;;
*)
KBB=1;
esac
if [[ $KBB -eq 1 ]]; then
showopts "keep original bounding box=true";
else
showopts "keep original bounding box=false";
fi
shift;;
-g|--get-bb|--getbb)
case $2 in
1|yes|y|true)
GBB=1;
SHIFT=2;
;;
0|no|n|false)
GBB=0;
SHIFT=2;
;;
-*)
GBB=1;
SHIFT=1;
;;
*)
GBB=1;
SHIFT=1;
esac
if [[ $GBB -eq 1 ]]; then
showopts "only compute bounding box=true";
else
showopts "only compute bounding box=false";
fi
shift $SHIFT;;
-g*|--get-bb=*|--getbb=*)
ANS=`echo $1|sed -re "s/--?g(etbb|et-bb)?=?//"`;
case $ANS in
1|yes|y|true)
GBB=1;
;;
0|no|n|false)
GBB=0;
;;
*)
GBB=1;
#echo "Normal use of '$1' option is: '$1 [0|1]'";
#echo "Assuming you want landscape outupt...";
esac
if [[ $GBB -eq 1 ]]; then
showopts "only compute bounding box=true";
else
showopts "only compute bounding box=false";
fi
shift;;
-s|--set-bb|--setbb)
case "$2$3$4$5" in
+([0-9]))
SBB=1;
BBX=$2;
BBY=$3;
BBW=$4;
BBH=$5;;
esac
showopts "bounding box set to $2 $3 $4 $5";
shift 5;;
-V)
case $2 in
@(0|1|2|3))
if [[ $VERB -lt $2 ]]; then
VERB=$2;
fi
SHIFT=2;;
*)
if [[ $VERB -lt 2 ]]; then
VERB=2;
fi
SHIFT=1;;
esac
shift $SHIFT;;
-V?(=)@(0|1|2|3))
if [[ $VERB -lt `echo $1|sed -re "s/-V=?//"` ]]; then
VERB=`echo $1|sed -re "s/-V=?//"`;
fi
shift;;
-V?(=)+([0-9]))
VERB=9;
shift;;
-VV)
if [[ $VERB -lt 2 ]]; then
VERB=2;
fi
shift;;
-VVV)
if [[ $VERB -lt 3 ]]; then
VERB=3;
fi
shift;;
-q|--quiet)
VERB=0;
shift;;
-w|--watermark|--watermark-file)
WATERMARK=$2;
showopts "watermarking with file $WATERMARK";
shift 2;;
-w=*|--watermark=*|--watermark-file=*)
ANS=`echo $1|sed -re "s/--?w[^=]*=//"`;
WATERMARK=$ANS;
showopts "watermarking with file $WATERMARK";
shift;;
-wp|--wperiod|--watermark-period)
WATERMARKPERIOD=$2;
showopts "watermarking period=$WATERMARKPERIOD";
shift 2;;
-wp=*|--wperiod=*|--watermark-period=*)
ANS=`echo $1|sed -re "s/--?w[^=]*=//"`;
WATERMARKPERIOD=$ANS;
showopts "watermarking period=$WATERMARKPERIOD";
shift;;
-v|--version)
echo "pdfxup version $VERSION (released $VDATE)";
exit 0;;
-d|--debug)
DEBUG=1;
shift;;
-*)
usage;;
*:+([0-9\-,\%]))
ARG=$1;
file=${ARG%:*};
PAGES+="${ARG#*:},";
## only one file is allowed, and no options
## should appear after the file name...
break;;
*)
file=$1;
## only one file is allowed, and no options
## should appear after the file name...
break;;
esac;
done
## this depends on verbosity, hence can only be announced *after* processing options...
myecho 3- "-> processing options";
## check input file
if [[ $file == "" ]]; then
echo "pdfxup error: no input file given; exiting.";
exit 0;
fi
if [[ ! -e $file ]]; then
echo "pdfxup error: file $file not found; exiting.";
exit 0;
fi
## get number of pages of input file
nbp=`$GS -sDEVICE=bbox -dNOPAUSE -dQUIET -c "($file) (r) file runpdfbegin pdfpagecount = quit"`
## now we can deal with ranges of pages (BB, NOBB, PAGES)
declare -i nbpages;
nbpages=0;
if [[ ${BB} != "" ]]; then
BB=${BB%,};
cleancslor $BB;
BB=${result%,};
showopts "use for bounding-box computation: "${BB};
else
if [[ ${PAGES} != "" ]]; then
BB=${PAGES%,};
cleancslor $BB;
BB=${result%,};
showopts "use for bounding-box computation: "${BB};
else
BB=$dfpdfxupBB;
fi
fi
if [[ ${NOBB} != "" ]]; then
NOBB=${NOBB%,};
cleancslor $NOBB;
NOBB=${result%,};
showopts "exclude from bounding-box computation: "${NOBB};
else
NOBB=$dfpdfxupNOBB;
fi
if [[ ${PAGES} != "" ]]; then
PAGES=${PAGES%,};
else
PAGES=$dfpdfxupPAGES;
fi
nbpages=0;
cleancslor $PAGES;
PAGES=${result%,};
showopts "pages to display: ${PAGES} (${nbpages} pages)";
## clipping option
if [[ $CLIP != 0 ]]; then
myecho 2+ " clipping pages (anything outside bounding box will be dropped)";
CLIPOPT=",clip";
else
myecho 2+ " not clipping pages (anything outside bounding box will be displayed)";
myecho 2+ " (pages may overlap)";
CLIPOPT="";
fi
## output file name
if [[ ! -e $file && `basename $file .pdf` == $file ]]; then
myecho 2+ " changing file name '$file' to '$file.pdf'";
file="$file.pdf";
fi;
## special case: if booklet, we force the numbers of rows and cols
if [[ $BOOKLET != 0 ]]; then
if [[ $COLS != 2 || $ROWS != 1 || $LANDSC == 0 ]]; then
echo " forcing booklet mode: 2 columns, 1 row, landscape mode";
COLS=2; ROWS=1; LANDSC=1;
fi
fi
## check watermarking file
nbwp=1; ## set even if no watemark
if [[ $WATERMARK != "" ]]; then
if [[ ! -e $WATERMARK ]]; then
myecho 1+ " pdfxup: watermarking file not found. Omiting watermarking."
else
myecho 2+ " * using file $WATERMARK for watermarking";
if [[ `file -b $WATERMARK | grep "PDF"` ]]; then
## get number of pages of WATERMARK (PDF) file
nbwp=`$GS -sDEVICE=bbox -dNOPAUSE -dQUIET -c "($WATERMARK) (r) file runpdfbegin pdfpagecount = quit"`
if [[ $WATERMARKPERIOD -gt $nbwp || $WATERMARKPERIOD -lt 1 ]]; then
WATERMARKPERIOD=$nbwp;
fi
fi
fi
fi
## start computing bounding box
x=$x0
y=$y0
w=$w0
h=$h0
curr=0
page=0
step=0
if [[ $KBB == 0 ]]; then
if [[ $SBB == 0 ]]; then
myecho 1+ -n "-> computing bounding box";
myecho 2+ "";
for r in ${BB//,/$IFS};
do
case $r in
+([0-9]))
first=$r;
last=$r;;
-+([0-9]))
first=1;
last=`echo $r|tr -d -`;;
+([0-9])-)
first=`echo $r|tr -d -`;
last=$nbp;;
+([0-9])-+([0-9]))
first=`echo $r|cut -d- -f1`;
last=`echo $r|cut -d- -f2`;;
-)
first=1;
last=$nbp;;
esac
myecho 2+ " * $GS -dNOPAUSE -dSAFER -dQUIET -dBATCH -dFirstPage=$first -dLastPage=$last -sDEVICE=bbox $file"
$GS -dNOPAUSE -dSAFER -dQUIET -dBATCH -dFirstPage=$first -dLastPage=$last -sDEVICE=bbox $file 2>&1 |
while IFS= read -r line; do
bbox=`echo $line | grep "%%BoundingBox" | sed "s/^.*Box: //"`;
if [[ $bbox != "" ]]; then
for i in `echo $line | grep "%%BoundingBox" | sed "s/^.*Box: //"`; do
if [[ $curr == 0 ]]; then
eval page=$(( page+1 ));
fi
case $curr in
0)
thisx=$i;
#if [[ $x -gt $i ]]; then x=$i; fi
;;
1)
thisy=$i;
#if [[ $y -gt $i ]]; then y=$i; fi
;;
2)
thisw=$i;
#if [[ $w -lt $i ]]; then w=$i; fi
;;
3)
thish=$i;
#if [[ $h -lt $i ]]; then h=$i; fi
ifinrangelist $page $NOBB;
if [ $in == 0 ]; then
eval step=$(( step+1 ));
if [[ $x -lt 0 || $x -gt $thisx && $thisx+$thisw -gt 0 ]]; then x=$thisx; fi
if [[ $y -lt 0 || $y -gt $thisy && $thisy+$thish -gt 0 ]]; then y=$thisy; fi
if [[ $w -lt 0 || $w -lt $thisw && $thisx+$thisw -gt 0 ]]; then w=$thisw; fi
if [[ $h -lt 0 || $h -lt $thish && $thisy+$thish -gt 0 ]]; then h=$thish; fi
myecho 1 -n "."
myecho 2 -ne " bbox: x=$x y=$y X=$w Y=$h (step $step) \\r";
myecho 3+ " bbox: x=$x y=$y X=$w Y=$h (step $step) ";
fi
;;
esac
eval curr=$(( (curr+1) % 4 ));
done
fi
done;
done;
else
x=$BBX;
y=$BBY;
w=$BBW;
h=$BBH;
fi
fi
EMPTYBB=$KBB;
if [[ $KBB == 0 && $x -eq $x0 &&
$y -eq $y0 &&
$h -eq $h0 &&
$w -eq $w0 ]]; then
myecho 1+ "";
myecho 1+ " * empty bounding box; keeping original margins";
EMPTYBB=1;
#exit 1;
fi
if [[ $SBB == 0 && $EMPTYBB == 0 ]]; then
myecho 1 -n "."
myecho 2+ -ne " bbox: x=$x y=$y X=$w Y=$h (final) \\r";
myecho 3+ "";
myecho 3+ -ne " (processed $page pages) \\r";
myecho 1+ "";
fi
if [[ $GBB != 0 ]]; then
myecho 1+ " final bounding box: x=$x y=$y X=$w Y=$h";
exit 0;
fi
## compute options to pass to \includegraphics
IHM=${IHM%pt};
IVM=${IVM%pt};
if [[ $EMPTYBB -eq 0 ]]; then
eval x=$((x-IHM))
eval y=$((y-IVM))
eval w=$((w+IHM))
eval h=$((h+IVM))
BBOPTION="viewport=$x $y $w $h";
else
BBOPTION="trim=-$IHM -$IVM -$IHM -$IVM";
fi
## start writing .tex file
cat > $filename.tex <<EOF
\newif\ifbooklet
\newif\iflongedge
EOF
case $BOOKLET in
0)
echo " \bookletfalse" >> $filename.tex;;
se)
echo " \booklettrue" >> $filename.tex
echo " \longedgefalse" >> $filename.tex;;
*)
echo " \booklettrue" >> $filename.tex
echo " \longedgetrue" >> $filename.tex;;
esac
cat >> $filename.tex <<EOF
\documentclass{article}
\usepackage[margin=0pt]{geometry}
\usepackage{graphicx}
\IfFileExists{grffile.sty}{\usepackage{grffile}}{}
\topskip=0pt
\makeatletter
%% \nthvalue#1#2 looks for #1-th value in list of intervals #2
\newcounter{result}%
\newif\iffound
\def\@parserange#1-#2-#3\@end#4\@end{%
\setcounter{result}{#4}%
\ifnum\value{result}=1\relax
\foundtrue
\setcounter{result}{#1}%
\else
\addtocounter{result}{-1}%
\ifx\relax#3\relax%% means that range contains no -
\else
\addtocounter{result}{#1}%
\ifnum#2<\value{result}\relax
\addtocounter{result}{-#2}%
\else
\foundtrue
\fi
\fi
\fi}
\def\parserange#1#2{\expandafter\@parserange#2-SINGLE-\@end#1\@end}
\def\@parsecsl#1,#2\@end#3\@end{%
\parserange{#3}{#1}%
\iffound\else
\ifx\relax#2\relax\else\@parsecsl#2\@end\value{result}\@end\fi\fi}
\def\nthvalue#1#2{\foundfalse\expandafter\@parsecsl#2,\@end#1\@end}
%%
\def\file{$file}
\def\pagelist{$PAGES}
\def\watermark{$WATERMARK}
\pdfximage{\file}
\parindent=0pt
\def\outputpaper{$PAP}
\def\outputlandscape{$LANDSC}
\def\nbhoriz{$COLS}
\def\nbvert{$ROWS}
\expandafter\geometry\expandafter{\outputpaper paper}
\ifnum\outputlandscape=1\relax\geometry{landscape}\fi
\newcounter{outpage}
\newcounter{lastpage}
%\setcounter{outpage}{\the\pdflastximagepages}
\setcounter{outpage}{$nbpages}
\addtocounter{outpage}{-1}
\divide\c@outpage by \nbhoriz
\divide\c@outpage by \nbvert
\ifbooklet
\divide\c@outpage by 2
\fi
\stepcounter{outpage}
\ifbooklet
\multiply\c@outpage by 2
\fi
\setcounter{lastpage}{\value{outpage}}
\multiply\c@lastpage by \nbhoriz
\multiply\c@lastpage by \nbvert
%\showthe\c@outpage
\makeatother
%
\newlength\outputvmargin
\newlength\outputhmargin
\setlength\outputvmargin{$VM}
\setlength\outputhmargin{$HM}
\newlength\outputindivvmargin
\newlength\outputindivhmargin
\setlength\outputindivvmargin{$IVS}
\setlength\outputindivhmargin{$IHS}
%
\fboxsep=0pt%
\setlength\fboxrule{$FW}
\newlength\hresult
\newlength\vresult
\hresult=\paperwidth
\advance\hresult by -\nbhoriz\fboxrule
\advance\hresult by -\nbhoriz\fboxrule
\vresult=\paperheight
\advance\vresult by -\nbvert\fboxrule
\advance\vresult by -\nbvert\fboxrule
%
\advance\hresult by -2\outputhmargin
\advance\vresult by -2\outputvmargin
%
\advance\hresult by -\nbhoriz \outputindivhmargin
\advance\vresult by -\nbvert \outputindivvmargin
\advance\hresult by \outputindivhmargin
\advance\vresult by \outputindivvmargin
%
\divide\hresult by \nbhoriz
\divide\vresult by \nbvert
% computing actual scale
\if0$EMPTYBB
\newcounter{origx}
\setcounter{origx}{$w}
\addtocounter{origx}{-$x}
\newcounter{origy}
\setcounter{origy}{$h}
\addtocounter{origy}{-$y}
\newlength\finalx
\newlength\finaly
\finalx=\hresult
\finaly=\vresult
\divide\finalx by \value{origx}
\divide\finaly by \value{origy}
\newwrite\scale
\immediate\openout\scale=$filename.scl
\ifdim\finalx>\finaly
\multiply\finaly by 100
\immediate\write\scale{\the\finaly}
\else
\multiply\finalx by 100
\immediate\write\scale{\the\finalx}
\fi
\immediate\closeout\scale
\fi
\begin{document}
%\tracingoutput=1
%\tracingpages=1
%\tracingparagraphs=1
\makeatletter
\newcounter{curroutpage}
\setcounter{curroutpage}{1}
\addtocounter{curroutpage}{-1}
\newcounter{currpage}
\newcounter{currcol}
\newcounter{currline}
\newcounter{realout}
\newcounter{wmout}
\newcounter{wmoutaux}
%\showthe\value{outpage}
%\showthe\value{curroutpage}
\@whilenum \value{outpage}>\value{curroutpage} \do%
{\stepcounter{curroutpage}%
\setcounter{currpage}{\value{curroutpage}}%
\advance\c@currpage by -1%
\multiply\c@currpage by \nbhoriz%
\multiply\c@currpage by \nbvert%
\hrule \@height\z@%
\setcounter{currline}{0}%
\vskip \outputvmargin%
\@whilenum\value{currline}<\nbvert \do%
{\hrule \@height\z@\vskip \outputindivvmargin%
\ifnum\value{currline}>0\vskip \outputindivvmargin\fi%
\global\stepcounter{currline}%
\setcounter{currcol}{0}%
\hskip \outputhmargin%
\@whilenum\value{currcol}<\nbhoriz \do%
{\ifnum\value{currcol}>0\hskip\outputindivhmargin\fi%
\global\stepcounter{currcol}%
\global\stepcounter{currpage}%
\ifnum\value{currpage}>\value{lastpage}\else
%% computing page number corresponding to \currline and \currcol
\setcounter{realout}{\value{currpage}}%
\def\ang{0}%
\ifbooklet
\iflongedge
%% long edge:
%% 1->n, 2->1, 3->n-1 (rotated), 4->2(rotated)...
\ifodd\value{realout}% -> 1 or 3
\addtocounter{realout}{-1}%
\divide\c@realout by 2\relax
\ifodd\value{realout}% -> 3
\def\ang{180}%
\else% -> 1
\fi
\setcounter{realout}{-\value{realout}}%
\addtocounter{realout}{\value{outpage}}%
\addtocounter{realout}{\value{outpage}}%
\else% -> 2 or 4
\divide\c@realout by 2\relax
\ifodd\value{realout}% -> 2
\else% -> 4
\def\ang{180}%
\fi
\fi
\else
%% short edge:
%% 1->n, 2->1, 3->2, 4->n-1, 5->n-2, 6->3, 7->4, 8->n-3
\ifodd\value{realout}% -> 1 or 3
\addtocounter{realout}{-1}%
\divide\c@realout by 2\relax
\ifodd\value{realout}% -> 3
\stepcounter{realout}
\else% -> 1
\setcounter{realout}{-\value{realout}}%
\addtocounter{realout}{\value{outpage}}%
\addtocounter{realout}{\value{outpage}}%
\fi
\else% -> 2 or 4
\divide\c@realout by 2\relax
\ifodd\value{realout}% -> 2
\else% -> 4
\setcounter{realout}{-\value{realout}}%
\stepcounter{realout}
\addtocounter{realout}{\value{outpage}}%
\addtocounter{realout}{\value{outpage}}%
\fi
\fi
\fi
\fi
\ifnum\value{realout}>$nbpages\relax
%% if page above nb of pages, output blank page
\hskip\hresult\hskip2\fboxrule
\else
%% otherwise compute corresponding page to display
%% first keep realout for watermarking...
\setcounter{wmoutaux}{\value{realout}}%
\setcounter{wmout}{\value{realout}}%
\nthvalue{\value{realout}}{\pagelist}%
\iffound\setcounter{realout}{\value{result}}%
\else %% hmmm... problem
\message{I'm messed up counting pages...}%
\fi
%% compute watermarking page (should be original realout?)
\ifx\watermark\@empty\else
\ifnum$nbwp<\value{wmoutaux}\relax
\addtocounter{wmoutaux}{-$nbwp}%
\addtocounter{wmoutaux}{-1}%
\divide\c@wmoutaux by $WATERMARKPERIOD\relax
\stepcounter{wmoutaux}%
\multiply\c@wmoutaux by $WATERMARKPERIOD\relax
\addtocounter{wmout}{-\value{wmoutaux}}%
\fi
\vbox to \vresult{\vfill
\hbox to 0pt{\hfill
\expandafter\includegraphics\expandafter[keepaspectratio,%
height=\vresult,width=\hresult,angle=\ang,%
page=\value{wmout}$CLIPOPT]{$WATERMARK}\hss}\vfill}%
\fi
\fbox{\vbox to \vresult{\vfill
\hbox to \hresult{\hfill
\expandafter\includegraphics\expandafter[$BBOPTION,%
keepaspectratio,height=\vresult,width=\hresult,angle=\ang,%
page=\value{realout}$CLIPOPT]{\file}\hfill}\vfill}}%
\fi
\fi}}%
\clearpage%
}%
\makeatother%
\end{document}
EOF
myecho 1+ "-> producing final file";
case $VERB in
0|1|2)
myecho 2+ " * $PDFLATEX -interaction=nonstopmode $filename.tex"
$PDFLATEX -interaction=batchmode $filename.tex > /dev/null 2>&1 || \
LATEXFAILED=1;;
*)
myecho 3+ " * $PDFLATEX -interaction=nonstopmode $filename.tex"
$PDFLATEX -interaction=nonstopmode $filename.tex || LATEXFAILED=1;;
esac
if [[ $LATEXFAILED -eq 1 ]]; then
myecho 1+ ": failed!"
if [[ $DEBUG == 0 ]]; then
myecho 1+ "-> cleaning";
myecho 2+ " * rm $RMopt $filename.*"
rm $RMopt $filename.*
fi
exit 0;
fi
if [[ $EMPTYBB -eq 0 ]]; then
myecho 1+ " final scale: "`cat $filename.scl | sed -e "s/pt$//"`"%"
fi
myecho 2+ " * mv $MVopt $filename.pdf $OUTF"
mv $MVopt $filename.pdf $OUTF
if [[ $DEBUG == 0 ]]; then
myecho 1+ "-> cleaning";
myecho 2+ " * rm $RMopt $filename.*"
rm $RMopt $filename.*
fi
exit 0
##################################################################
##
## Manual
##
##################################################################
pdfxup creates a PDF document where each page is obtained by
combining several pages of a PDF file given as output. The
important feature of pdfxup, compared to similar programs,
is that it tries to compute the (global) bounding box of the
input PDF file, in order to remove the margins and to keep
the text only. Instead of having the font size divided by 2
(for the case of 2-up output), in some case you may end up
with the same font size as in the original document (as is
the case for a default 'article' document produced by LaTeX).
pdfxup has numerous options:
* '-x n' and '-y n' can be used to change the number of
rows and columns of the resulting document.
[default: -x2 -y1]
* '-l n' turns the output to landscape (n=1) or portrait
(n=0).
[default: -l1]
* '-b n' toggles the 'booklet' mode: the resulting PDF can
be printed and folded as a booklet. Printing such a
booklet requires 2-sided printing, which can follow
either the 'long-edge' or the 'short edge' of the paper.
'long-edge' seems to be the most commonly used, but using
'-b se' while produce a PDF booklet for 'short-edge'
2-sided printing.
* '-c' clips pages to their bounding box: this is set by
default, so that any content outside bounding box will be
lost. Using "-c 0", anything outside the bounding box will
be displayed, and may overlap neighbouring pages.
* '-p' can be used to only consider a set of pages of the
input file. The set of pages to include is a comma-
separated list of pages, ranges of pages of the form
'm-n', or sets of pages of the form "0%2" (all even-
numbered pages). Alternatively to '-p', the page range
can be specified after the file name, writing
'file.pdf:<list>' in place of '-p <list>'.
* '-bb' can be used to list the pages to be taken into
account when computing the bounding box. This is
especially useful for large documents, because computing the
bounding box on each page can be long, and because
computing the bounding box over the first 10 pages is
usually enough... This will not change the number of pages
included in the final document.
Several '-bb' options can be given, which will result in
considering the union of all the intervals.
* '-nobb' is used to remove pages from the computation of
the bounding box. This is useful if one page has e.g.
special headers (e.g. for arXiv papers). Notice that the
bounding box of those pages will still be computed by
ghostscript, so this does not save time. I'd be grateful
to anyone willing to implement difference of unions of
intervals... ;-)
* '-fw d' defines the width of the frame around each page.
Set to 0pt to have no frame at all.
* inner margins: margins to be added between each frame and
its included page.
* margins: margins of the final document
* spacing: spacing between frames
* '-w file' can be used to add watermarking to all pages. The
file can be anything that pdflatex can handle (eg. png, pdf).
If it is a PDF with several pages, page n of the watermarking
file will be used with page n of the input file. By default,
the last page will be repeated if the input file has more
pages than the watermarking file. This behaviour can be
modified with the '-wp n' options, which asks to repeat the
last n pages instead of only the last one. Setting `-wp 0`
will repeat all the pages of the watermarking file.
##################################################################
##
## Examples
##
##################################################################
# pdfxup file.pdf
-> creates pdfxup.pdf from file.pdf with default options
(2-up, margins=5mm)
# pdfxup -bb 1-4 file.pdf
-> same behaviour, but computes the bounding box only using the
first 4 pages
(this saves time when processing long documents)
# pdfxup -b file.pdf
-> same behaviour, but creates a booklet
# pdfxup -kbb -b -o booklet.pdf file.pdf:3-25
-> creates a booklet from pages 3-25 of file.pdf, without
reducing margins (option '-kbb' disables bounding-box
computation; equivalent to e.g. '-bb 0');
name the resulting file booklet.pdf.
# pdfxup -kbb -x1 -y2 -l0 beamer-frames.pdf
-> arranges 2 beamer frames per page (not reducing margins)
# pdfxup -kbb -x2 -y2 -l1 beamer-frames.pdf
-> arranges 4 beamer frames per page (not reducing margins)
# pdfxup -fw0 -w draft.png file.pdf
-> remove frame border; add 'draft' watermarking on all pages