diff --git a/pdfScale.sh b/pdfScale.sh index b5a64c2..631cde4 100755 --- a/pdfScale.sh +++ b/pdfScale.sh @@ -5,14 +5,14 @@ # Scale PDF to specified percentage of original size. # # Gustavo Arnosti Neves - 2016 / 07 / 10 -# Latest Version - 2017 / 05 / 14 +# Latest Version - 2017 / 05 / 19 # # This script: https://github.com/tavinus/pdfScale # Based on: http://ma.juii.net/blog/scale-page-content-of-pdf-files # And: https://gist.github.com/MichaelJCole/86e4968dbfc13256228a -VERSION="2.0.5" +VERSION="2.1.0" ###################### EXTERNAL PROGRAMS ####################### @@ -34,6 +34,7 @@ LC_NUMERIC="C" TRUE=0 # Silly stuff FALSE=1 + ########################### GLOBALS ############################ SCALE="0.95" # scaling factor (0.95 = 95%, e.g.) @@ -42,9 +43,12 @@ PDFSCALE_NAME="$(basename $0)" # simplified name of this script OSNAME="$(uname 2>/dev/null)" # Check where we are running GS_RUN_STATUS="" # Holds GS error messages, signals errors +INFILEPDF="" # Input PDF file name +OUTFILEPDF="" # Output PDF file name JUST_IDENTIFY=$FALSE # Flag to just show PDF info +ABORT_ON_OVERWRITE=$FALSE # Flag to abort if OUTFILEPDF already exists ADAPTIVEMODE=$TRUE # Automatically try to guess best mode -AUTOMATIC_SCALING=$TRUE # Default scaling in $SCALE, override by resize mode +AUTOMATIC_SCALING=$TRUE # Default scaling in $SCALE, disabled in resize mode MODE="" # Which page size detection to use RESIZE_PAPER_TYPE="" # Pre-defined paper to use CUSTOM_RESIZE_PAPER=$FALSE # If we are using a custom-defined paper @@ -71,6 +75,8 @@ EXIT_MISSING_DEPENDENCY=25 EXIT_IMAGEMAGIK_NOT_FOUND=26 EXIT_MAC_MDLS_NOT_FOUND=27 EXIT_PDFINFO_NOT_FOUND=28 +EXIT_NOWRITE_PERMISSION=29 +EXIT_NOREAD_PERMISSION=30 EXIT_TEMP_FILE_EXISTS=40 EXIT_INVALID_PAPER_SIZE=50 @@ -80,15 +86,12 @@ EXIT_INVALID_PAPER_SIZE=50 # Main function called at the end main() { printPDFSizes # may exit here - vprint " Input File: $INFILEPDF" - vprint " Output File: $OUTFILEPDF" - getPageSize - vPrintPageSizes ' Source' local finalRet=$EXIT_ERROR - local tempFile="" - local tempSuffix="$RANDOM$RANDOM""_TEMP_$RANDOM$RANDOM.pdf" if isMixedMode; then + initMain " Mixed Tasks: Resize & Scale" + local tempFile="" + local tempSuffix="$RANDOM$RANDOM""_TEMP_$RANDOM$RANDOM.pdf" outputFile="$OUTFILEPDF" # backup outFile name tempFile="${OUTFILEPDF%.pdf}.$tempSuffix" # set a temp file name if isFile "$tempFile"; then @@ -107,12 +110,14 @@ main() { pageScale # scale the resized pdf finalRet=$(($finalRet+$?)) # remove tmp file - rm "$tempFile" >/dev/null 2>&1 || printError "Error when removing temporary file: $tempFile" + isFile "$tempFile" && rm "$tempFile" >/dev/null 2>&1 || printError "Error when removing temporary file: $tempFile" elif isResizeMode; then + initMain " Single Task: Resize PDF Paper" vPrintScaleFactor "Disabled (resize only)" pageResize finalRet=$? else + initMain " Single Task: Scale PDF Contents" local scaleMode="" isManualScaledMode && scaleMode='(manual)' || scaleMode='(auto)' vPrintScaleFactor "$SCALE $scaleMode" @@ -123,13 +128,22 @@ main() { if [[ $finalRet -eq $EXIT_SUCCESS ]] && isEmpty "$GS_RUN_STATUS"; then vprint " Final Status: File created successfully" else - vprint " Final Status: Error detected"$'\n'" Exit status: $finalRet" - printError $'\n'"PdfScale: ERROR!"$'\n'"Ghostscript Debug Info:"$'\n'"$GS_RUN_STATUS" + vprint " Final Status: Error detected. Exit status: $finalRet" + printError "PdfScale: ERROR!"$'\n'"Ghostscript Debug Info:"$'\n'"$GS_RUN_STATUS" fi return $finalRet } +# Initializes PDF processing for all modes of operation +initMain() { + printVersion 1 'verbose' + isNotEmpty "$1" && vprint "$1" + vPrintFileInfo + getPageSize + vPrintPageSizes ' Source' +} + # Prints PDF Info and exits with $EXIT_SUCCESS, but only if $JUST_IDENTIFY is $TRUE printPDFSizes() { if [[ $JUST_IDENTIFY -eq $TRUE ]]; then @@ -151,6 +165,7 @@ printPDFSizes() { return $EXIT_SUCCESS } + ###################### GHOSTSCRIPT CALLS ####################### # Runs the ghostscript scaling script @@ -183,30 +198,14 @@ gsPageScale() { return $? } - # Runs the ghostscript paper resize script pageResize() { - # Get new paper sizes if not custom paper - isNotCustomPaper && getGSPaperSize "$RESIZE_PAPER_TYPE" - + # Get paper sizes from source if not resizing + isResizePaperSource && { RESIZE_WIDTH=$PGWIDTH; RESIZE_HEIGHT=$PGHEIGHT; } + # Get new paper sizes if not custom or source paper + isNotCustomPaper && ! isResizePaperSource && getGSPaperSize "$RESIZE_PAPER_TYPE" vprint " Auto Rotate: $(basename $AUTO_ROTATION)" - - # Flip detect - local tmpInverter="" - if [[ $FLIP_DETECTION -eq $TRUE || $FLIP_FORCE -eq $TRUE ]]; then - if [[ $PGWIDTH -gt $PGHEIGHT && $RESIZE_WIDTH -lt $RESIZE_HEIGHT ]] || [[ $FLIP_FORCE -eq $TRUE ]]; then - [[ $FLIP_FORCE -eq $TRUE ]] && vprint " Flip Detect: Forced Mode!" || vprint " Flip Detect: Wrong orientation detected!" - vprint " Inverting Width <-> Height" - tmpInverter=$RESIZE_HEIGHT - RESIZE_HEIGHT=$RESIZE_WIDTH - RESIZE_WIDTH=$tmpInverter - else - vprint " Flip Detect: No change needed" - fi - else - vprint " Flip Detect: Disabled" - fi - + runFlipDetect vprint " Run Resizing: $(uppercase "$RESIZE_PAPER_TYPE") ( "$RESIZE_WIDTH" x "$RESIZE_HEIGHT" ) pts" GS_RUN_STATUS="$GS_RUN_STATUS""$(gsPageResize 2>&1)" return $? @@ -228,6 +227,53 @@ gsPageResize() { return $? } +# Returns $TRUE if we should use the source paper size, $FALSE otherwise +isResizePaperSource() { + [[ "$RESIZE_PAPER_TYPE" = 'source' ]] && return $TRUE + return $FALSE +} + +# Filp-Detect Logic +runFlipDetect() { + if isFlipForced; then + vprint " Flip Detect: Forced Mode!" + applyFlipRevert + elif isFlipDetectionEnabled && shouldFlip; then + vprint " Flip Detect: Wrong orientation detected!" + applyFlipRevert + elif ! isFlipDetectionEnabled; then + vprint " Flip Detect: Disabled" + else + vprint " Flip Detect: No change needed" + fi +} + +# Inverts $RESIZE_HEIGHT with $RESIZE_WIDTH +applyFlipRevert() { + local tmpInverter="" + tmpInverter=$RESIZE_HEIGHT + RESIZE_HEIGHT=$RESIZE_WIDTH + RESIZE_WIDTH=$tmpInverter + vprint " Inverting Width <-> Height" +} + +# Returns the $FLIP_DETECTION flag +isFlipDetectionEnabled() { + return $FLIP_DETECTION +} + +# Returns the $FLIP_FORCE flag +isFlipForced() { + return $FLIP_FORCE +} + +# Returns $TRUE if the the paper size will invert orientation from source, $FALSE otherwise +shouldFlip() { + [[ $PGWIDTH -gt $PGHEIGHT && $RESIZE_WIDTH -lt $RESIZE_HEIGHT ]] || [[ $PGWIDTH -lt $PGHEIGHT && $RESIZE_WIDTH -gt $RESIZE_HEIGHT ]] && return $TRUE + return $FALSE +} + + ########################## INITIALIZERS ######################### # Loads external dependencies and checks for errors @@ -241,9 +287,9 @@ initDeps() { vprint "Checking for basename, grep, ghostscript and bcmath" basename "" >/dev/null 2>&1 || printDependency 'basename' - notIsAvailable "$GREPBIN" && printDependency 'grep' - notIsAvailable "$GSBIN" && printDependency 'ghostscript' - notIsAvailable "$BCBIN" && printDependency 'bc' + isNotAvailable "$GREPBIN" && printDependency 'grep' + isNotAvailable "$GSBIN" && printDependency 'ghostscript' + isNotAvailable "$BCBIN" && printDependency 'bc' return $TRUE } @@ -251,16 +297,16 @@ initDeps() { checkDeps() { if [[ $MODE = "IDENTIFY" ]]; then vprint "Checking for imagemagick's identify" - if notIsAvailable "$IDBIN"; then printDependency 'imagemagick'; fi + if isNotAvailable "$IDBIN"; then printDependency 'imagemagick'; fi fi if [[ $MODE = "PDFINFO" ]]; then vprint "Checking for pdfinfo" - if notIsAvailable "$PDFINFOBIN"; then printDependency 'pdfinfo'; fi + if isNotAvailable "$PDFINFOBIN"; then printDependency 'pdfinfo'; fi fi if [[ $MODE = "MDLS" ]]; then vprint "Checking for MacOS mdls" - if notIsAvailable "$MDLSBIN"; then - initError 'mdls executable was not found! Is this even MacOS?' $EXIT_MAC_MDLS_NOT_FOUND 'nobanner' + if isNotAvailable "$MDLSBIN"; then + initError 'mdls executable was not found! Is this even MacOS?' $EXIT_MAC_MDLS_NOT_FOUND fi fi return $TRUE @@ -271,73 +317,123 @@ checkDeps() { # Parse options getOptions() { - while getopts ":vhVis:m:r:pf:a:" o; do - case "${o}" in - v) - ((VERBOSE++)) - ;; - h) - printHelp - exit $EXIT_SUCCESS - ;; - V) - printVersion 3 - exit $EXIT_SUCCESS - ;; - i) - JUST_IDENTIFY=$TRUE - ;; - s) - parseScale ${OPTARG} - ;; - m) - parseMode ${OPTARG} - ;; - r) - parsePaperResize ${OPTARG} - ;; - p) - printPaperInfo - exit $EXIT_SUCCESS - ;; - f) - parseFlipDetectionMode ${OPTARG} - ;; - a) - parseAutoRotationMode ${OPTARG} - ;; + local _optArgs=() # things that do not start with a '-' + local _tgtFile="" # to set $OUTFILEPDF + local _currParam="" # to enable case-insensitiveness + while [ ${#} -gt 0 ]; do + if [[ "${1:0:2}" = '--' ]]; then + # Long Option, get lowercase version + _currParam="$(lowercase ${1})" + elif [[ "${1:0:1}" = '-' ]]; then + # short Option, just assign + _currParam="${1}" + else + # file name arguments, store as is and reset loop + _optArgs+=("$1") + shift + continue + fi + case "$_currParam" in + -v|--verbose) + ((VERBOSE++)) + shift + ;; + -n|--no-overwrite|--nooverwrite) + ABORT_ON_OVERWRITE=$TRUE + shift + ;; + -h|--help) + printHelp + exit $EXIT_SUCCESS + ;; + -V|--version) + printVersion 3 + exit $EXIT_SUCCESS + ;; + -i|--identify|--info) + JUST_IDENTIFY=$TRUE + shift + ;; + -s|--scale|--setscale|--set-scale) + shift + parseScale "$1" + shift + ;; + -m|--mode|--paperdetect|--paper-detect|--pagesizemode|--page-size-mode) + shift + parseMode "$1" + shift + ;; + -r|--resize) + shift + parsePaperResize "$1" + shift + ;; + -p|--printpapers|--print-papers|--listpapers|--list-papers) + printPaperInfo + exit $EXIT_SUCCESS + ;; + -f|--flipdetection|--flip-detection|--flip-mode|--flipmode|--flipdetect|--flip-detect) + shift + parseFlipDetectionMode "$1" + shift + ;; + -a|--autorotation|--auto-rotation|--autorotate|--auto-rotate) + shift + parseAutoRotationMode "$1" + shift + ;; *) - initError "Invalid Option: -$OPTARG" $EXIT_INVALID_OPTION - ;; + initError "Invalid Parameter: \"$1\"" $EXIT_INVALID_OPTION + ;; esac done - shift $((OPTIND-1)) - + + isEmpty "${_optArgs[2]}" || initError "Seems like you passed an extra file name?"$'\n'"Invalid option: ${_optArgs[2]}" $EXIT_INVALID_OPTION + if [[ $JUST_IDENTIFY -eq $TRUE ]]; then - VERBOSE=0 + isEmpty "${_optArgs[1]}" || initError "Seems like you passed an extra file name?"$'\n'"Invalid option: ${_optArgs[1]}" $EXIT_INVALID_OPTION + VERBOSE=0 # remove verboseness if present fi # Validate input PDF file - INFILEPDF="$1" - isEmpty "$INFILEPDF" && initError "Input file is empty!" $EXIT_NO_INPUT_FILE - isPDF "$INFILEPDF" || initError "Input file is not a PDF file: $INFILEPDF" $EXIT_INPUT_NOT_PDF - isFile "$INFILEPDF" || initError "Input file not found: $INFILEPDF" $EXIT_FILE_NOT_FOUND - - printVersion 1 'verbose' + INFILEPDF="${_optArgs[0]}" + isEmpty "$INFILEPDF" && initError "Input file is empty!" $EXIT_NO_INPUT_FILE + isPDF "$INFILEPDF" || initError "Input file is not a PDF file: $INFILEPDF" $EXIT_INPUT_NOT_PDF + isFile "$INFILEPDF" || initError "Input file not found: $INFILEPDF" $EXIT_FILE_NOT_FOUND + isReadable "$INFILEPDF" || initError "No read access to input file: $INFILEPDF"$'\nPermission Denied' $EXIT_NOREAD_PERMISSION + checkDeps + + if [[ $JUST_IDENTIFY -eq $TRUE ]]; then + return $TRUE # no need to get output file, so return already + fi + + _tgtFile="${_optArgs[1]}" + local _autoName="${INFILEPDF%.*}" # remove possible stupid extension, like .pDF if isMixedMode; then - vprint " Mixed Tasks: Resize & Scale" - isEmpty "$2" && OUTFILEPDF="${INFILEPDF%.pdf}.$(uppercase $RESIZE_PAPER_TYPE).SCALED.pdf" + isEmpty "$_tgtFile" && OUTFILEPDF="${_autoName}.$(uppercase $RESIZE_PAPER_TYPE).SCALED.pdf" elif isResizeMode; then - vprint " Single Task: Resize PDF Paper" - isEmpty "$2" && OUTFILEPDF="${INFILEPDF%.pdf}.$(uppercase $RESIZE_PAPER_TYPE).pdf" + isEmpty "$_tgtFile" && OUTFILEPDF="${_autoName}.$(uppercase $RESIZE_PAPER_TYPE).pdf" else - vprint " Single Task: Scale PDF Contents" - isEmpty "$2" && OUTFILEPDF="${INFILEPDF%.pdf}.SCALED.pdf" + isEmpty "$_tgtFile" && OUTFILEPDF="${_autoName}.SCALED.pdf" fi - isNotEmpty "$2" && OUTFILEPDF="${2%.pdf}.pdf" + isNotEmpty "$_tgtFile" && OUTFILEPDF="${_tgtFile%.pdf}.pdf" + validateOutFile } +# Checks if output file is valid and writable +validateOutFile() { + local _tgtDir="$(dirname "$OUTFILEPDF")" + isDir "$_tgtDir" || initError "Output directory does not exist!"$'\n'"Target Dir: $_tgtDir" $EXIT_NOWRITE_PERMISSION + isAbortOnOverwrite && isFile "$OUTFILEPDF" && initError $'Output file already exists and --no-overwrite was used!\nRemove the "-n" or "--no-overwrite" option if you want to overwrite the file\n'"Target File: $OUTFILEPDF" $EXIT_NOWRITE_PERMISSION + isTouchable "$OUTFILEPDF" || initError "Could not get write permission for output file!"$'\n'"Target File: $OUTFILEPDF"$'\nPermission Denied' $EXIT_NOWRITE_PERMISSION +} + +# Returns $TRUE if we should not overwrite $OUTFILEPDF, $FALSE otherwise +isAbortOnOverwrite() { + return $ABORT_ON_OVERWRITE +} # Parses and validates the scaling factor parseScale() { @@ -375,15 +471,15 @@ parseMode() { MODE="PDFINFO" return $TRUE ;; - *) + a|auto|automatic|adaptive) ADAPTIVEMODE=$TRUE MODE="" - if [[ "$param" != 'a' && "$param" != 'auto' && "$param" != 'automatic' && "$param" != 'adaptive' ]]; then - printError "Error! Invalid PDF Size Detection Mode: \"$1\", using adaptive mode!" - return $FALSE - fi return $TRUE ;; + *) + initError "Invalid PDF Size Detection Mode: \"$1\"" $EXIT_INVALID_OPTION + return $FALSE + ;; esac return $FALSE @@ -401,11 +497,14 @@ parseFlipDetectionMode() { FLIP_DETECTION=$FALSE FLIP_FORCE=$TRUE ;; - *) - [[ "$param" != 'a' && "$param" != 'auto' ]] && printError "Error! Invalid Flip Detection Mode: \"$1\", using automatic mode!" + a|auto|automatic) FLIP_DETECTION=$TRUE FLIP_FORCE=$FALSE ;; + *) + initError "Invalid Flip Detection Mode: \"$1\"" $EXIT_INVALID_OPTION + return $FALSE + ;; esac } @@ -423,11 +522,43 @@ parseAutoRotationMode() { AUTO_ROTATION='/PageByPage' ;; *) - printError "Error! Invalid Auto Rotation Mode: $param, using default: $(basename $AUTO_ROTATION)" + initError "Invalid Auto Rotation Mode: \"$1\"" $EXIT_INVALID_OPTION + return $FALSE ;; esac } +# Validades the a paper resize CLI option and sets the paper to $RESIZE_PAPER_TYPE +parsePaperResize() { + isEmpty "$1" && initError 'Invalid Paper Type: (empty)' $EXIT_INVALID_PAPER_SIZE + local lowercasePaper="$(lowercase $1)" + local customPaper=($lowercasePaper) + if [[ "$customPaper" = 'same' || "$customPaper" = 'keep' || "$customPaper" = 'source' ]]; then + RESIZE_PAPER_TYPE='source' + elif [[ "${customPaper[0]}" = 'custom' ]]; then + if isNotValidMeasure "${customPaper[1]}" || ! isFloatBiggerThanZero "${customPaper[2]}" || ! isFloatBiggerThanZero "${customPaper[3]}"; then + initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom '"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION + fi + RESIZE_PAPER_TYPE="custom" + CUSTOM_RESIZE_PAPER=$TRUE + if isMilimeter "${customPaper[1]}"; then + RESIZE_WIDTH="$(milimetersToPoints "${customPaper[2]}")" + RESIZE_HEIGHT="$(milimetersToPoints "${customPaper[3]}")" + elif isInch "${customPaper[1]}"; then + RESIZE_WIDTH="$(inchesToPoints "${customPaper[2]}")" + RESIZE_HEIGHT="$(inchesToPoints "${customPaper[3]}")" + elif isPoint "${customPaper[1]}"; then + RESIZE_WIDTH="${customPaper[2]}" + RESIZE_HEIGHT="${customPaper[3]}" + else + initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom '"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION + fi + else + isPaperName "$lowercasePaper" || initError "Invalid Paper Type: $1" $EXIT_INVALID_PAPER_SIZE + RESIZE_PAPER_TYPE="$lowercasePaper" + fi +} + ################### PDF PAGE SIZE DETECTION #################### @@ -498,9 +629,9 @@ getPageSize() { # Gets page size using imagemagick's identify getPageSizeImagemagick() { # Sanity and Adaptive together - if notIsFile "$IDBIN" && isNotAdaptiveMode; then + if isNotFile "$IDBIN" && isNotAdaptiveMode; then notAdaptiveFailed "Make sure you installed ImageMagick and have identify on your \$PATH" "ImageMagick's Identify" - elif notIsFile "$IDBIN" && isAdaptiveMode; then + elif isNotFile "$IDBIN" && isAdaptiveMode; then return $FALSE fi @@ -521,13 +652,12 @@ getPageSizeImagemagick() { return $TRUE } - # Gets page size using Mac Quarts mdls getPageSizeMdls() { # Sanity and Adaptive together - if notIsFile "$MDLSBIN" && isNotAdaptiveMode; then + if isNotFile "$MDLSBIN" && isNotAdaptiveMode; then notAdaptiveFailed "Are you even trying this on a Mac?" "Mac Quartz mdls" - elif notIsFile "$MDLSBIN" && isAdaptiveMode; then + elif isNotFile "$MDLSBIN" && isAdaptiveMode; then return $FALSE fi @@ -554,13 +684,12 @@ getPageSizeMdls() { return $TRUE } - # Gets page size using Linux PdfInfo getPageSizePdfInfo() { # Sanity and Adaptive together - if notIsFile "$PDFINFOBIN" && isNotAdaptiveMode; then + if isNotFile "$PDFINFOBIN" && isNotAdaptiveMode; then notAdaptiveFailed "Do you have pdfinfo installed and available on your \$PATH?" "Linux pdfinfo" - elif notIsFile "$PDFINFOBIN" && isAdaptiveMode; then + elif isNotFile "$PDFINFOBIN" && isAdaptiveMode; then return $FALSE fi @@ -582,7 +711,6 @@ getPageSizePdfInfo() { return $TRUE } - # Gets page size using cat and grep getPageSizeCatGrep() { # get MediaBox info from PDF file using grep, these are all possible @@ -647,7 +775,7 @@ vPrintPageSizes() { #################### GHOSTSCRIPT PAPER INFO #################### -# Loads GS paper info to memory +# Loads valid paper info to memory getPaperInfo() { # name inchesW inchesH mmW mmH pointsW pointsH sizesUS="\ @@ -750,7 +878,6 @@ getGSPaperName() { return $FALSE } - # Loads an array with paper names to memory getPaperNames() { paperNames=(a0 a1 a2 a3 a4 a4small a5 a6 a7 a8 a9 a10 isob0 isob1 isob2 isob3 isob4 isob5 isob6 c0 c1 c2 c3 c4 c5 c6 \ @@ -783,8 +910,8 @@ isPaperName() { # Prints all tables with ghostscript paper information printPaperInfo() { - printVersion - echo $'\n'"Valid Ghostscript Paper Sizes accepted"$'\n' + printVersion 3 + echo $'\n'"Paper Sizes Information"$'\n' getPaperInfo printPaperTable "ISO STANDARD" "$sizesISO"; echo printPaperTable "US STANDARD" "$sizesUS"; echo @@ -826,34 +953,6 @@ printPaperTable() { printTableDivider } -# Validades the a paper resize CLI option and sets the paper to $RESIZE_PAPER_TYPE -parsePaperResize() { - isEmpty "$1" && initError 'Invalid Paper Type: (empty)' $EXIT_INVALID_PAPER_SIZE - local lowercasePaper="$(lowercase $1)" - if [[ "$1" = 'custom' ]]; then - if isNotValidMeasure "$2" || ! isFloatBiggerThanZero "$3" || ! isFloatBiggerThanZero "$4"; then - initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom '"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION - fi - RESIZE_PAPER_TYPE="custom" - CUSTOM_RESIZE_PAPER=$TRUE - if isMilimeter "$2"; then - RESIZE_WIDTH="$(milimetersToPoints "$3")" - RESIZE_HEIGHT="$(milimetersToPoints "$4")" - elif isInch "$2"; then - RESIZE_WIDTH="$(inchesToPoints "$3")" - RESIZE_HEIGHT="$(inchesToPoints "$4")" - elif isPoint "$2"; then - RESIZE_WIDTH="$3" - RESIZE_HEIGHT="$4" - else - initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom '"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION - fi - else - isPaperName "$lowercasePaper" || initError "Invalid Paper Type: $1" $EXIT_INVALID_PAPER_SIZE - RESIZE_PAPER_TYPE="$lowercasePaper" - fi -} - # Returns $TRUE if $1 is a valid measurement for a custom paper, $FALSE otherwise isNotValidMeasure() { isMilimeter "$1" || isInch "$1" || isPoint "$1" && return $FALSE @@ -883,28 +982,14 @@ isCustomPaper() { return $CUSTOM_RESIZE_PAPER } +# Returns $FALSE if a custom paper is being used, $TRUE otherwise isNotCustomPaper() { isCustomPaper && return $FALSE return $TRUE } -# Returns $TRUE if the scale was set manually, $FALSE if we are using automatic scaling -isManualScaledMode() { - [[ $AUTOMATIC_SCALING -eq $TRUE ]] && return $FALSE - return $TRUE -} -# Returns true if we are resizing a paper (ignores scaling), false otherwise -isResizeMode() { - isEmpty $RESIZE_PAPER_TYPE && return $FALSE - return $TRUE -} - -# Returns true if we are resizing a paper and the scale was manually set -isMixedMode() { - isResizeMode && isManualScaledMode && return $TRUE - return $FALSE -} +######################### CONVERSIONS ########################## # Prints the lowercase char value for $1 lowercaseChar() { @@ -979,23 +1064,31 @@ pointsToInches() { } -########################## VALIDATORS ########################## +######################## MODE-DETECTION ######################## -# Returns $TRUE if $PGWIDTH OR $PGWIDTH are empty or NOT an Integer, $FALSE otherwise -pageSizeIsInvalid() { - if isNotAnInteger "$PGWIDTH" || isNotAnInteger "$PGHEIGHT"; then - return $TRUE - fi - return $FALSE +# Returns $TRUE if the scale was set manually, $FALSE if we are using automatic scaling +isManualScaledMode() { + [[ $AUTOMATIC_SCALING -eq $TRUE ]] && return $FALSE + return $TRUE } +# Returns true if we are resizing a paper (ignores scaling), false otherwise +isResizeMode() { + isEmpty $RESIZE_PAPER_TYPE && return $FALSE + return $TRUE +} + +# Returns true if we are resizing a paper and the scale was manually set +isMixedMode() { + isResizeMode && isManualScaledMode && return $TRUE + return $FALSE +} # Return $TRUE if adaptive mode is enabled, $FALSE otherwise isAdaptiveMode() { return $ADAPTIVEMODE } - # Return $TRUE if adaptive mode is disabled, $FALSE otherwise isNotAdaptiveMode() { isAdaptiveMode && return $FALSE @@ -1003,13 +1096,22 @@ isNotAdaptiveMode() { } +########################## VALIDATORS ########################## + +# Returns $TRUE if $PGWIDTH OR $PGWIDTH are empty or NOT an Integer, $FALSE otherwise +pageSizeIsInvalid() { + if isNotAnInteger "$PGWIDTH" || isNotAnInteger "$PGHEIGHT"; then + return $TRUE + fi + return $FALSE +} + # Return $TRUE if $1 is empty, $FALSE otherwise isEmpty() { [[ -z "$1" ]] && return $TRUE return $FALSE } - # Return $TRUE if $1 is NOT empty, $FALSE otherwise isNotEmpty() { [[ -z "$1" ]] && return $FALSE @@ -1044,41 +1146,53 @@ isFloatBiggerThanZero() { return $FALSE } +# Returns $TRUE if $1 is readable, $FALSE otherwise +isReadable() { + [[ -r "$1" ]] && return $TRUE + return $FALSE; +} + +# Returns $TRUE if $1 is a directory, $FALSE otherwise +isDir() { + [[ -d "$1" ]] && return $TRUE + return $FALSE; +} + +# Returns 0 if succeded, other integer otherwise +isTouchable() { + touch "$1" 2>/dev/null +} + # Returns $TRUE if $1 has a .pdf extension, false otherwsie isPDF() { - [[ "$1" =~ ^..*\.pdf$ ]] && return $TRUE + [[ "$(lowercase $1)" =~ ^..*\.pdf$ ]] && return $TRUE return $FALSE } - # Returns $TRUE if $1 is a file, false otherwsie isFile() { [[ -f "$1" ]] && return $TRUE return $FALSE } - # Returns $TRUE if $1 is NOT a file, false otherwsie -notIsFile() { +isNotFile() { [[ -f "$1" ]] && return $FALSE return $TRUE } - # Returns $TRUE if $1 is executable, false otherwsie isExecutable() { [[ -x "$1" ]] && return $TRUE return $FALSE } - # Returns $TRUE if $1 is NOT executable, false otherwsie -notIsExecutable() { +isNotExecutable() { [[ -x "$1" ]] && return $FALSE return $TRUE } - # Returns $TRUE if $1 is a file and executable, false otherwsie isAvailable() { if isFile "$1" && isExecutable "$1"; then @@ -1087,10 +1201,9 @@ isAvailable() { return $FALSE } - # Returns $TRUE if $1 is NOT a file or NOT executable, false otherwsie -notIsAvailable() { - if notIsFile "$1" || notIsExecutable "$1"; then +isNotAvailable() { + if isNotFile "$1" || isNotExecutable "$1"; then return $TRUE fi return $FALSE @@ -1114,6 +1227,12 @@ printVersion() { fi } +# Prints input, output file info, if verbosing +vPrintFileInfo() { + vprint " Input File: $INFILEPDF" + vprint " Output File: $OUTFILEPDF" +} + # Prints the scale factor to screen, or custom message vPrintScaleFactor() { local scaleMsg="$SCALE" @@ -1121,7 +1240,6 @@ vPrintScaleFactor() { vprint " Scale Factor: $scaleMsg" } - # Prints help info printHelp() { printVersion 3 @@ -1136,83 +1254,106 @@ Usage: $PDFSCALE_NAME $PDFSCALE_NAME -V Parameters: - -v Verbose mode, prints extra information + -v, --verbose + Verbose mode, prints extra information Use twice for timestamp - -h Print this help to screen and exits - -V Prints version to screen and exits - -m Page size Detection mode - May disable the Adaptive Mode - -i Prints Page Size information to screen and exits - -s Changes the scaling factor or forces scaling - Defaults: $SCALE / no scaling (resize mode) + -h, --help + Print this help to screen and exits + -V, --version + Prints version to screen and exits + -n, --no-overwrite + Aborts execution if the output PDF file already exists + By default, the output file will be overwritten + -m, --mode + Paper size detection mode + Modes: a, adaptive Default mode, tries all the methods below + g, grep Forces the use of Grep method + m, mdls Forces the use of MacOS Quartz mdls + p, pdfinfo Forces the use of PDFInfo + i, identify Forces the use of ImageMagick's Identify + -i, --info + Prints Paper Size information to screen and exits + -s, --scale + Changes the scaling factor or forces mixed mode + Defaults: $SCALE (scale mode) / Disabled (resize mode) MUST be a number bigger than zero Eg. -s 0.8 for 80% of the original size - -r Triggers the Resize Paper Mode - Resize PDF paper proportionally - Uses a valid paper name or a custom defined paper - -f Flip Detection Mode, defaults to 'auto'. - Inverts Width <-> Height of a Resized PDF. - Modes: a, auto - automatic detection, default - f, force - forces flip W <-> H - d, disable - disables flipping - -a GS Auto-Rotation Setting, defaults to 'PageByPage'. - Setting for GS -dAutoRotatePages. - Modes: p, pagebypage - auto-rotates pages individually - a, all - rotates all pages (or none) depending - on a kind of \"majority decision\" - n, none - retains orientation of each page - -p Prints Ghostscript paper info tables to screen + -r, --resize + Triggers the Resize Paper Mode, disables auto-scaling of $SCALE + Resize PDF and fit-to-page + can be: source, custom or a valid std paper name, read below + -f, --flip-detect + Flip Detection Mode, defaults to 'auto' + Inverts Width <-> Height of a Resized PDF + Modes: a, auto Keeps source orientation, default + f, force Forces flip W <-> H + d, disable Disables flipping + -a, auto-rotate + Setting for GS -dAutoRotatePages, defaults to 'PageByPage' + Uses text-orientation detection to set Portrait/Landscape + Modes: p, pagebypage Auto-rotates pages individually + n, none Retains orientation of each page + a, all Rotates all pages (or none) depending + on a kind of \"majority decision\" + -p, --print-papers + Prints Standard Paper info tables to screen and exits Scaling Mode: - The default mode of operation is scaling mode with fixed paper - size and scaling pre-set to $SCALE. By not using the resize mode - you are using scaling mode. Flip-Detection and Auto-Rotation are - disabled in Scaling mode. + - The default mode of operation is scaling mode with fixed paper + size and scaling pre-set to $SCALE + - By not using the resize mode you are using scaling mode + - Flip-Detection and Auto-Rotation are disabled in Scaling mode, + you can use '-r source -s ' to override. Resize Paper Mode: - Disables the default scaling factor! ($SCALE) - Changes the PDF Paper Size in points. Will fit-to-page. + - Disables the default scaling factor! ($SCALE) + - Changes the PDF Paper Size in points. Will fit-to-page Mixed Mode: - In mixed mode both the -s option and -r option must be specified. - The PDF will be first resized then scaled. + - In mixed mode both the -s option and -r option must be specified + - The PDF will be first resized then scaled Output filename: - The output filename is optional. If no file name is passed - the output file will have the same name/destination of the - input file with added suffixes: + - Having the extension .pdf on the output file name is optional, + it will be added if not present. + - The output filename is optional. If no file name is passed + the output file will have the same name/destination of the + input file with added suffixes: .SCALED.pdf is added to scaled files ..pdf is added to resized files ..SCALED.pdf is added in mixed mode -Page Size Detection Modes: - a, adaptive Default mode, tries all the methods below - g, grep Forces the use of grep method - m, mdls Forces the use of MacOS Quartz mdls - p, pdfinfo Forces the use of PDFInfo - i, identify Forces the use of ImageMagick's Identify - -Valid Paper Names: (case-insensitive) +Standard Paper Names: (case-insensitive) $paperList Custom Paper Size: - Paper size can be set manually in Milimeters, Inches or Points. + - Paper size can be set manually in Milimeters, Inches or Points + - Custom paper definition MUST be quoted into a single parameter + - Actual size is applied in points (mms and inches are transformed) + - Measurements: mm, mms, milimeters + pt, pts, points + in, inch, inches Use: $PDFSCALE_NAME -r 'custom ' Ex: $PDFSCALE_NAME -r 'custom mm 300 300' - Measurements can be: mm, inch, pts. - Custom paper definition MUST be quoted into a single parameter. - Actual size is applied in points (mms and inches are transformed). + +Using Source Paper Size: (no-resizing) + - Wildcard 'source' is used used to keep paper size the same as the input + - Usefull to run Flip-Detection and Auto-Rotation without resizing + - Eg. $PDFSCALE_NAME -r source ./input.dpf + +Options and Parameters Parsing: + - From v2.1.0 (long-opts) there is no need to pass file names at the end + - Anything that is not a short-option is case-insensitive + - Short-options: case-sensitive Eg. -v for Verbose, -V for Version + - Long-options: case-insensitive Eg. --SCALE and --scale are the same + - Subparameters: case-insensitive Eg. -m PdFinFo is valid + - Grouping short-options is not supported Eg. -vv, or -vs 0.9 Additional Notes: - - Adaptive Page size detection will try different modes until - it gets a page size. You can force a mode with -m 'mode'. - - Options must be passed before the file names to be parsed. - - Having the extension .pdf on the output file name is optional, - it will be added if not present. - - File and folder names with spaces should be quoted or escaped. - - The scaling is centered and using a scale bigger than 1 may - result on cropping parts of the pdf. - - Most of the options are case-insensitive, Ex: -m PdFinFo + - File and folder names with spaces should be quoted or escaped + - The scaling is centered and using a scale bigger than 1.0 may + result on cropping parts of the PDF + - For detailed paper types information, use: $PDFSCALE_NAME -p Examples: $PDFSCALE_NAME myPdfFile.pdf @@ -1227,16 +1368,14 @@ Examples: " } - # Prints usage info usage() { [[ "$2" != 'nobanner' ]] && printVersion 2 - isNotEmpty "$1" && printError "$1" - printError "Usage: $PDFSCALE_NAME [-v] [-s ] [-m ] [outfile.pdf]" - printError "Try: $PDFSCALE_NAME -h # for help" + isNotEmpty "$1" && printError $'\n'"$1" + printError $'\n'"Usage: $PDFSCALE_NAME [-v] [-s ] [-m ] [-r [-f ] [-a ]] [outfile.pdf]" + printError "Help : $PDFSCALE_NAME -h" } - # Prints Verbose information vprint() { [[ $VERBOSE -eq 0 ]] && return $TRUE @@ -1245,10 +1384,9 @@ vprint() { echo "$timestamp$1" } - # Prints dependency information and aborts execution printDependency() { - #printVersion 2 + printVersion 2 local brewName="$1" [[ "$1" = 'pdfinfo' && "$OSNAME" = "Darwin" ]] && brewName="xpdf" printError $'\n'"ERROR! You need to install the package '$1'"$'\n' @@ -1259,7 +1397,6 @@ printDependency() { exit $EXIT_MISSING_DEPENDENCY } - # Prints initialization errors and aborts execution initError() { local errStr="$1" @@ -1269,19 +1406,15 @@ initError() { exit $exitStat } - # Prints to stderr printError() { echo >&2 "$@" } - - ########################## EXECUTION ########################### initDeps getOptions "${@}" main exit $? -