Bash Script to scale and/or resize PDFs from the command line.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

280 行
7.7 KiB

  1. #!/usr/bin/env bash
  2. # pdfScale.sh
  3. #
  4. # Scale PDF to specified percentage of original size.
  5. #
  6. # Gustavo 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.2.7"
  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. TRUE=0 # Silly stuff
  22. FALSE=1
  23. USEIMGMGK=$FALSE # ImageMagick Flag, will use identify if true
  24. # Prints version
  25. printVersion() {
  26. if [[ $1 -eq 2 ]]; then
  27. echo >&2 "$BASENAME v$VERSION"
  28. else
  29. echo "$BASENAME v$VERSION"
  30. fi
  31. }
  32. # Prints help info
  33. printHelp() {
  34. printVersion
  35. echo "
  36. Usage: $BASENAME [-v] [-s <factor>] [-i] <inFile.pdf> [outfile.pdf]
  37. $BASENAME -h
  38. $BASENAME -V
  39. Parameters:
  40. -v Verbose mode, prints extra information
  41. Use twice for even more information
  42. -h Print this help to screen and exits
  43. -V Prints version to screen and exits
  44. -i Use imagemagick to get page size, defaults false
  45. -s <factor> Changes the scaling factor, defaults to 0.95
  46. MUST be a number bigger than zero.
  47. Eg. -s 0.8 for 80% of the original size
  48. Notes:
  49. - Options must be passed before the file names to be parsed
  50. - The output filename is optional. If no file name is passed
  51. the output file will have the same name/destination of the
  52. input file, with .SCALED.pdf at the end (instead of just .pdf)
  53. - Having the extension .pdf on the output file name is optional,
  54. it will be added if not present
  55. - Should handle file names with spaces without problems
  56. - The scaling is centered and using a scale bigger than 1 may
  57. result on cropping parts of the pdf.
  58. Examples:
  59. $BASENAME myPdfFile.pdf
  60. $BASENAME myPdfFile.pdf myScaledPdf
  61. $BASENAME -v -v myPdfFile.pdf
  62. $BASENAME -s 0.85 myPdfFile.pdf myScaledPdf.pdf
  63. $BASENAME -v -v -s 0.7 myPdfFile.pdf
  64. $BASENAME -h
  65. "
  66. }
  67. # Prints usage info
  68. usage() {
  69. printVersion 2
  70. echo >&2 "Usage: $BASENAME [-v] [-s <factor>] <inFile.pdf> [outfile.pdf]"
  71. echo >&2 "Try: $BASENAME -h # for help"
  72. exit 1
  73. }
  74. # Prints Verbose information
  75. vprint() {
  76. [[ $VERBOSE -eq 0 ]] && return 0
  77. timestamp=""
  78. [[ $VERBOSE -gt 1 ]] && timestamp="$(date +%Y-%m-%d:%H:%M:%S) | "
  79. echo "$timestamp$1"
  80. }
  81. # Prints dependency information and aborts execution
  82. printDependency() {
  83. printVersion 2
  84. echo >&2 $'\n'"ERROR! You need to install the package '$1'"$'\n'
  85. echo >&2 "Linux apt-get.: sudo apt-get install $1"
  86. echo >&2 "Linux yum.....: sudo yum install $1"
  87. echo >&2 "MacOS homebrew: brew install $1"
  88. echo >&2 $'\n'"Aborting..."
  89. exit 3
  90. }
  91. # Parses and validates the scaling factor
  92. parseScale() {
  93. if ! [[ -n "$1" && "$1" =~ ^-?[0-9]*([.][0-9]+)?$ && (($1 > 0 )) ]] ; then
  94. echo >&2 "Invalid factor: $1"
  95. echo >&2 "The factor must be a floating point number greater than 0"
  96. echo >&2 "Example: for 80% use 0.8"
  97. exit 2
  98. fi
  99. SCALE=$1
  100. }
  101. # Gets page size using imagemagick's identify
  102. getPageSizeImagemagick() {
  103. # get data from image magick
  104. local identify="$("$IDBIN" -format '%[fx:w] %[fx:h]BREAKME' "$INFILEPDF" 2>/dev/null)"
  105. identify="${identify%%BREAKME*}" # get page size only for 1st page
  106. identify=($identify) # make it an array
  107. PGWIDTH=${identify[0]} # assign
  108. PGHEIGHT=${identify[1]}
  109. }
  110. # Gets page size using cat and grep
  111. getPageSize() {
  112. # get MediaBox info from PDF file using cat and grep, these are all possible
  113. # /MediaBox [0 0 595 841]
  114. # /MediaBox [ 0 0 595.28 841.89]
  115. # /MediaBox[ 0 0 595.28 841.89 ]
  116. # Get MediaBox data if possible
  117. local mediaBox="$(cat "$INFILEPDF" | grep -a '/MediaBox' | head -n1)"
  118. mediaBox="${mediaBox##*/MediaBox}"
  119. # If no MediaBox, try BBox
  120. if [[ -z $mediaBox ]]; then
  121. mediaBox="$(cat "$INFILEPDF" | grep -a '/BBox' | head -n1)"
  122. mediaBox="${mediaBox##*/BBox}"
  123. fi
  124. # No page size data available
  125. if [[ -z $mediaBox ]]; then
  126. echo "Error when reading input file!"
  127. echo "Could not determine the page size!"
  128. echo "There is no MediaBox or BBox in the pdf document!"
  129. echo "Aborting..."
  130. exit 15
  131. fi
  132. # remove chars [ and ]
  133. mediaBox="${mediaBox//[}"
  134. mediaBox="${mediaBox//]}"
  135. mediaBox=($mediaBox) # make it an array
  136. mbCount=${#mediaBox[@]} # array size
  137. # sanity
  138. if [[ $mbCount -lt 4 ]]; then
  139. echo "Error when reading the page size!"
  140. echo "The page size information is invalid!"
  141. exit 16
  142. fi
  143. # we are done
  144. PGWIDTH=$(printf '%.0f' "${mediaBox[2]}") # Get Round Width
  145. PGHEIGHT=$(printf '%.0f' "${mediaBox[3]}") # Get Round Height
  146. }
  147. # Parse options
  148. while getopts ":vihVs:" o; do
  149. case "${o}" in
  150. v)
  151. ((VERBOSE++))
  152. ;;
  153. h)
  154. printHelp
  155. exit 0
  156. ;;
  157. V)
  158. printVersion
  159. exit 0
  160. ;;
  161. s)
  162. parseScale ${OPTARG}
  163. ;;
  164. i)
  165. USEIMGMGK=$TRUE
  166. ;;
  167. *)
  168. usage
  169. ;;
  170. esac
  171. done
  172. shift $((OPTIND-1))
  173. ######### START EXECUTION
  174. #Intro message
  175. vprint "$(basename $0) v$VERSION - Verbose execution"
  176. # Dependencies
  177. vprint "Checking for ghostscript and bcmath"
  178. command -v gs >/dev/null 2>&1 || printDependency 'ghostscript'
  179. command -v bc >/dev/null 2>&1 || printDependency 'bc'
  180. if [[ $USEIMGMGK -eq $TRUE ]]; then
  181. vprint "Checking for imagemagick's identify"
  182. command -v identify >/dev/null 2>&1 || printDependency 'imagemagick'
  183. fi
  184. # Get dependency binaries
  185. GSBIN=$(which gs 2>/dev/null)
  186. BCBIN=$(which bc 2>/dev/null)
  187. IDBIN=$(which identify 2>/dev/null)
  188. # Verbose scale info
  189. vprint " Scale factor: $SCALE"
  190. # Validate args
  191. [[ $# -lt 1 ]] && { usage; exit 1; }
  192. INFILEPDF="$1"
  193. [[ "$INFILEPDF" =~ ^..*\.pdf$ ]] || { usage; exit 2; }
  194. vprint " Input file: $INFILEPDF"
  195. # Parse output filename
  196. if [[ -z $2 ]]; then
  197. OUTFILEPDF="${INFILEPDF%.pdf}.SCALED.pdf"
  198. else
  199. OUTFILEPDF="${2%.pdf}.pdf"
  200. fi
  201. vprint " Output file: $OUTFILEPDF"
  202. # Set PGWIDTH and PGHEIGHT
  203. if [[ $USEIMGMGK -eq $TRUE ]]; then
  204. getPageSizeImagemagick
  205. else
  206. getPageSize
  207. fi
  208. vprint " Width: $PGWIDTH postscript-points"
  209. vprint " Height: $PGHEIGHT postscript-points"
  210. # Compute translation factors (to center page.
  211. XTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGWIDTH" | "$BCBIN")
  212. YTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGHEIGHT" | "$BCBIN")
  213. vprint " Translation X: $XTRANS"
  214. vprint " Translation Y: $YTRANS"
  215. # Do it.
  216. "$GSBIN" \
  217. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  218. -dCompatibilityLevel="1.5" -dPDFSETTINGS="/printer" \
  219. -dColorConversionStrategy=/LeaveColorUnchanged \
  220. -dSubsetFonts=true -dEmbedAllFonts=true \
  221. -dDEVICEWIDTH=$PGWIDTH -dDEVICEHEIGHT=$PGHEIGHT \
  222. -sOutputFile="$OUTFILEPDF" \
  223. -c "<</BeginPage{$SCALE $SCALE scale $XTRANS $YTRANS translate}>> setpagedevice" \
  224. -f "$INFILEPDF"