Bash Script to scale and/or resize PDFs from the command line.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

206 lines
5.7 KiB

  1. #!/usr/bin/env bash
  2. # pdfScale.sh
  3. #
  4. # Scale PDF to specified percentage of original size.
  5. #
  6. # Gutavo Arnosti Neves - 2016 / 07 / 10
  7. #
  8. # This script: https://github.com/tavinus/pdfScale
  9. # Based on: http://ma.juii.net/blog/scale-page-content-of-pdf-files
  10. # And: https://gist.github.com/MichaelJCole/86e4968dbfc13256228a
  11. VERSION="1.1.3"
  12. SCALE="0.95" # scaling factor (0.95 = 95%, e.g.)
  13. VERBOSE=0 # verbosity Level
  14. BASENAME="$(basename $0)" # simplified name of this script
  15. GSBIN="" # Set with which after we check dependencies
  16. BCBIN="" # Set with which after we check dependencies
  17. LC_MEASUREMENT="C" # To make sure our numbers have .decimals
  18. LC_ALL="C" # Some languages use , as decimal token
  19. LC_CTYPE="C"
  20. LC_NUMERIC="C"
  21. printVersion() {
  22. if [[ $1 -eq 2 ]]; then
  23. echo >&2 "$BASENAME v$VERSION"
  24. else
  25. echo "$BASENAME v$VERSION"
  26. fi
  27. }
  28. printHelp() {
  29. printVersion
  30. echo "
  31. Usage: $BASENAME [-v] [-s <factor>] <inFile.pdf> [outfile.pdf]
  32. $BASENAME -h
  33. $BASENAME -V
  34. Parameters:
  35. -v Verbose mode, prints extra information
  36. Use twice for even more information
  37. -h Print this help to screen and exits
  38. -V Prints version to screen and exits
  39. -s <factor> Changes the scaling factor, defaults to 0.95
  40. MUST be a number bigger than zero.
  41. Eg. -s 0.8 for 80% of the original size
  42. Notes:
  43. - Options must be passed before the file names to be parsed
  44. - The output filename is optional. If no file name is passed
  45. the output file will have the same name/destination of the
  46. input file, with .SCALED.pdf at the end (instead of just .pdf)
  47. - Having the extension .pdf on the output file name is optional,
  48. it will be added if not present
  49. - Should handle file names with spaces without problems
  50. - The scaling is centered and using a scale bigger than 1 may
  51. result on cropping parts of the pdf.
  52. Examples:
  53. $BASENAME myPdfFile.pdf
  54. $BASENAME myPdfFile.pdf myScaledPdf
  55. $BASENAME -v -v myPdfFile.pdf
  56. $BASENAME -s 0.85 myPdfFile.pdf myScaledPdf.pdf
  57. $BASENAME -v -v -s 0.7 myPdfFile.pdf
  58. $BASENAME -h
  59. "
  60. }
  61. usage() {
  62. printVersion 2
  63. echo >&2 "Usage: $BASENAME [-v] [-s <factor>] <inFile.pdf> [outfile.pdf]"
  64. echo >&2 "Try: $BASENAME -h # for help"
  65. exit 1
  66. }
  67. vprint() {
  68. [[ $VERBOSE -eq 0 ]] && return 0
  69. timestamp=""
  70. [[ $VERBOSE -gt 1 ]] && timestamp="$(date +%Y-%m-%d:%H:%M:%S) | "
  71. echo "$timestamp$1"
  72. }
  73. printDependency() {
  74. printVersion 2
  75. echo >&2 $'\n'"ERROR! You need to install the package '$1'"$'\n'
  76. echo >&2 "Linux apt-get.: sudo apt-get install $1"
  77. echo >&2 "Linux yum.....: sudo yum install $1"
  78. echo >&2 "MacOS homebrew: brew install $1"
  79. echo >&2 $'\n'"Aborting..."
  80. exit 3
  81. }
  82. parseScale() {
  83. if ! [[ -n "$1" && "$1" =~ ^-?[0-9]*([.][0-9]+)?$ && (($1 > 0 )) ]] ; then
  84. echo >&2 "Invalid factor: $1"
  85. echo >&2 "The factor must be a floating point number greater than 0"
  86. echo >&2 "Example: for 80% use 0.8"
  87. exit 2
  88. fi
  89. SCALE=$1
  90. }
  91. getPageSize() {
  92. # get MediaBox info from PDF file using cat and grep, these are all possible
  93. # /MediaBox [0 0 595 841]
  94. # /MediaBox [ 0 0 595.28 841.89]
  95. # /MediaBox[ 0 0 595.28 841.89 ]
  96. local mediaBox="$(cat "$INFILEPDF" | grep -a '/MediaBox')" # done with externals
  97. if [[ -z $mediaBox ]]; then
  98. mediaBox="$(cat "$INFILEPDF" | grep -a '/BBox')" # if no mediaBox
  99. fi
  100. if [[ -z $mediaBox ]]; then
  101. echo "Error when reading input file!"
  102. echo "Could not determine the page size!"
  103. echo "There is no MediaBox or BBox in the pdf document!"
  104. echo "Aborting..."
  105. exit 15
  106. fi
  107. #mediaBox="/MediaBox [0 0 595 841]"
  108. #echo "mediaBox $mediaBox"
  109. mediaBox="${mediaBox#*0 0 }"
  110. #echo "mediaBox $mediaBox"
  111. PGWIDTH=$(printf '%.0f' "${mediaBox%% *}") # Get Round Width
  112. #echo "PGWIDTH $PGWIDTH"
  113. mediaBox="${mediaBox#* }"
  114. #echo "mediaBox $mediaBox"
  115. PGHEIGHT="${mediaBox%%]*}" # Get value, may have spaces
  116. #echo "PGHEIGHT $PGHEIGHT"
  117. PGHEIGHT=$(printf '%.0f' "${PGHEIGHT%% *}") # Get Round Height
  118. #echo "PGHEIGHT $PGHEIGHT"
  119. vprint " Width: $PGWIDTH postscript-points"
  120. vprint " Height: $PGHEIGHT postscript-points"
  121. }
  122. while getopts ":vhVs:" o; do
  123. case "${o}" in
  124. v)
  125. ((VERBOSE++))
  126. ;;
  127. h)
  128. printHelp
  129. exit 0
  130. ;;
  131. V)
  132. printVersion
  133. exit 0
  134. ;;
  135. s)
  136. parseScale ${OPTARG}
  137. ;;
  138. *)
  139. usage
  140. ;;
  141. esac
  142. done
  143. shift $((OPTIND-1))
  144. vprint "$(basename $0) v$VERSION - Verbose execution"
  145. # Dependencies
  146. vprint "Checking dependencies"
  147. command -v gs >/dev/null 2>&1 || printDependency 'ghostscript'
  148. command -v bc >/dev/null 2>&1 || printDependency 'bc'
  149. GSBIN=$(which gs 2>/dev/null)
  150. BCBIN=$(which bc 2>/dev/null)
  151. vprint " Scale factor: $SCALE"
  152. # Validate args
  153. [[ $# -lt 1 ]] && { usage; exit 1; }
  154. INFILEPDF="$1"
  155. [[ "$INFILEPDF" =~ ^..*\.pdf$ ]] || { usage; exit 2; }
  156. vprint " Input file: $INFILEPDF"
  157. # Parse output filename
  158. if [[ -z $2 ]]; then
  159. OUTFILEPDF="${INFILEPDF%.pdf}.SCALED.pdf"
  160. else
  161. OUTFILEPDF="${2%.pdf}.pdf"
  162. fi
  163. vprint " Output file: $OUTFILEPDF"
  164. # Set PGWIDTH and PGHEIGHT
  165. getPageSize
  166. # Compute translation factors (to center page.
  167. XTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGWIDTH" | "$BCBIN")
  168. YTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGHEIGHT" | "$BCBIN")
  169. vprint " Translation X: $XTRANS"
  170. vprint " Translation Y: $YTRANS"
  171. # Do it.
  172. "$GSBIN" \
  173. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  174. -dCompatibilityLevel="1.5" -dPDFSETTINGS="/printer" \
  175. -dColorConversionStrategy=/LeaveColorUnchanged \
  176. -dSubsetFonts=true -dEmbedAllFonts=true \
  177. -dDEVICEWIDTH=$PGWIDTH -dDEVICEHEIGHT=$PGHEIGHT \
  178. -sOutputFile="$OUTFILEPDF" \
  179. -c "<</BeginPage{$SCALE $SCALE scale $XTRANS $YTRANS translate}>> setpagedevice" \
  180. -f "$INFILEPDF"