Bash Script to scale and/or resize PDFs from the command line.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

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