PDF Printing
PDF Printing
While many applications offer exporting output to portable document format (PDF) files, many others do not. It is easy to add a virtual PDF printer to CUPS by installing the cups-pdf package that is available at http://www.slackbuilds.org
This works well for single documents, but if you print multiple documents that are parsed as having the same name then the older documents will be overwritten. A solution to this is to run a script that watches for the creation of the PDF document in the spool directory (/var/spool/cups-pdf/<username> by default) and then moves the document to another directory (USERS_DIR). The script below (watch_for_spooled_pdf.sh kept in /home/xx/pdf_printing) also prepends a date and time string to keep the document names unique. A user xx should start this script as a background process i.e. /home/xx/pdf_printing/watch_for_spooled_pdf.sh &
#!/bin/sh # Script to watch for creation of .pdf files by CUPS-PDF in spool directory # and move to users directory prepending the creation date and time. # # This script uses the -m option to inotifywait and should never exit. SPOOL_DIR=/var/spool/cups-pdf/xx/ USERS_DIR=/home/xx/Desktop/PDF_Files/ inotifywait -mq --timefmt '%Y%m%d %H%M%S' --format '%T %f' \ -e close_write $SPOOL_DIR \ | while read date time file; do mv $SPOOL_DIR${file} $USERS_DIR${date}${time}_${file} done
What if printed PDF documents should be combined into one large PDF document? A user could move the files to be combined to a new subdirectory and then run the script (combine.sh) shown below. This script creates a single PDF document with bookmark entries to each of the individual documents using the facilities in the pdfpages and hyperref packages of LaTeX. The page order is in the order of creation date and time.
#!/bin/bash # Script to combine .pdf files into a single bookmarked .pdf file # Intended to be run from within a directory containing files to be concatenated. # The directory name is accepted as a parameter # If the directory name has been passed, then make it the working directory. if [[ $1 ]]; then cd $1; fi # Filename for the .tex file that will be processed using pdflatex OUTFILE=$PWD/out2.tex # Starting values for bookmark creation BKMK_TEXT=Contents BKMK_ANCHOR=Beginning BKMK_LEVEL=0 # Variable containing ASCII code for centre dot character CENTREDOT=$(echo -e "\xB7") # Function to sanitise filenames by: # Changing space characters to underscore characters # and changing all but last period characters to centre dot (0xB7) # Necessary for \includepdf to parse filenames correctly sanitise_filenames () { for FILENAME in *.[Pp][Dd][Ff] ; do PREFIX=${FILENAME%.*} SUFFIX=${FILENAME##*.} NEWPREFIX=${PREFIX// /_} NEWPREFIX=${NEWPREFIX//./$CENTREDOT} if [ "$PREFIX" != "$NEWPREFIX" ]; then mv "$FILENAME" "$NEWPREFIX.$SUFFIX" fi done return } # Function to create a bookmark entry do_bookmark_entry () { BKMK_TEXT=${FILENAME%.*} BKMK_TEXT=${BKMK_TEXT:15} # NB. Need to substitute 'space' for 'underscore' to be valid bookmark text. BKMK_TEXT=${BKMK_TEXT//_/ } # Create a unique anchor point based on date and time prepended to filename BKMK_ANCHOR=${FILENAME:0:14} echo "\pdfbookmark["$BKMK_LEVEL"]{"$BKMK_TEXT"}{"$BKMK_ANCHOR"}" >> $OUTFILE return } # Function to add all pdf files in current directory to the output file add_pdf_files () { for FILENAME in *.[Pp][Dd][Ff] ; do do_bookmark_entry echo "\includepdf[pages=-,fitpaper]{"$PWD"/"$FILENAME"}" >> $OUTFILE done return } echo "\documentclass{article}" > $OUTFILE echo "\usepackage{pdfpages}" >> $OUTFILE echo "\usepackage[bookmarks,bookmarksopen,bookmarksopenlevel=1,pdfpagelayout={SinglePage},pdfview={Fit}]{hyperref}" >> $OUTFILE echo "\begin{document}" >> $OUTFILE echo "\pdfbookmark["$BKMK_LEVEL"]{"$BKMK_TEXT"}{"$BKMK_ANCHOR"}" >> $OUTFILE sanitise_filenames (( BKMK_LEVEL++ )) for FNAME in * ; do if [ -d $FNAME ]; then FILENAME=$FNAME do_bookmark_entry cd $FNAME (( BKMK_LEVEL++ )) sanitise_filenames add_pdf_files (( BKMK_LEVEL-- )) cd .. elif [ -f $FNAME ] && [[ ${FNAME##*.} == [Pp][Dd][Ff] ]] ; then FILENAME=$FNAME do_bookmark_entry echo "\includepdf[pages=-,fitpaper]{"$PWD"/"$FILENAME"}" >> $OUTFILE fi done echo "\end{document}" >> $OUTFILE # Now process the .tex file # Do a second run so that bookmark entries are resolved pdflatex $OUTFILE; pdflatex $OUTFILE wait # Rename the created .pdf file mv ${OUTFILE%.*}.pdf $(date +%Y%m%d%H%M%S)_All.pdf # Cleanup files left by pdflatex processing rm ${OUTFILE%.*}* # Cleanup trigger file if this script has been started from watch_for_combine_start.sh script if [ -f combine.start ]; then rm combine.start; fi # Remove this script rm $0
As a convenience, the user could also have a second background process running the script (watch_for_combine_start.sh) shown below. This script watches for the creation of a 'trigger' file (combine.start) in the directory tree and then executes the 'combine.sh' script shown above. This is useful in a network environment, so that a Windows user manipulating the files via a Samba share can create the combined PDF file without having to log in to the Slackware Linux server.
#!/bin/sh # Script to watch for creation of a trigger file in a directory tree. # This event causes another script to be copied into the tree subdirectory and run. # The tree subdirectory name is passed as a parameter. # # This script should never exit WATCH_DIR=/home/xx/Desktop/PDF_Files TRIGGER_FILE=combine.start SCRIPT_FILE=/home/xx/pdf_printing/combine.sh inotifywait -mqr --timefmt '%Y%m%d %H%M%S' --format '%T %w %f' \ -e close_write $WATCH_DIR \ | while read date time path file; do if [ ${file} == $TRIGGER_FILE ]; then cp $SCRIPT_FILE ${path} sh ${path}/$(basename $SCRIPT_FILE) ${path} > /dev/null & fi done