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.

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