#!/bin/bash
#---------------------------------------------------------------#
#                          pdf2booklet                
#                                
#                    Jerusalem, November 2006            
#                    
#---------------------------------------------------------------#
#
#  rearranges a pdf file to print it as one booklet or an array of signatures
#  thanks to Mendel Cooper for the Advanced Bash-Scripting Guide

#  variables used:
#  W, H  are the output-page width and hight AS PRINTED, i.e. height is the longer
#+ and width is the shorter
#  PDFH and PDFW are the with and height of the PDF-file, respectively
#  XOFFSET and YOFFSET are the "left" and "upper"  margin and correspond to the xoff, yoff
#+ in pstops




# VARS
ALLOWED_PAGEFORMATS="a4 (default), letter"

factor (){
#  defines F according to $1
#+ to change cm, inch into points
case $1 in
            cm ) F=28.4
            ;;
            in ) F=72
            ;;
            pt ) F=1
            ;;
            * )     echo " only points (pt), centimetres (cm) and inches (in) allowed!"
                exit
            ;;
        esac
}


error () {
cat <<EOF
Usage: $0 [OPTIONS] PDF-FILE

    creates ps documents from a pdf for booklet printing
    
    
    OPTIONS
    -I        show Information and suggestions on file and exit
    -T         two-on-one page, not booklet (default=booklet)
    -O uuXxY[:X2xY2] string to define X,Y-offset. X/Y start at upper left corner of output page,
            i.e. it is  left(X) and upper margin (Y)
            Format: uu<X>x<Y>[/X2xY2] where uu is a 2-letter code for the measurement(pt,cm,in)
            followed by X and Y separated by \`x' and optionally the same
            for the second page ([:X2xY2])
    -x        center horizontically
    -y        center vertically
    -r        automatic resize (including offset)
    -c <pages>    amount of folios for the codex (default=6, i.e. 24 pages)
    -p <pag>    output page (a4 (default), letter)
    -P uuWxH    string to define width and height of output paper. Format:
            uu<width>x<height> where uu is a 2-letter code for the measurement(pt,cm,in)
            followed by width and height separated by \`x'
    -s <shrink>    shrink by factor (default=.7)
    -F value    first page (default=1)
    -L value    last page (default=last)
    -d        show frame around page
    -v        show result in gv

    *** save trees - think twice before printing! ***

EOF
}

while getopts ":ITO:xyrc:p:P:s:F:L:dv"  OPTION
do
    case $OPTION in
    I )    # INFO
        INFO=yes
;;
    T )    # two-in-one
        TWOINONE=yes
;;
    r )    # left margin
        RESIZE=yes
;;
    O )    # offset
        REST=${OPTARG:2}        # rest XxY/XxY
        O=${REST%:*}            # first XxY/...
        O2=${REST#*:}            # last  .../XxY
        factor  ${OPTARG:0:2}    # units (pt,cm,in) get factor..
        # as output page is landscape,the X and Y are switched !!    
        YOFFSET=$(echo  "${O%x*} * $F" |bc 2> /dev/null )     #+ ..for conversion
        XOFFSET=$(echo  "${O#*x} * $F" |bc 2> /dev/null )    #+ .. to points
        Y2OFFSET=$(echo  "${O2%x*} * $F" |bc 2> /dev/null )     #+ ..for conversion
        X2OFFSET=$(echo  "${O2#*x} * $F" |bc 2> /dev/null )    #+ .. to points
;;
    x)    XCENTER=yes
;;
    y)    YCENTER=yes
;;
    c )    # number of pages of codex
        FOLIO=$OPTARG
;;
    p )    
        PAGESIZE=$OPTARG
        case $OPTARG in
            a4 ) # do nothing
            ;;
            letter )
                H=792
                W=612
                SHRINK=.647
            ;;
            * ) echo "only $ALLOWED_PAGEFORMATS -- use -P uu<X>x<Y> other sizes"
            exit
            ;;
        esac
;;
    P )    # output page size
        O=${OPTARG:2}
        factor ${OPTARG:0:2}    # get factor for conversion to points
        W=$(echo  "${O%x*} * $F" |bc 2> /dev/null )
        H=$(echo  "${O#*x} * $F" |bc 2> /dev/null )
;;
    s )    # shrink factor
        SHRINK=$OPTARG
;;
    F )    # first page
        FIRST=$OPTARG
;;
    L )    # last page
        LAST=$OPTARG
;;
    d )    # show frame around page
        SHOWFRAME="-d"
;;
    v)    # gv results
        GV=yes
;;
esac
done

shift $(( $OPTIND - 1 ))

if [ -z "$1"  ]
    then
    error
    exit 65
fi


#Declare varialbles
# from input (pdf) file
PDF="$1"                        # our pdf file to print
PDFINFO=`pdfinfo "$1"`
PAGES=$(echo "$PDFINFO"|grep Pages| awk '{print $2}')        # number of pages in pdf-file
PDFW=$(echo "$PDFINFO"|grep "Page size"| awk '{print $3}')    # height of PDF-file
PDFH=$(echo "$PDFINFO"|grep "Page size"| awk '{print $5}')    # width of PDF-file

# options
FOLIO=${FOLIO-6}            # size of codex, i.e. number of folios
let "PCODEX = $FOLIO * 4"        # number of pages in codex,
SHRINK=${SHRINK-.7}            # shrint factor, default is 0.7
FIRST=${FIRST-1}            # first page, default is first
LAST=${LAST-$PAGES}            # last page, default is last

# output page
H=${H-842}            # height of output page
W=${W-595}            # width of output page
XOFFSET=${XOFFSET-0.0}        # horizontical offset
YOFFSET=${YOFFSET-0.0}        # vertical offset
X2OFFSET=${X2OFFSET-$XOFFSET}        # horizontical offset 2nd page
Y2OFFSET=${Y2OFFSET-$YOFFSET}        # vertical offset 2nd page

PAGESIZE="-w$W -h$H"

# check, if input file exists
if ! test -f "$PDF"    
    then
        echo "File not found"
        exit
fi


# -I: show info and exit
if [[ ! -z $INFO ]]
    then
    # form command pdfinfo
    echo -e " File: $PDF"                    # file name
    echo "$PDFINFO" | sed 's/^/ /; s/:[ ]*/: /g'        # pdfinfo relayouted
    echo
    echo -e " pages per codex   # of codices     pages of last codex           %"
    echo " ----------------------------------------------------------------------"
    # list to see "left-over" pages when printing codices
    for i in `seq 1 12`
        do
        #  divide no of pages by pages of codex
        #+ and rounded up to next higher integer
        #+ (broken numbers mean empty pages)
        X=$(echo $PAGES  $i | awk '{  
        x = ( $1 / 4 )
        if (x == int(x))
            x = x
        else
            x = int(x + 1)
        print x
        ival = x % $2
        aval = int(ival)
        if (ival == 0 )
            print $2
        else {
        if (ival == aval)
            print aval
        else
            print aval + 1
        }
        ival = x / $2
        aval = int(ival)
        if (ival == aval)
            print aval
        else
            print aval + 1
        }')
        #  set awk output as arguments
        set -- $X        #+ there is no more need for arguments, anyhow
        SIGNATURES=$1        # number of signatures to print
        LASTCODEX=$2        # pages of last codex
        NOCODEX=$3         # number of codices to print
        [[  $LASTCODEX -eq $i ]] && echo -n " >>"    # mark when last codex has 100% pages
        echo -e -n "\t$i\t\t$NOCODEX\t\t$LASTCODEX\t\t\t"
        echo "scale=2; $LASTCODEX / $i * 100" |bc
    done
    echo -e "\tsignatures to print: $SIGNATURES"
    exit
fi

if [[ $RESIZE == yes ]]        # calculate best resize factor accoring to input, ouput and offset
    then
    # find larger X-offset, avoid negative
    VO=$(echo "0 $XOFFSET $X2OFFSET" |awk '{for (i=1; i<=NF; i++) if ($i >= max ) max = $i } END {print max}')
    HO=$(echo "0 $YOFFSET $Y2OFFSET" |awk '{for (i=1; i<=NF; i++) if ($i >= max ) max = $i } END {print max}')

    resize1=$(echo "scale=2; ( ($H / 2 ) - $HO ) / $PDFW" |bc)  
    resize2=$(echo "scale=2; ( $W  - $VO ) / $PDFH" |bc)
    
    # choose the smaller resize factor ;
    if [[ ${resize1:1} -gt ${resize2:1} ]]
        then
        SHRINK=$resize2
        else
        SHRINK=$resize1
    fi
fi



# creating ps file from pdf
TMP1=/tmp/pdf.ps
TMP2=/tmp/booklet.ps
OUTPUTFILE=${PDF%.pdf}

echo " converting (pdftops) ..."
pdftops -paper match -f $FIRST -l $LAST  "$PDF" $TMP1

# rearrange pages for booklet
if [[  $TWOINONE == yes ]]  
    then
    TMP2=$TMP1        # non booklet needs no rearragement, just change file
    else
    psbook -s$PCODEX  $TMP1 >$TMP2
fi

# create string for pstops
# see pstops for details (very complex!!)
if [[ $YCENTER == yes ]]        # center page to X-axis
    then
    XOFFSET=$(echo "scale=2; $XOFFSET + ($W - ($PDFH * $SHRINK )-$XOFFSET) / 2" |bc 2>/dev/null)
    X2OFFSET=$(echo "scale=2; $X2OFFSET + ($W - ($PDFH * $SHRINK )-$X2OFFSET) / 2" |bc 2>/dev/null)
fi

if [[ $XCENTER == yes ]]        # center page to y-axix
    then
    YOFFSET=$(echo "scale=2; $YOFFSET +( (($H / 2 ) - ($PDFW * $SHRINK ) - $YOFFSET) / 2)" |bc 2>/dev/null)
    Y2OFFSET=$(echo "scale=2; $Y2OFFSET +( (($H / 2 ) - ($PDFW * $SHRINK ) - $Y2OFFSET) / 2)" |bc 2>/dev/null)
fi

#  page is first shrank (with lower left corner fixed)
#+ then rotated (90 deg to the left (again lower left corner fixed)
#+ and then moved its own (new) size plus the offset

X1=$(echo "scale=2; ($PDFH * $SHRINK) + $XOFFSET" |bc 2>/dev/null)     # page height and offset
Y1="$YOFFSET"    
X2=$(echo "scale=2; ($PDFH * $SHRINK) + $X2OFFSET" |bc 2>/dev/null)
Y2=$(echo "scale=2; ($H / 2 ) + $Y2OFFSET" |bc 2>/dev/null)

DUPLEX="2:0L@$SHRINK($X1,$Y1)+1L@$SHRINK($X2,$Y2)"

# create final output
cat <<EOF
 left margin (left page): $YOFFSET pts
 upper margin (left page): $XOFFSET pts
 left margin (right page): $Y2OFFSET pts
 upper margin (right page): $X2OFFSET pts
 shrink factor: $SHRINK
 output page size: $PAGESIZE (pts)
 file: $OUTPUTFILE.ps

 create booklet ...
EOF
pstops $PAGESIZE -b  $SHOWFRAME "$DUPLEX"  $TMP2  > "$OUTPUTFILE".ps

if [[ $GV == yes ]]
    then
    gv --orientation=landscape --resize --scale=-1 "$OUTPUTFILE".ps
fi