Bash Script to scale and/or resize PDFs from the command line.
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 

1284 linhas
43 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. # Latest Version - 2017 / 05 / 14
  8. #
  9. # This script: https://github.com/tavinus/pdfScale
  10. # Based on: http://ma.juii.net/blog/scale-page-content-of-pdf-files
  11. # And: https://gist.github.com/MichaelJCole/86e4968dbfc13256228a
  12. VERSION="2.0.0"
  13. ###################### EXTERNAL PROGRAMS #######################
  14. GSBIN="" # GhostScript Binary
  15. BCBIN="" # BC Math Binary
  16. IDBIN="" # Identify Binary
  17. PDFINFOBIN="" # PDF Info Binary
  18. MDLSBIN="" # MacOS mdls Binary
  19. ##################### ENVIRONMENT SET-UP #######################
  20. LC_MEASUREMENT="C" # To make sure our numbers have .decimals
  21. LC_ALL="C" # Some languages use , as decimal token
  22. LC_CTYPE="C"
  23. LC_NUMERIC="C"
  24. TRUE=0 # Silly stuff
  25. FALSE=1
  26. ########################### GLOBALS ############################
  27. SCALE="0.95" # scaling factor (0.95 = 95%, e.g.)
  28. VERBOSE=0 # verbosity Level
  29. PDFSCALE_NAME="$(basename $0)" # simplified name of this script
  30. OSNAME="$(uname 2>/dev/null)" # Check where we are running
  31. JUST_IDENTIFY=$FALSE # Flag to just show PDF info
  32. ADAPTIVEMODE=$TRUE # Automatically try to guess best mode
  33. AUTOMATIC_SCALING=$TRUE # Default scaling in $SCALE, override by resize mode
  34. MODE="" # Which page size detection to use
  35. RESIZE_PAPER_TYPE="" # Pre-defined paper to use
  36. CUSTOM_RESIZE_PAPER=$FALSE # If we are using a custom-defined paper
  37. FLIP_DETECTION=$TRUE # If we shoudl run the Flip-detection
  38. FLIP_FORCE=$FALSE # If we should force Flipping
  39. AUTO_ROTATION='/PageByPage' # GS cal auto-rotation setting
  40. PGWIDTH="" # Input PDF Page Width
  41. PGHEIGHT="" # Input PDF Page Height
  42. RESIZE_WIDTH="" # Resized PDF Page Width
  43. RESIZE_HEIGHT="" # Resized PDF Page Height
  44. ########################## EXIT FLAGS ##########################
  45. EXIT_SUCCESS=0
  46. EXIT_ERROR=1
  47. EXIT_INVALID_PAGE_SIZE_DETECTED=10
  48. EXIT_FILE_NOT_FOUND=20
  49. EXIT_INPUT_NOT_PDF=21
  50. EXIT_INVALID_OPTION=22
  51. EXIT_NO_INPUT_FILE=23
  52. EXIT_INVALID_SCALE=24
  53. EXIT_MISSING_DEPENDENCY=25
  54. EXIT_IMAGEMAGIK_NOT_FOUND=26
  55. EXIT_MAC_MDLS_NOT_FOUND=27
  56. EXIT_PDFINFO_NOT_FOUND=28
  57. EXIT_TEMP_FILE_EXISTS=40
  58. EXIT_INVALID_PAPER_SIZE=50
  59. ############################# MAIN #############################
  60. # Main function called at the end
  61. main() {
  62. checkDeps
  63. printPDFSizes
  64. vprint " Input File: $INFILEPDF"
  65. vprint " Output File: $OUTFILEPDF"
  66. getPageSize
  67. vPrintPageSizes ' Source'
  68. local finalRet=$EXIT_ERROR
  69. local tempFile=""
  70. local tempSuffix="$RANDOM$RANDOM""_TEMP_$RANDOM$RANDOM.pdf"
  71. if isMixedMode; then
  72. outputFile="$OUTFILEPDF" # backup outFile name
  73. tempFile="${OUTFILEPDF%.pdf}.$tempSuffix" # set a temp file name
  74. if isFile "$tempFile"; then
  75. printError $'Error! Temporary file name already exists!\n'"File: $tempFile"$'\nAborting execution to avoid overwriting the file.\nPlease Try again...'
  76. exit $EXIT_TEMP_FILE_EXISTS
  77. fi
  78. OUTFILEPDF="$tempFile" # set output to tmp file
  79. pageResize # resize to tmp file
  80. finalRet=$?
  81. INFILEPDF="$tempFile" # get tmp file as input
  82. OUTFILEPDF="$outputFile" # reset final target
  83. PGWIDTH=$RESIZE_WIDTH # we already know the new page size
  84. PGHEIGHT=$RESIZE_HEIGHT # from the last command (Resize)
  85. vPrintPageSizes ' New'
  86. vPrintScaleFactor
  87. pageScale # scale the resized pdf
  88. finalRet=$(($finalRet+$?))
  89. # remove tmp file
  90. rm "$tempFile" >/dev/null 2>&1 || printError "Error when removing temporary file: $tempFile"
  91. elif isResizeMode; then
  92. vPrintScaleFactor "Disabled (resize only)"
  93. pageResize
  94. finalRet=$?
  95. else
  96. local scaleMode=""
  97. isManualScaledMode && scaleMode='(manual)' || scaleMode='(auto)'
  98. vPrintScaleFactor "$SCALE $scaleMode"
  99. pageScale
  100. finalRet=$?
  101. fi
  102. if [[ finalRet -eq $EXIT_SUCCESS ]]; then
  103. vprint " Final Status: File created successfully"
  104. else
  105. vprint " Final Status: Errors were detected. Exit status: $finalRet"
  106. fi
  107. return $finalRet
  108. }
  109. # Prints PDF Info and exits with $EXIT_SUCCESS, but only if $JUST_IDENTIFY is $TRUE
  110. printPDFSizes() {
  111. if [[ $JUST_IDENTIFY -eq $TRUE ]]; then
  112. VERBOSE=0
  113. printVersion 3 " - Paper Sizes"
  114. getPageSize || initError "Could not get pagesize!"
  115. local paperType="$(getGSPaperName $PGWIDTH $PGHEIGHT)"
  116. isEmpty "$paperType" && paperType="NOT Detected"
  117. printf '%s\n' "------------+-----------------------------"
  118. printf " File | %s\n" "$(basename "$INFILEPDF")"
  119. printf " Paper Type | %s\n" "$paperType"
  120. printf '%s\n' "------------+-----------------------------"
  121. printf '%s\n' " | WIDTH x HEIGHT"
  122. printf " Points | %+8s x %-8s\n" "$PGWIDTH" "$PGHEIGHT"
  123. printf " Milimeters | %+8s x %-8s\n" "$(pointsToMilimeters $PGWIDTH)" "$(pointsToMilimeters $PGHEIGHT)"
  124. printf " Inches | %+8s x %-8s\n" "$(pointsToInches $PGWIDTH)" "$(pointsToInches $PGHEIGHT)"
  125. exit $EXIT_SUCCESS
  126. fi
  127. return $EXIT_SUCCESS
  128. }
  129. ###################### GHOSTSCRIPT CALLS #######################
  130. # Runs the ghostscript scaling script
  131. pageScale() {
  132. # Compute translation factors (to center page).
  133. XTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGWIDTH" | "$BCBIN")
  134. YTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGHEIGHT" | "$BCBIN")
  135. vprint " Translation X: $XTRANS"
  136. vprint " Translation Y: $YTRANS"
  137. local increase=$(echo "scale=0; (($SCALE - 1) * 100)/1" | "$BCBIN")
  138. vprint " Run Scaling: $increase %"
  139. # Scale page
  140. "$GSBIN" \
  141. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  142. -dCompatibilityLevel="1.5" -dPDFSETTINGS="/printer" \
  143. -dColorConversionStrategy=/LeaveColorUnchanged \
  144. -dSubsetFonts=true -dEmbedAllFonts=true \
  145. -dDEVICEWIDTHPOINTS=$PGWIDTH -dDEVICEHEIGHTPOINTS=$PGHEIGHT \
  146. -sOutputFile="$OUTFILEPDF" \
  147. -c "<</BeginPage{$SCALE $SCALE scale $XTRANS $YTRANS translate}>> setpagedevice" \
  148. -f "$INFILEPDF"
  149. return $?
  150. }
  151. # Runs the ghostscript paper resize script
  152. pageResize() {
  153. # Get new paper sizes if not custom paper
  154. isNotCustomPaper && getGSPaperSize "$RESIZE_PAPER_TYPE"
  155. vprint " Auto Rotate: $(basename $AUTO_ROTATION)"
  156. # Flip detect
  157. local tmpInverter=""
  158. if [[ $FLIP_DETECTION -eq $TRUE || $FLIP_FORCE -eq $TRUE ]]; then
  159. if [[ $PGWIDTH -gt $PGHEIGHT && $RESIZE_WIDTH -lt $RESIZE_HEIGHT ]] || [[ $FLIP_FORCE -eq $TRUE ]]; then
  160. [[ $FLIP_FORCE -eq $TRUE ]] && vprint " Flip Detect: Forced Mode!" || vprint " Flip Detect: Wrong orientation detected!"
  161. vprint " Inverting Width <-> Height"
  162. tmpInverter=$RESIZE_HEIGHT
  163. RESIZE_HEIGHT=$RESIZE_WIDTH
  164. RESIZE_WIDTH=$tmpInverter
  165. else
  166. vprint " Flip Detect: No change needed"
  167. fi
  168. else
  169. vprint " Flip Detect: Disabled"
  170. fi
  171. vprint " Run Resizing: $(uppercase "$RESIZE_PAPER_TYPE") ( "$RESIZE_WIDTH" x "$RESIZE_HEIGHT" ) pts"
  172. # Change page size
  173. "$GSBIN" \
  174. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  175. -dCompatibilityLevel="1.5" -dPDFSETTINGS="/printer" \
  176. -dColorConversionStrategy=/LeaveColorUnchanged \
  177. -dSubsetFonts=true -dEmbedAllFonts=true \
  178. -dDEVICEWIDTHPOINTS=$RESIZE_WIDTH -dDEVICEHEIGHTPOINTS=$RESIZE_HEIGHT \
  179. -dAutoRotatePages=$AUTO_ROTATION \
  180. -dFIXEDMEDIA -dPDFFitPage \
  181. -sOutputFile="$OUTFILEPDF" \
  182. -f "$INFILEPDF"
  183. return $?
  184. }
  185. ########################## INITIALIZERS #########################
  186. # Loads external dependencies and checks for errors
  187. initDeps() {
  188. GREPBIN="$(which grep 2>/dev/null)"
  189. GSBIN="$(which gs 2>/dev/null)"
  190. BCBIN="$(which bc 2>/dev/null)"
  191. IDBIN=$(which identify 2>/dev/null)
  192. MDLSBIN="$(which mdls 2>/dev/null)"
  193. PDFINFOBIN="$(which pdfinfo 2>/dev/null)"
  194. vprint "Checking for basename, grep, ghostscript and bcmath"
  195. basename "" >/dev/null 2>&1 || printDependency 'basename'
  196. notIsAvailable "$GREPBIN" && printDependency 'grep'
  197. notIsAvailable "$GSBIN" && printDependency 'ghostscript'
  198. notIsAvailable "$BCBIN" && printDependency 'bc'
  199. return $TRUE
  200. }
  201. # Checks for dependencies errors, run after getting options
  202. checkDeps() {
  203. if [[ $MODE = "IDENTIFY" ]]; then
  204. vprint "Checking for imagemagick's identify"
  205. if notIsAvailable "$IDBIN"; then printDependency 'imagemagick'; fi
  206. fi
  207. if [[ $MODE = "PDFINFO" ]]; then
  208. vprint "Checking for pdfinfo"
  209. if notIsAvailable "$PDFINFOBIN"; then printDependency 'pdfinfo'; fi
  210. fi
  211. if [[ $MODE = "MDLS" ]]; then
  212. vprint "Checking for MacOS mdls"
  213. if notIsAvailable "$MDLSBIN"; then
  214. initError 'mdls executable was not found! Is this even MacOS?' $EXIT_MAC_MDLS_NOT_FOUND 'nobanner'
  215. fi
  216. fi
  217. return $TRUE
  218. }
  219. ######################### CLI OPTIONS ##########################
  220. # Parse options
  221. getOptions() {
  222. while getopts ":vhVis:m:r:pf:a:" o; do
  223. case "${o}" in
  224. v)
  225. ((VERBOSE++))
  226. ;;
  227. h)
  228. printHelp
  229. exit $EXIT_SUCCESS
  230. ;;
  231. V)
  232. printVersion
  233. exit $EXIT_SUCCESS
  234. ;;
  235. i)
  236. JUST_IDENTIFY=$TRUE
  237. ;;
  238. s)
  239. parseScale ${OPTARG}
  240. ;;
  241. m)
  242. parseMode ${OPTARG}
  243. ;;
  244. r)
  245. parsePaperResize ${OPTARG}
  246. ;;
  247. p)
  248. printPaperInfo
  249. exit $EXIT_SUCCESS
  250. ;;
  251. f)
  252. parseFlipDetectionMode ${OPTARG}
  253. ;;
  254. a)
  255. parseAutoRotationMode ${OPTARG}
  256. ;;
  257. *)
  258. initError "Invalid Option: -$OPTARG" $EXIT_INVALID_OPTION
  259. ;;
  260. esac
  261. done
  262. shift $((OPTIND-1))
  263. if [[ $JUST_IDENTIFY -eq $TRUE ]]; then
  264. VERBOSE=0
  265. fi
  266. # Validate input PDF file
  267. INFILEPDF="$1"
  268. isEmpty "$INFILEPDF" && initError "Input file is empty!" $EXIT_NO_INPUT_FILE
  269. isPDF "$INFILEPDF" || initError "Input file is not a PDF file: $INFILEPDF" $EXIT_INPUT_NOT_PDF
  270. isFile "$INFILEPDF" || initError "Input file not found: $INFILEPDF" $EXIT_FILE_NOT_FOUND
  271. printVersion 1 'verbose'
  272. if isMixedMode; then
  273. vprint " Mixed Tasks: Resize & Scale"
  274. isEmpty "$2" && OUTFILEPDF="${INFILEPDF%.pdf}.$(uppercase $RESIZE_PAPER_TYPE).SCALED.pdf"
  275. elif isResizeMode; then
  276. vprint " Single Task: Resize PDF Paper"
  277. isEmpty "$2" && OUTFILEPDF="${INFILEPDF%.pdf}.$(uppercase $RESIZE_PAPER_TYPE).pdf"
  278. else
  279. vprint " Single Task: Scale PDF Contents"
  280. isEmpty "$2" && OUTFILEPDF="${INFILEPDF%.pdf}.SCALED.pdf"
  281. fi
  282. isNotEmpty "$2" && OUTFILEPDF="${2%.pdf}.pdf"
  283. }
  284. # Parses and validates the scaling factor
  285. parseScale() {
  286. AUTOMATIC_SCALING=$FALSE
  287. if ! isFloatBiggerThanZero "$1"; then
  288. printError "Invalid factor: $1"
  289. printError "The factor must be a floating point number greater than 0"
  290. printError "Example: for 80% use 0.8"
  291. exit $EXIT_INVALID_SCALE
  292. fi
  293. SCALE="$1"
  294. }
  295. # Parse a forced mode of operation
  296. parseMode() {
  297. local param="$(lowercase $1)"
  298. case "${param}" in
  299. c|catgrep|'cat+grep'|grep|g)
  300. ADAPTIVEMODE=$FALSE
  301. MODE="CATGREP"
  302. return $TRUE
  303. ;;
  304. i|imagemagick|identify)
  305. ADAPTIVEMODE=$FALSE
  306. MODE="IDENTIFY"
  307. return $TRUE
  308. ;;
  309. m|mdls|quartz|mac)
  310. ADAPTIVEMODE=$FALSE
  311. MODE="MDLS"
  312. return $TRUE
  313. ;;
  314. p|pdfinfo)
  315. ADAPTIVEMODE=$FALSE
  316. MODE="PDFINFO"
  317. return $TRUE
  318. ;;
  319. *)
  320. ADAPTIVEMODE=$TRUE
  321. MODE=""
  322. if [[ "$param" != 'a' && "$param" != 'auto' && "$param" != 'automatic' && "$param" != 'adaptive' ]]; then
  323. printError "Error! Invalid PDF Size Detection Mode: \"$1\", using adaptive mode!"
  324. return $FALSE
  325. fi
  326. return $TRUE
  327. ;;
  328. esac
  329. return $FALSE
  330. }
  331. # Parses and validates the scaling factor
  332. parseFlipDetectionMode() {
  333. local param="$(lowercase $1)"
  334. case "${param}" in
  335. d|disable)
  336. FLIP_DETECTION=$FALSE
  337. FLIP_FORCE=$FALSE
  338. ;;
  339. f|force)
  340. FLIP_DETECTION=$FALSE
  341. FLIP_FORCE=$TRUE
  342. ;;
  343. *)
  344. [[ "$param" != 'a' && "$param" != 'auto' ]] && printError "Error! Invalid Flip Detection Mode: \"$1\", using automatic mode!"
  345. FLIP_DETECTION=$TRUE
  346. FLIP_FORCE=$FALSE
  347. ;;
  348. esac
  349. }
  350. # Parses and validates the scaling factor
  351. parseAutoRotationMode() {
  352. local param="$(lowercase $1)"
  353. case "${param}" in
  354. n|none)
  355. AUTO_ROTATION='/None'
  356. ;;
  357. a|all)
  358. AUTO_ROTATION='/All'
  359. ;;
  360. p|pagebypage|auto)
  361. AUTO_ROTATION='/PageByPage'
  362. ;;
  363. *)
  364. printError "Error! Invalid Auto Rotation Mode: $param, using default: $(basename $AUTO_ROTATION)"
  365. ;;
  366. esac
  367. }
  368. ################### PDF PAGE SIZE DETECTION ####################
  369. ################################################################
  370. # Detects operation mode and also runs the adaptive mode
  371. # PAGESIZE LOGIC
  372. # 1- Try to get Mediabox with GREP
  373. # 2- MacOS => try to use mdls
  374. # 3- Try to use pdfinfo
  375. # 4- Try to use identify (imagemagick)
  376. # 5- Fail
  377. ################################################################
  378. getPageSize() {
  379. if isNotAdaptiveMode; then
  380. vprint " Get Page Size: Adaptive Disabled"
  381. if [[ $MODE = "CATGREP" ]]; then
  382. vprint " Method: Grep"
  383. getPageSizeCatGrep
  384. elif [[ $MODE = "MDLS" ]]; then
  385. vprint " Method: Mac Quartz mdls"
  386. getPageSizeMdls
  387. elif [[ $MODE = "PDFINFO" ]]; then
  388. vprint " Method: PDFInfo"
  389. getPageSizePdfInfo
  390. elif [[ $MODE = "IDENTIFY" ]]; then
  391. vprint " Method: ImageMagick's Identify"
  392. getPageSizeImagemagick
  393. else
  394. printError "Error! Invalid Mode: $MODE"
  395. printError "Aborting execution..."
  396. exit $EXIT_INVALID_OPTION
  397. fi
  398. return $TRUE
  399. fi
  400. vprint " Get Page Size: Adaptive Enabled"
  401. vprint " Method: Grep"
  402. getPageSizeCatGrep
  403. if pageSizeIsInvalid && [[ $OSNAME = "Darwin" ]]; then
  404. vprint " Failed"
  405. vprint " Method: Mac Quartz mdls"
  406. getPageSizeMdls
  407. fi
  408. if pageSizeIsInvalid; then
  409. vprint " Failed"
  410. vprint " Method: PDFInfo"
  411. getPageSizePdfInfo
  412. fi
  413. if pageSizeIsInvalid; then
  414. vprint " Failed"
  415. vprint " Method: ImageMagick's Identify"
  416. getPageSizeImagemagick
  417. fi
  418. if pageSizeIsInvalid; then
  419. vprint " Failed"
  420. printError "Error when detecting PDF paper size!"
  421. printError "All methods of detection failed"
  422. printError "You may want to install pdfinfo or imagemagick"
  423. exit $EXIT_INVALID_PAGE_SIZE_DETECTED
  424. fi
  425. return $TRUE
  426. }
  427. # Gets page size using imagemagick's identify
  428. getPageSizeImagemagick() {
  429. # Sanity and Adaptive together
  430. if notIsFile "$IDBIN" && isNotAdaptiveMode; then
  431. notAdaptiveFailed "Make sure you installed ImageMagick and have identify on your \$PATH" "ImageMagick's Identify"
  432. elif notIsFile "$IDBIN" && isAdaptiveMode; then
  433. return $FALSE
  434. fi
  435. # get data from image magick
  436. local identify="$("$IDBIN" -format '%[fx:w] %[fx:h]BREAKME' "$INFILEPDF" 2>/dev/null)"
  437. if isEmpty "$identify" && isNotAdaptiveMode; then
  438. notAdaptiveFailed "ImageMagicks's Identify returned an empty string!"
  439. elif isEmpty "$identify" && isAdaptiveMode; then
  440. return $FALSE
  441. fi
  442. identify="${identify%%BREAKME*}" # get page size only for 1st page
  443. identify=($identify) # make it an array
  444. PGWIDTH=$(printf '%.0f' "${identify[0]}") # assign
  445. PGHEIGHT=$(printf '%.0f' "${identify[1]}") # assign
  446. return $TRUE
  447. }
  448. # Gets page size using Mac Quarts mdls
  449. getPageSizeMdls() {
  450. # Sanity and Adaptive together
  451. if notIsFile "$MDLSBIN" && isNotAdaptiveMode; then
  452. notAdaptiveFailed "Are you even trying this on a Mac?" "Mac Quartz mdls"
  453. elif notIsFile "$MDLSBIN" && isAdaptiveMode; then
  454. return $FALSE
  455. fi
  456. local identify="$("$MDLSBIN" -mdls -name kMDItemPageHeight -name kMDItemPageWidth "$INFILEPDF" 2>/dev/null)"
  457. if isEmpty "$identify" && isNotAdaptiveMode; then
  458. notAdaptiveFailed "Mac Quartz mdls returned an empty string!"
  459. elif isEmpty "$identify" && isAdaptiveMode; then
  460. return $FALSE
  461. fi
  462. identify=${identify//$'\t'/ } # change tab to space
  463. identify=($identify) # make it an array
  464. if [[ "${identify[5]}" = "(null)" || "${identify[2]}" = "(null)" ]] && isNotAdaptiveMode; then
  465. notAdaptiveFailed "There was no metadata to read from the file! Is Spotlight OFF?"
  466. elif [[ "${identify[5]}" = "(null)" || "${identify[2]}" = "(null)" ]] && isAdaptiveMode; then
  467. return $FALSE
  468. fi
  469. PGWIDTH=$(printf '%.0f' "${identify[5]}") # assign
  470. PGHEIGHT=$(printf '%.0f' "${identify[2]}") # assign
  471. return $TRUE
  472. }
  473. # Gets page size using Linux PdfInfo
  474. getPageSizePdfInfo() {
  475. # Sanity and Adaptive together
  476. if notIsFile "$PDFINFOBIN" && isNotAdaptiveMode; then
  477. notAdaptiveFailed "Do you have pdfinfo installed and available on your \$PATH?" "Linux pdfinfo"
  478. elif notIsFile "$PDFINFOBIN" && isAdaptiveMode; then
  479. return $FALSE
  480. fi
  481. # get data from image magick
  482. local identify="$("$PDFINFOBIN" "$INFILEPDF" 2>/dev/null | "$GREPBIN" -i 'Page size:' )"
  483. if isEmpty "$identify" && isNotAdaptiveMode; then
  484. notAdaptiveFailed "Linux PdfInfo returned an empty string!"
  485. elif isEmpty "$identify" && isAdaptiveMode; then
  486. return $FALSE
  487. fi
  488. identify="${identify##*Page size:}" # remove stuff
  489. identify=($identify) # make it an array
  490. PGWIDTH=$(printf '%.0f' "${identify[0]}") # assign
  491. PGHEIGHT=$(printf '%.0f' "${identify[2]}") # assign
  492. return $TRUE
  493. }
  494. # Gets page size using cat and grep
  495. getPageSizeCatGrep() {
  496. # get MediaBox info from PDF file using cat and grep, these are all possible
  497. # /MediaBox [0 0 595 841]
  498. # /MediaBox [ 0 0 595.28 841.89]
  499. # /MediaBox[ 0 0 595.28 841.89 ]
  500. # Get MediaBox data if possible
  501. #local mediaBox="$(cat "$INFILEPDF" | "$GREPBIN" -a '/MediaBox' | "$HEADBIN" -n1)"
  502. #local mediaBox="$("$GREPBIN" -a -e '/MediaBox' "$INFILEPDF" | "$HEADBIN" -n1)"
  503. local mediaBox="$("$GREPBIN" -a -e '/MediaBox' "$INFILEPDF" 2>/dev/null)"$'\n\n'
  504. while read l; do
  505. mediaBox="$l"
  506. break
  507. done <<< "$mediaBox"
  508. mediaBox="${mediaBox##*/MediaBox}"
  509. # No page size data available
  510. if isEmpty "$mediaBox" && isNotAdaptiveMode; then
  511. notAdaptiveFailed "There is no MediaBox in the pdf document!"
  512. elif isEmpty "$mediaBox" && isAdaptiveMode; then
  513. return $FALSE
  514. fi
  515. # remove chars [ and ]
  516. mediaBox="${mediaBox//[}"
  517. mediaBox="${mediaBox//]}"
  518. mediaBox=($mediaBox) # make it an array
  519. mbCount=${#mediaBox[@]} # array size
  520. # sanity
  521. if [[ $mbCount -lt 4 ]]; then
  522. printError "Error when reading the page size!"
  523. printError "The page size information is invalid!"
  524. exit $EXIT_INVALID_PAGE_SIZE_DETECTED
  525. fi
  526. # we are done
  527. PGWIDTH=$(printf '%.0f' "${mediaBox[2]}") # Get Round Width
  528. PGHEIGHT=$(printf '%.0f' "${mediaBox[3]}") # Get Round Height
  529. return $TRUE
  530. }
  531. # Prints error message and exits execution
  532. notAdaptiveFailed() {
  533. local errProgram="$2"
  534. local errStr="$1"
  535. if isEmpty "$2"; then
  536. printError "Error when reading input file!"
  537. printError "Could not determine the page size!"
  538. else
  539. printError "Error! $2 was not found!"
  540. fi
  541. isNotEmpty "$errStr" && printError "$errStr"
  542. printError "Aborting! You may want to try the adaptive mode."
  543. exit $EXIT_INVALID_PAGE_SIZE_DETECTED
  544. }
  545. # Verbose print of the Width and Height (Source or New) to screen
  546. vPrintPageSizes() {
  547. vprint " $1 Width: $PGWIDTH postscript-points"
  548. vprint "$1 Height: $PGHEIGHT postscript-points"
  549. }
  550. #################### GHOSTSCRIPT PAPER INFO ####################
  551. # Loads GS paper info to memory
  552. getPaperInfo() {
  553. # name inchesW inchesH mmW mmH pointsW pointsH
  554. sizesUS="\
  555. 11x17 11.0 17.0 279 432 792 1224
  556. ledger 17.0 11.0 432 279 1224 792
  557. legal 8.5 14.0 216 356 612 1008
  558. letter 8.5 11.0 216 279 612 792
  559. lettersmall 8.5 11.0 216 279 612 792
  560. archE 36.0 48.0 914 1219 2592 3456
  561. archD 24.0 36.0 610 914 1728 2592
  562. archC 18.0 24.0 457 610 1296 1728
  563. archB 12.0 18.0 305 457 864 1296
  564. archA 9.0 12.0 229 305 648 864"
  565. sizesISO="\
  566. a0 33.1 46.8 841 1189 2384 3370
  567. a1 23.4 33.1 594 841 1684 2384
  568. a2 16.5 23.4 420 594 1191 1684
  569. a3 11.7 16.5 297 420 842 1191
  570. a4 8.3 11.7 210 297 595 842
  571. a4small 8.3 11.7 210 297 595 842
  572. a5 5.8 8.3 148 210 420 595
  573. a6 4.1 5.8 105 148 297 420
  574. a7 2.9 4.1 74 105 210 297
  575. a8 2.1 2.9 52 74 148 210
  576. a9 1.5 2.1 37 52 105 148
  577. a10 1.0 1.5 26 37 73 105
  578. isob0 39.4 55.7 1000 1414 2835 4008
  579. isob1 27.8 39.4 707 1000 2004 2835
  580. isob2 19.7 27.8 500 707 1417 2004
  581. isob3 13.9 19.7 353 500 1001 1417
  582. isob4 9.8 13.9 250 353 709 1001
  583. isob5 6.9 9.8 176 250 499 709
  584. isob6 4.9 6.9 125 176 354 499
  585. c0 36.1 51.1 917 1297 2599 3677
  586. c1 25.5 36.1 648 917 1837 2599
  587. c2 18.0 25.5 458 648 1298 1837
  588. c3 12.8 18.0 324 458 918 1298
  589. c4 9.0 12.8 229 324 649 918
  590. c5 6.4 9.0 162 229 459 649
  591. c6 4.5 6.4 114 162 323 459"
  592. sizesJIS="\
  593. jisb0 NA NA 1030 1456 2920 4127
  594. jisb1 NA NA 728 1030 2064 2920
  595. jisb2 NA NA 515 728 1460 2064
  596. jisb3 NA NA 364 515 1032 1460
  597. jisb4 NA NA 257 364 729 1032
  598. jisb5 NA NA 182 257 516 729
  599. jisb6 NA NA 128 182 363 516"
  600. sizesOther="\
  601. flsa 8.5 13.0 216 330 612 936
  602. flse 8.5 13.0 216 330 612 936
  603. halfletter 5.5 8.5 140 216 396 612
  604. hagaki 3.9 5.8 100 148 283 420"
  605. sizesAll="\
  606. $sizesUS
  607. $sizesISO
  608. $sizesJIS
  609. $sizesOther"
  610. }
  611. # Gets a paper size in points and sets it to RESIZE_WIDTH and RESIZE_HEIGHT
  612. getGSPaperSize() {
  613. isEmpty "$sizesall" && getPaperInfo
  614. while read l; do
  615. local cols=($l)
  616. if [[ "$1" == ${cols[0]} ]]; then
  617. RESIZE_WIDTH=${cols[5]}
  618. RESIZE_HEIGHT=${cols[6]}
  619. return $TRUE
  620. fi
  621. done <<< "$sizesAll"
  622. }
  623. # Gets a paper size in points and sets it to RESIZE_WIDTH and RESIZE_HEIGHT
  624. getGSPaperName() {
  625. local w="$(printf "%.0f" $1)"
  626. local h="$(printf "%.0f" $2)"
  627. isEmpty "$sizesall" && getPaperInfo
  628. # Because US Standard has inverted sizes, I need to scan 2 times
  629. # instead of just testing if width is bigger than height
  630. while read l; do
  631. local cols=($l)
  632. if [[ "$w" == ${cols[5]} && "$h" == ${cols[6]} ]]; then
  633. printf "%s Portrait" $(uppercase ${cols[0]})
  634. return $TRUE
  635. fi
  636. done <<< "$sizesAll"
  637. while read l; do
  638. local cols=($l)
  639. if [[ "$w" == ${cols[6]} && "$h" == ${cols[5]} ]]; then
  640. printf "%s Landscape" $(uppercase ${cols[0]})
  641. return $TRUE
  642. fi
  643. done <<< "$sizesAll"
  644. return $FALSE
  645. }
  646. # Loads an array with paper names to memory
  647. getPaperNames() {
  648. 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 \
  649. 11x17 ledger legal letter lettersmall archE archD archC archB archA \
  650. jisb0 jisb1 jisb2 jisb3 jisb4 jisb5 jisb6 \
  651. flsa flse halfletter hagaki)
  652. }
  653. # Prints uppercase paper names to screen (used in help)
  654. printPaperNames() {
  655. isEmpty "$paperNames" && getPaperNames
  656. for i in "${!paperNames[@]}"; do
  657. [[ $i -eq 0 ]] && echo -n -e ' '
  658. [[ $i -ne 0 && $((i % 5)) -eq 0 ]] && echo -n -e $'\n '
  659. ppN="$(uppercase ${paperNames[i]})"
  660. printf "%-14s" "$ppN"
  661. done
  662. echo ""
  663. }
  664. # Returns $TRUE if $! is a valid paper name, $FALSE otherwise
  665. isPaperName() {
  666. isEmpty "$1" && return $FALSE
  667. isEmpty "$paperNames" && getPaperNames
  668. for i in "${paperNames[@]}"; do
  669. [[ "$i" = "$1" ]] && return $TRUE
  670. done
  671. return $FALSE
  672. }
  673. # Prints all tables with ghostscript paper information
  674. printPaperInfo() {
  675. printVersion
  676. echo $'\n'"Valid Ghostscript Paper Sizes accepted"$'\n'
  677. getPaperInfo
  678. printPaperTable "ISO STANDARD" "$sizesISO"; echo
  679. printPaperTable "US STANDARD" "$sizesUS"; echo
  680. printPaperTable "JIS STANDARD *Aproximated Points" "$sizesJIS"; echo
  681. printPaperTable "OTHERS" "$sizesOther"; echo
  682. }
  683. # GS paper table helper, prints a full line
  684. printTableLine() {
  685. echo '+-----------------------------------------------------------------+'
  686. }
  687. # GS paper table helper, prints a line with dividers
  688. printTableDivider() {
  689. echo '+-----------------+-------+-------+-------+-------+-------+-------+'
  690. }
  691. # GS paper table helper, prints a table header
  692. printTableHeader() {
  693. echo '| Name | inchW | inchH | mm W | mm H | pts W | pts H |'
  694. }
  695. # GS paper table helper, prints a table title
  696. printTableTitle() {
  697. printf "| %-64s%s\n" "$1" '|'
  698. }
  699. # GS paper table printer, prints a table for a paper variable
  700. printPaperTable() {
  701. printTableLine
  702. printTableTitle "$1"
  703. printTableLine
  704. printTableHeader
  705. printTableDivider
  706. while read l; do
  707. local cols=($l)
  708. printf "| %-15s | %+5s | %+5s | %+5s | %+5s | %+5s | %+5s |\n" ${cols[*]};
  709. done <<< "$2"
  710. printTableDivider
  711. }
  712. # Validades the a paper resize CLI option and sets the paper to $RESIZE_PAPER_TYPE
  713. parsePaperResize() {
  714. isEmpty "$1" && initError 'Invalid Paper Type: (empty)' $EXIT_INVALID_PAPER_SIZE
  715. local lowercasePaper="$(lowercase $1)"
  716. if [[ "$1" = 'custom' ]]; then
  717. if isNotValidMeasure "$2" || ! isFloatBiggerThanZero "$3" || ! isFloatBiggerThanZero "$4"; then
  718. initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom <measurement> <width> <height>'"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION
  719. fi
  720. RESIZE_PAPER_TYPE="custom"
  721. CUSTOM_RESIZE_PAPER=$TRUE
  722. if isMilimeter "$2"; then
  723. RESIZE_WIDTH="$(milimetersToPoints "$3")"
  724. RESIZE_HEIGHT="$(milimetersToPoints "$4")"
  725. elif isInch "$2"; then
  726. RESIZE_WIDTH="$(inchesToPoints "$3")"
  727. RESIZE_HEIGHT="$(inchesToPoints "$4")"
  728. elif isPoint "$2"; then
  729. RESIZE_WIDTH="$3"
  730. RESIZE_HEIGHT="$4"
  731. else
  732. initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom <measurement> <width> <height>'"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION
  733. fi
  734. else
  735. isPaperName "$lowercasePaper" || initError "Invalid Paper Type: $1" $EXIT_INVALID_PAPER_SIZE
  736. RESIZE_PAPER_TYPE="$lowercasePaper"
  737. fi
  738. }
  739. # Returns $TRUE if $1 is a valid measurement for a custom paper, $FALSE otherwise
  740. isNotValidMeasure() {
  741. isMilimeter "$1" || isInch "$1" || isPoint "$1" && return $FALSE
  742. return $TRUE
  743. }
  744. # Returns $TRUE if $1 is a valid milimeter string, $FALSE otherwise
  745. isMilimeter() {
  746. [[ "$1" = 'mm' || "$1" = 'milimeters' || "$1" = 'milimeter' ]] && return $TRUE
  747. return $FALSE
  748. }
  749. # Returns $TRUE if $1 is a valid inch string, $FALSE otherwise
  750. isInch() {
  751. [[ "$1" = 'in' || "$1" = 'inch' || "$1" = 'inches' ]] && return $TRUE
  752. return $FALSE
  753. }
  754. # Returns $TRUE if $1 is a valid point string, $FALSE otherwise
  755. isPoint() {
  756. [[ "$1" = 'pt' || "$1" = 'pts' || "$1" = 'point' || "$1" = 'points' ]] && return $TRUE
  757. return $FALSE
  758. }
  759. # Returns $TRUE if a custom paper is being used, $FALSE otherwise
  760. isCustomPaper() {
  761. return $CUSTOM_RESIZE_PAPER
  762. }
  763. isNotCustomPaper() {
  764. isCustomPaper && return $FALSE
  765. return $TRUE
  766. }
  767. # Returns $TRUE if the scale was set manually, $FALSE if we are using automatic scaling
  768. isManualScaledMode() {
  769. [[ $AUTOMATIC_SCALING -eq $TRUE ]] && return $FALSE
  770. return $TRUE
  771. }
  772. # Returns true if we are resizing a paper (ignores scaling), false otherwise
  773. isResizeMode() {
  774. isEmpty $RESIZE_PAPER_TYPE && return $FALSE
  775. return $TRUE
  776. }
  777. # Returns true if we are resizing a paper and the scale was manually set
  778. isMixedMode() {
  779. isResizeMode && isManualScaledMode && return $TRUE
  780. return $FALSE
  781. }
  782. # Prints the lowercase char value for $1
  783. lowercaseChar() {
  784. case "$1" in
  785. [A-Z])
  786. n=$(printf "%d" "'$1")
  787. n=$((n+32))
  788. printf \\$(printf "%o" "$n")
  789. ;;
  790. *)
  791. printf "%s" "$1"
  792. ;;
  793. esac
  794. }
  795. # Prints the lowercase version of a string
  796. lowercase() {
  797. word="$@"
  798. for((i=0;i<${#word};i++))
  799. do
  800. ch="${word:$i:1}"
  801. lowercaseChar "$ch"
  802. done
  803. }
  804. # Prints the uppercase char value for $1
  805. uppercaseChar(){
  806. case "$1" in
  807. [a-z])
  808. n=$(printf "%d" "'$1")
  809. n=$((n-32))
  810. printf \\$(printf "%o" "$n")
  811. ;;
  812. *)
  813. printf "%s" "$1"
  814. ;;
  815. esac
  816. }
  817. # Prints the uppercase version of a string
  818. uppercase() {
  819. word="$@"
  820. for((i=0;i<${#word};i++))
  821. do
  822. ch="${word:$i:1}"
  823. uppercaseChar "$ch"
  824. done
  825. }
  826. # Prints the postscript points rounded equivalent from $1 mm
  827. milimetersToPoints() {
  828. local pts=$(echo "scale=8; $1 * 72 / 25.4" | "$BCBIN")
  829. printf '%.0f' "$pts" # Print rounded conversion
  830. }
  831. # Prints the postscript points rounded equivalent from $1 inches
  832. inchesToPoints() {
  833. local pts=$(echo "scale=8; $1 * 72" | "$BCBIN")
  834. printf '%.0f' "$pts" # Print rounded conversion
  835. }
  836. # Prints the mm equivalent from $1 postscript points
  837. pointsToMilimeters() {
  838. local pts=$(echo "scale=8; $1 / 72 * 25.4" | "$BCBIN")
  839. printf '%.0f' "$pts" # Print rounded conversion
  840. }
  841. # Prints the inches equivalent from $1 postscript points
  842. pointsToInches() {
  843. local pts=$(echo "scale=8; $1 / 72" | "$BCBIN")
  844. printf '%.1f' "$pts" # Print rounded conversion
  845. }
  846. ########################## VALIDATORS ##########################
  847. # Returns $TRUE if $PGWIDTH OR $PGWIDTH are empty or NOT an Integer, $FALSE otherwise
  848. pageSizeIsInvalid() {
  849. if isNotAnInteger "$PGWIDTH" || isNotAnInteger "$PGHEIGHT"; then
  850. return $TRUE
  851. fi
  852. return $FALSE
  853. }
  854. # Return $TRUE if adaptive mode is enabled, $FALSE otherwise
  855. isAdaptiveMode() {
  856. return $ADAPTIVEMODE
  857. }
  858. # Return $TRUE if adaptive mode is disabled, $FALSE otherwise
  859. isNotAdaptiveMode() {
  860. isAdaptiveMode && return $FALSE
  861. return $TRUE
  862. }
  863. # Return $TRUE if $1 is empty, $FALSE otherwise
  864. isEmpty() {
  865. [[ -z "$1" ]] && return $TRUE
  866. return $FALSE
  867. }
  868. # Return $TRUE if $1 is NOT empty, $FALSE otherwise
  869. isNotEmpty() {
  870. [[ -z "$1" ]] && return $FALSE
  871. return $TRUE
  872. }
  873. # Returns $TRUE if $1 is an integer, $FALSE otherwise
  874. isAnInteger() {
  875. case $1 in
  876. ''|*[!0-9]*) return $FALSE ;;
  877. *) return $TRUE ;;
  878. esac
  879. }
  880. # Returns $TRUE if $1 is NOT an integer, $FALSE otherwise
  881. isNotAnInteger() {
  882. case $1 in
  883. ''|*[!0-9]*) return $TRUE ;;
  884. *) return $FALSE ;;
  885. esac
  886. }
  887. # Returns $TRUE if $1 is a floating point number (or an integer), $FALSE otherwise
  888. isFloat() {
  889. [[ -n "$1" && "$1" =~ ^-?[0-9]*([.][0-9]+)?$ ]] && return $TRUE
  890. return $FALSE
  891. }
  892. # Returns $TRUE if $1 is a floating point number bigger than zero, $FALSE otherwise
  893. isFloatBiggerThanZero() {
  894. isFloat "$1" && [[ (( $1 > 0 )) ]] && return $TRUE
  895. return $FALSE
  896. }
  897. # Returns $TRUE if $1 has a .pdf extension, false otherwsie
  898. isPDF() {
  899. [[ "$1" =~ ^..*\.pdf$ ]] && return $TRUE
  900. return $FALSE
  901. }
  902. # Returns $TRUE if $1 is a file, false otherwsie
  903. isFile() {
  904. [[ -f "$1" ]] && return $TRUE
  905. return $FALSE
  906. }
  907. # Returns $TRUE if $1 is NOT a file, false otherwsie
  908. notIsFile() {
  909. [[ -f "$1" ]] && return $FALSE
  910. return $TRUE
  911. }
  912. # Returns $TRUE if $1 is executable, false otherwsie
  913. isExecutable() {
  914. [[ -x "$1" ]] && return $TRUE
  915. return $FALSE
  916. }
  917. # Returns $TRUE if $1 is NOT executable, false otherwsie
  918. notIsExecutable() {
  919. [[ -x "$1" ]] && return $FALSE
  920. return $TRUE
  921. }
  922. # Returns $TRUE if $1 is a file and executable, false otherwsie
  923. isAvailable() {
  924. if isFile "$1" && isExecutable "$1"; then
  925. return $TRUE
  926. fi
  927. return $FALSE
  928. }
  929. # Returns $TRUE if $1 is NOT a file or NOT executable, false otherwsie
  930. notIsAvailable() {
  931. if notIsFile "$1" || notIsExecutable "$1"; then
  932. return $TRUE
  933. fi
  934. return $FALSE
  935. }
  936. ###################### PRINTING TO SCREEN ######################
  937. # Prints version
  938. printVersion() {
  939. local vStr=""
  940. [[ "$2" = 'verbose' ]] && vStr=" - Verbose Execution"
  941. local strBanner="$PDFSCALE_NAME v$VERSION$vStr"
  942. if [[ $1 -eq 2 ]]; then
  943. printError "$strBanner"
  944. elif [[ $1 -eq 3 ]]; then
  945. local extra="$(isNotEmpty "$2" && echo "$2")"
  946. echo "$strBanner$extra"
  947. else
  948. vprint "$strBanner"
  949. fi
  950. }
  951. # Prints the scale factor to screen, or custom message
  952. vPrintScaleFactor() {
  953. local scaleMsg="$SCALE"
  954. isNotEmpty "$1" && scaleMsg="$1"
  955. vprint " Scale Factor: $scaleMsg"
  956. }
  957. # Prints help info
  958. printHelp() {
  959. printVersion 3
  960. local paperList="$(printPaperNames)"
  961. echo "
  962. Usage: $PDFSCALE_NAME <inFile.pdf>
  963. $PDFSCALE_NAME -i <inFile.pdf>
  964. $PDFSCALE_NAME [-v] [-s <factor>] [-m <page-detection>] <inFile.pdf> [outfile.pdf]
  965. $PDFSCALE_NAME [-v] [-r <paper>] [-f <flip-detection>] [-a <auto-rotation>] <inFile.pdf> [outfile.pdf]
  966. $PDFSCALE_NAME -p
  967. $PDFSCALE_NAME -h
  968. $PDFSCALE_NAME -V
  969. Parameters:
  970. -v Verbose mode, prints extra information
  971. Use twice for timestamp
  972. -h Print this help to screen and exits
  973. -V Prints version to screen and exits
  974. -m <mode> Page size Detection mode
  975. May disable the Adaptive Mode
  976. -i <file> Prints <file> Page Size information to screen and exits
  977. -s <factor> Changes the scaling factor or forces scaling
  978. Defaults: $SCALE / no scaling (resize mode)
  979. MUST be a number bigger than zero
  980. Eg. -s 0.8 for 80% of the original size
  981. -r <paper> Triggers the Resize Paper Mode
  982. Resize PDF paper proportionally
  983. Uses a valid paper name or a custom defined paper
  984. -f <mode> Flip Detection Mode, defaults to 'auto'.
  985. Inverts Width <-> Height of a Resized PDF.
  986. Modes: a, auto - automatic detection, default
  987. f, force - forces flip W <-> H
  988. d, disable - disables flipping
  989. -a <mode> GS Auto-Rotation Setting, defaults to 'PageByPage'.
  990. Setting for GS -dAutoRotatePages.
  991. Modes: p, pagebypage - auto-rotates pages individually
  992. a, all - rotates all pages (or none) depending
  993. on a kind of \"majority decision\"
  994. n, none - retains orientation of each page
  995. -p Prints Ghostscript paper info tables to screen
  996. Scaling Mode:
  997. The default mode of operation is scaling mode with fixed paper
  998. size and scaling pre-set to $SCALE. By not using the resize mode
  999. you are using scaling mode. Flip-Detection and Auto-Rotation are
  1000. disabled in Scaling mode.
  1001. Resize Paper Mode:
  1002. Disables the default scaling factor! ($SCALE)
  1003. Changes the PDF Paper Size in points. Will fit-to-page.
  1004. Mixed Mode:
  1005. In mixed mode both the -s option and -r option must be specified.
  1006. The PDF will be first resized then scaled.
  1007. Output filename:
  1008. The output filename is optional. If no file name is passed
  1009. the output file will have the same name/destination of the
  1010. input file with added suffixes:
  1011. .SCALED.pdf is added to scaled files
  1012. .<PAPERSIZE>.pdf is added to resized files
  1013. .<PAPERSIZE>.SCALED.pdf is added in mixed mode
  1014. Page Size Detection Modes:
  1015. a, adaptive Default mode, tries all the methods below
  1016. g, grep Forces the use of grep method
  1017. m, mdls Forces the use of MacOS Quartz mdls
  1018. p, pdfinfo Forces the use of PDFInfo
  1019. i, identify Forces the use of ImageMagick's Identify
  1020. Valid Paper Names: (case-insensitive)
  1021. $paperList
  1022. Custom Paper Size:
  1023. Paper size can be set manually in Milimeters, Inches or Points.
  1024. Use: $PDFSCALE_NAME -r 'custom <measurement> <width> <height>'
  1025. Ex: $PDFSCALE_NAME -r 'custom mm 300 300'
  1026. Measurements can be: mm, inch, pts.
  1027. Custom paper definition MUST be quoted into a single parameter.
  1028. Actual size is applied in points (mms and inches are transformed).
  1029. Additional Notes:
  1030. - Adaptive Page size detection will try different modes until
  1031. it gets a page size. You can force a mode with -m 'mode'.
  1032. - Options must be passed before the file names to be parsed.
  1033. - Having the extension .pdf on the output file name is optional,
  1034. it will be added if not present.
  1035. - File and folder names with spaces should be quoted or escaped.
  1036. - The scaling is centered and using a scale bigger than 1 may
  1037. result on cropping parts of the pdf.
  1038. - Most of the options are case-insensitive, Ex: -m PdFinFo
  1039. Examples:
  1040. $PDFSCALE_NAME myPdfFile.pdf
  1041. $PDFSCALE_NAME -i '/home/My Folder/My PDF File.pdf'
  1042. $PDFSCALE_NAME myPdfFile.pdf \"My Scaled Pdf\"
  1043. $PDFSCALE_NAME -v -v myPdfFile.pdf
  1044. $PDFSCALE_NAME -s 0.85 myPdfFile.pdf My\\ Scaled\\ Pdf.pdf
  1045. $PDFSCALE_NAME -m pdfinfo -s 0.80 -v myPdfFile.pdf
  1046. $PDFSCALE_NAME -v -v -m i -s 0.7 myPdfFile.pdf
  1047. $PDFSCALE_NAME -r A4 myPdfFile.pdf
  1048. $PDFSCALE_NAME -v -v -r \"custom mm 252 356\" -s 0.9 -f \"../input file.pdf\" \"../my new pdf\"
  1049. "
  1050. }
  1051. # Prints usage info
  1052. usage() {
  1053. [[ "$2" != 'nobanner' ]] && printVersion 2
  1054. isNotEmpty "$1" && printError "$1"
  1055. printError "Usage: $PDFSCALE_NAME [-v] [-s <factor>] [-m <mode>] <inFile.pdf> [outfile.pdf]"
  1056. printError "Try: $PDFSCALE_NAME -h # for help"
  1057. }
  1058. # Prints Verbose information
  1059. vprint() {
  1060. [[ $VERBOSE -eq 0 ]] && return $TRUE
  1061. timestamp=""
  1062. [[ $VERBOSE -gt 1 ]] && timestamp="$(date +%Y-%m-%d:%H:%M:%S) | "
  1063. echo "$timestamp$1"
  1064. }
  1065. # Prints dependency information and aborts execution
  1066. printDependency() {
  1067. #printVersion 2
  1068. local brewName="$1"
  1069. [[ "$1" = 'pdfinfo' && "$OSNAME" = "Darwin" ]] && brewName="xpdf"
  1070. printError $'\n'"ERROR! You need to install the package '$1'"$'\n'
  1071. printError "Linux apt-get.: sudo apt-get install $1"
  1072. printError "Linux yum.....: sudo yum install $1"
  1073. printError "MacOS homebrew: brew install $brewName"
  1074. printError $'\n'"Aborting..."
  1075. exit $EXIT_MISSING_DEPENDENCY
  1076. }
  1077. # Prints initialization errors and aborts execution
  1078. initError() {
  1079. local errStr="$1"
  1080. local exitStat=$2
  1081. isEmpty "$exitStat" && exitStat=$EXIT_ERROR
  1082. usage "ERROR! $errStr" "$3"
  1083. exit $exitStat
  1084. }
  1085. # Prints to stderr
  1086. printError() {
  1087. echo >&2 "$@"
  1088. }
  1089. ########################## EXECUTION ###########################
  1090. initDeps
  1091. getOptions "${@}"
  1092. main
  1093. exit $?