#!/bin/bash
#
# Created by Daniel Mäder, www.bluevirus.ch
# May be distributed without removing the creators information.
# Use at your own risk.
#
# The aim of this script is to collect pages from a pdf and put them together 
# for printing. Since many printers are not able to print on endless paper the
# pages will be printed on the maximal paper height your printer can manage
# (check the optional parameter -m).
# According to the maximal paper height your printer can mange the amount of
# toilet tissue pieces a sheet-sets consist of.
# After generation you can print them directly on toilet tissue. Remember to use
# the specific paper dimensions that will be printed out on command line.
# Remember to append a normal paper of same width as the toilet tissue and the
# height that you may have specified (check the optional parameter -m) at the
# beginning of the toilet tissue slices.
# Finally you can splice them together.
# 
# For more information type:
#   toiletmerge -h

# declare toiletpaper's height and width in mm
VERSION="0.1"
PRGMNAME="toiletmerge"
verbosity=2
VERBOSE=3
NOTICE=2
ERROR=1
overwritemode=0
reverse=0

widthmm=98
heightmm=126
maxheightmm=676
precedingHeightmm=100
PIXELPERMM=6.7940
#13.588

input=""
inputdefined=0
output=""
outputdefined=0
outputext=".png"

## Functions
  # displays progress
function progressBar  #@ USAGE: progressBar current-state full-state
{
  tput sc
  if [ $# -eq 2 ]; then
    PROGRESSSIZE=$(tput cols)
    PROGRESSSIZE=$(echo $PROGRESSSIZE-12|bc)
    percentage=$(echo "scale=0;100*${1}/${2}" | bc)
    percentage=$(printf %3.0f $percentage) 
    bar="[ "
    for (( u=0;u<$PROGRESSSIZE;u++ )); do
      exp=$(echo "100*$u/$PROGRESSSIZE <= $percentage"|bc)
      if [ $exp -eq 1 ]; then
        bar="${bar}#"
      else
        bar="${bar} "
      fi
    done
    bar="${bar} ]"
    echo -ne " $bar $percentage %"
  else
    echo "Need 2 arguments: current-state and full-state"
  fi
  tput el
  tput rc
}

  # ceil number
function ceil #@ USAGE: ceil floating-number
{
  if [ $# -eq 1 ]; then
    in=$(echo $1|bc)
    in=$(echo $in+.5|bc)
    for bash_rounded_number in $(printf %.0f $in); do
      echo $bash_rounded_number
    done 

  fi
}

  # print help
function ehelp
{
usage=$(
cat <<EOF

$PRGMNAME $VERSION
The aim of this script is to collect pages from a pdf and put them together for 
printing. Since many printers are not able to print on endless paper the pages 
will be printed on the maximal paper height your printer can manage (check the 
optional parameter -m).
According to the maximal paper height your printer can mange the amount of 
toilet tissue pieces a sheet-sets consist of.
After generation you can print them directly on toilet tissue. Remember to use
the specific paper dimensions that will be printed out on command line. Remember
to append a normal paper of same width as the toilet tissue and the height that 
you may have specified (check the optional parameter -m) at the beginning of the
toilet tissue slices.
Finally you can splice them together.

Usage:
  $0 -h
  $0 [-vrf] -i input [-o output ] [-m maxheight] [-p height]

Parameters:
  -v           Increase verbosity level
  -i input     PDF-file that needs to be converted
  -o output    Destination file (basename)
  -m height    Define maximum sheet height in mm
  -f           Forces overwriting existing files
  -r           Reverses page order
  -p height    Defines preceding normal paper's height in mm
  -h           Show this help file

Example:
  $0 -i toilet.pdf    

                      This will merge all pages from toilet.pdf to as few as
                      possible images with the maximum image height of $maxheightmm mm.
                      The result will be stored in toilet_0.png, toilet_1.png,
                      ... . Now you can print those images on toilet paper,
                      using the paper dimensions and amount of sheets printed 
                      out by the program.

.
EOF
)
  echo "$usage"
}

function eminhelp
{
  if [ $# -eq 1 ]; then
    echo -ne "$1 "
  fi

  echo "For help type:"
  echo "  $0 -h"
}

function eMessage
{
  if [ $# -eq 2 ]; then
    if [ $verbosity -ge $1 ]; then
      echo $2
    fi
  fi
}

## Check input arguments
while getopts "hvi:o:m:frp:" OPTION; do
  case "$OPTION" in
    h)      ehelp
            exit 0
            ;;
    v)      verbosity=$(($verbosity+1))
            ;;
    i)      case ${OPTARG##*.} in
              pdf) 
                    input="$OPTARG"
                    inputdefined=1
                    
                    # does the file exist?
                    if [ ! -e $input ]; then
                      eminhelp "Given file '$input' does not exist."
                      exit 0
                    fi
                    
                    if [ $outputdefined -eq 0 ]; then
                      outputext=".png"
                      output=${OPTARG%.*}
                    fi
                    ;;
                *)  # Invalid filetype
                    eminhelp "Invalid filetype '${OPTARG##*.}' given. Use PDF file."
                    exit 0
              ;;
            esac
            ;;
    o)      outputext=".${OPTARG##*.}"  # get file extension
            output=${OPTARG%.*}         # get filename without extension
            outputdefined=1
            ;;
    m)      if [[ "$OPTARG" == ?(+)+([0-9]) ]]; then
              maxheightmm="$OPTARG"
            else
              eminhelp "Given value $OPTARG is not a valid height."
              exit 0
            fi
            ;;
    f)      overwritemode=1
            ;;
    r)      reverse=1
            ;;
    p)      if [[ "$OPTARG" == ?(+)+([0-9]) ]]; then
              precedingHeightmm="$OPTARG"
            else
              eminhelp "Given value $OPTARG is not a valid height."
              exit 0
            fi
            ;;
    *)      # Invalid argument
            eminhelp "Invalid argument."
            exit 0
            ;;
  esac
done

if [ $inputdefined -eq 0 ]; then
  eminhelp "Missing arguments."
  exit 0
fi


## Make some calculations...
  # calculate width and height in pixel
WIDTH=$(echo "scale=0;$PIXELPERMM*$widthmm"|bc)
HEIGHT=$(echo "scale=0;$PIXELPERMM*$heightmm"|bc)
PRECED=$(echo "scale=0;$PIXELPERMM*$precedingHeightmm"|bc)
WIDTH=$(printf %.0f $WIDTH)
HEIGHT=$(printf %.0f $HEIGHT)
PRECED=$(printf %.0f $PRECED)


# find out the number of pages the pdf has
PAGENUMINFO=`pdftk $input dump_data output|grep -i Num`

if [[ $PAGENUMINFO =~ ^[[:alpha:]]*\:[[:space:]]([0-9]*)$ ]]; then
  PAGES=${BASH_REMATCH[1]}
  if [ $verbosity -eq 0 ]; then
    eMessage $VERBOSE "Document has $PAGES pages."
  fi
else
  eMessage $ERROR "ERROR: Unknown amount of pages, exiting."
  exit 1
fi

# find out how many parts we can do
  # calculate pages per "sheet"
PAGESPERSHEET=$(echo \($maxheightmm-$precedingHeightmm\)/$heightmm|bc) # Abrunden OK
SHEETSCOUNT=$(ceil "scale=10;$PAGES/$PAGESPERSHEET" | bc)
eMessage $NOTICE "With a maximum of $PAGESPERSHEET pages per sheet-set we need $SHEETSCOUNT sheet-sets. Preceding blank normal page length is ${precedingHeightmm}mm"


# check that no file exists with the same name as the output files
if [ $overwritemode -eq 0 ]; then
  for (( s=0;s<$SHEETSCOUNT;s++)); do
    if [ -e ${output}_${s}${outputext} ]; then
      eMessage $ERROR "ERROR: A file with the outputname ${output}_${s}${outputext} already exists. Aborting..."
      exit 0
    fi
  done
fi

# final merge process:
eMessage $NOTICE "Merging ..."
progressBar 0 $PAGES
for (( s=0;s<$SHEETSCOUNT;s++)); do
  ALLHEIGHT=$(echo $PAGESPERSHEET*$HEIGHT|bc)
  # create huge image
  convert -size ${WIDTH}x${ALLHEIGHT}\! xc:white ${output}_${s}${outputext}
  # merge all pieces into it
  for (( i=0;i<$PAGESPERSHEET;i++)); do
    if [ $reverse -eq 0 ]; then
      let p=$s*$PAGESPERSHEET+$i
    else
      let p=$s*$PAGESPERSHEET+$PAGESPERSHEET-$i-1
    fi
    if [[ $p -lt $PAGES ]]; then
      hpos=$(echo $i*$HEIGHT+$PRECED|bc)
      composite -interlace none -density 300 -quality 80 \( $input[$p] -resize ${WIDTH}x${HEIGHT}\! \) -geometry +0+${hpos} ${output}_${s}${outputext} ${output}_${s}${outputext}
      num=$(echo $s*$PAGESPERSHEET+$i+1|bc)
      progressBar $num $PAGES
    fi
  done
done
echo " "
echo "done."

allheightmm=$(echo $PAGESPERSHEET*$heightmm|bc)
eMessage $NOTICE "Set sheet dimension in printer settings to ${widthmm}mm x ${allheightmm}mm"
eMessage $VERBOSE "print with command like:"
for (( s=0;s<$SHEETSCOUNT;s++)); do
  eMessage $VERBOSE "  lp -d <printerId> -o PageSize=Custom.${widthmm}x${allheightmm}mm -o fitplot ${output}_${s}${outputext}"
done


