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.
 
 

2296 line
83 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 - 2018 / 08 / 09
  8. #
  9. # This script: https://github.com/tavinus/pdfScale
  10. #
  11. # Related: http://ma.juii.net/blog/scale-page-content-of-pdf-files
  12. # And: https://gist.github.com/MichaelJCole/86e4968dbfc13256228a
  13. VERSION="2.4.4"
  14. ###################### EXTERNAL PROGRAMS #######################
  15. GSBIN="" # GhostScript Binary
  16. BCBIN="" # BC Math Binary
  17. IDBIN="" # Identify Binary
  18. PDFINFOBIN="" # PDF Info Binary
  19. MDLSBIN="" # MacOS mdls Binary
  20. ##################### ENVIRONMENT SET-UP #######################
  21. LC_MEASUREMENT="C" # To make sure our numbers have .decimals
  22. LC_ALL="C" # Some languages use , as decimal token
  23. LC_CTYPE="C"
  24. LC_NUMERIC="C"
  25. TRUE=0 # Silly stuff
  26. FALSE=1
  27. ########################### GLOBALS ############################
  28. SCALE="0.95" # scaling factor (0.95 = 95%, e.g.)
  29. VERBOSE=0 # verbosity Level
  30. PDFSCALE_NAME="$(basename $0)" # simplified name of this script
  31. OSNAME="$(uname 2>/dev/null)" # Check where we are running
  32. GS_RUN_STATUS="" # Holds GS error messages, signals errors
  33. INFILEPDF="" # Input PDF file name
  34. OUTFILEPDF="" # Output PDF file name
  35. JUST_IDENTIFY=$FALSE # Flag to just show PDF info
  36. ABORT_ON_OVERWRITE=$FALSE # Flag to abort if OUTFILEPDF already exists
  37. ADAPTIVEMODE=$TRUE # Automatically try to guess best mode
  38. AUTOMATIC_SCALING=$TRUE # Default scaling in $SCALE, disabled in resize mode
  39. MODE="" # Which page size detection to use
  40. RESIZE_PAPER_TYPE="" # Pre-defined paper to use
  41. CUSTOM_RESIZE_PAPER=$FALSE # If we are using a custom-defined paper
  42. FLIP_DETECTION=$TRUE # If we should run the Flip-detection
  43. FLIP_FORCE=$FALSE # If we should force Flipping
  44. AUTO_ROTATION='/PageByPage' # GS call auto-rotation setting
  45. FIT_PAGE='-dPDFFitPage' # GS call resize fit page setting
  46. PGWIDTH="" # Input PDF Page Width
  47. PGHEIGHT="" # Input PDF Page Height
  48. RESIZE_WIDTH="" # Resized PDF Page Width
  49. RESIZE_HEIGHT="" # Resized PDF Page Height
  50. ############################# Image resolution (dpi)
  51. IMAGE_RESOLUTION=300 # 300 is /Printer default
  52. ############################# Image compression setting
  53. # default screen ebook printer prepress
  54. # ColorImageDownsampleType /Subsample /Average /Bicubic /Bicubic /Bicubic
  55. IMAGE_DOWNSAMPLE_TYPE='/Bicubic'
  56. ############################# default PDF profile
  57. # /screen /ebook /printer /prepress /default
  58. # -dPDFSETTINGS=/screen (screen-view-only quality, 72 dpi images)
  59. # -dPDFSETTINGS=/ebook (low quality, 150 dpi images)
  60. # -dPDFSETTINGS=/printer (high quality, 300 dpi images)
  61. # -dPDFSETTINGS=/prepress (high quality, color preserving, 300 dpi imgs)
  62. # -dPDFSETTINGS=/default (almost identical to /screen)
  63. PDF_SETTINGS='/printer'
  64. ############################# default Scaling alignment
  65. VERT_ALIGN="CENTER"
  66. HOR_ALIGN="CENTER"
  67. ############################# Translation Offset to apply
  68. XTRANSOFFSET=0.0
  69. YTRANSOFFSET=0.0
  70. ############################# Background/Bleed color creation
  71. BACKGROUNDTYPE="NONE" # Should be NONE, CMYK or RGB only
  72. BACKGROUNDCOLOR="" # Color parameters for CMYK(4) or RGB(3)
  73. BACKGROUNDCALL="" # Actual PS call to be embedded
  74. BACKGROUNDLOG="No background (default)"
  75. ############################# Execution Flags
  76. SIMULATE=$FALSE # Avoid execution
  77. PRINT_GS_CALL=$FALSE # Print GS Call to stdout
  78. GS_CALL_STRING="" # Buffer
  79. ############################# Project Info
  80. PROJECT_NAME="pdfScale"
  81. PROJECT_URL="https://github.com/tavinus/$PROJECT_NAME"
  82. PROJECT_BRANCH='master'
  83. HTTPS_INSECURE=$FALSE
  84. ASSUME_YES=$FALSE
  85. RUN_SELF_INSTALL=$FALSE
  86. TARGET_LOC="/usr/local/bin/pdfscale"
  87. ########################## EXIT FLAGS ##########################
  88. EXIT_SUCCESS=0
  89. EXIT_ERROR=1
  90. EXIT_INVALID_PAGE_SIZE_DETECTED=10
  91. EXIT_FILE_NOT_FOUND=20
  92. EXIT_INPUT_NOT_PDF=21
  93. EXIT_INVALID_OPTION=22
  94. EXIT_NO_INPUT_FILE=23
  95. EXIT_INVALID_SCALE=24
  96. EXIT_MISSING_DEPENDENCY=25
  97. EXIT_IMAGEMAGIK_NOT_FOUND=26
  98. EXIT_MAC_MDLS_NOT_FOUND=27
  99. EXIT_PDFINFO_NOT_FOUND=28
  100. EXIT_NOWRITE_PERMISSION=29
  101. EXIT_NOREAD_PERMISSION=30
  102. EXIT_TEMP_FILE_EXISTS=40
  103. EXIT_INVALID_PAPER_SIZE=50
  104. EXIT_INVALID_IMAGE_RESOLUTION=51
  105. ############################# MAIN #############################
  106. # Main function called at the end
  107. main() {
  108. printPDFSizes # may exit here
  109. local finalRet=$EXIT_ERROR
  110. if isMixedMode; then
  111. initMain " Mixed Tasks: Resize & Scale"
  112. local tempFile=""
  113. local tempSuffix="$RANDOM$RANDOM""_TEMP_$RANDOM$RANDOM.pdf"
  114. outputFile="$OUTFILEPDF" # backup outFile name
  115. tempFile="${OUTFILEPDF%.pdf}.$tempSuffix" # set a temp file name
  116. if isFile "$tempFile"; then
  117. printError $'Error! Temporary file name already exists!\n'"File: $tempFile"$'\nAborting execution to avoid overwriting the file.\nPlease Try again...'
  118. exit $EXIT_TEMP_FILE_EXISTS
  119. fi
  120. OUTFILEPDF="$tempFile" # set output to tmp file
  121. pageResize # resize to tmp file
  122. finalRet=$?
  123. INFILEPDF="$tempFile" # get tmp file as input
  124. OUTFILEPDF="$outputFile" # reset final target
  125. PGWIDTH=$RESIZE_WIDTH # we already know the new page size
  126. PGHEIGHT=$RESIZE_HEIGHT # from the last command (Resize)
  127. vPrintPageSizes ' New'
  128. vPrintScaleFactor
  129. pageScale # scale the resized pdf
  130. finalRet=$(($finalRet+$?))
  131. # remove tmp file
  132. if isFile "$tempFile"; then
  133. rm "$tempFile" >/dev/null 2>&1 || printError "Error when removing temporary file: $tempFile"
  134. fi
  135. elif isResizeMode; then
  136. initMain " Single Task: Resize PDF Paper"
  137. vPrintScaleFactor "Disabled (resize only)"
  138. pageResize
  139. finalRet=$?
  140. else
  141. initMain " Single Task: Scale PDF Contents"
  142. local scaleMode=""
  143. isManualScaledMode && scaleMode='(manual)' || scaleMode='(auto)'
  144. vPrintScaleFactor "$SCALE $scaleMode"
  145. pageScale
  146. finalRet=$?
  147. fi
  148. if [[ $finalRet -eq $EXIT_SUCCESS ]] && isEmpty "$GS_RUN_STATUS"; then
  149. if isDryRun; then
  150. vprint " Final Status: Simulation completed successfully"
  151. else
  152. vprint " Final Status: File created successfully"
  153. fi
  154. else
  155. vprint " Final Status: Error detected. Exit status: $finalRet"
  156. printError "PdfScale: ERROR!"$'\n'"Ghostscript Debug Info:"$'\n'"$GS_RUN_STATUS"
  157. fi
  158. if isNotEmpty "$GS_CALL_STRING" && shouldPrintGSCall; then
  159. printf "%s" "$GS_CALL_STRING"
  160. fi
  161. return $finalRet
  162. }
  163. # Initializes PDF processing for all modes of operation
  164. initMain() {
  165. printVersion 1 'verbose'
  166. isNotEmpty "$1" && vprint "$1"
  167. local sim="FALSE"
  168. isDryRun && sim="TRUE (Simulating)"
  169. vprint " Dry-Run: $sim"
  170. vPrintFileInfo
  171. getPageSize
  172. vPrintPageSizes ' Source'
  173. }
  174. # Prints PDF Info and exits with $EXIT_SUCCESS, but only if $JUST_IDENTIFY is $TRUE
  175. printPDFSizes() {
  176. if [[ $JUST_IDENTIFY -eq $TRUE ]]; then
  177. VERBOSE=0
  178. printVersion 3 " - Paper Sizes"
  179. getPageSize || initError "Could not get pagesize!"
  180. local paperType="$(getGSPaperName $PGWIDTH $PGHEIGHT)"
  181. isEmpty "$paperType" && paperType="Custom Paper Size"
  182. printf '%s\n' "------------+-----------------------------"
  183. printf " File | %s\n" "$(basename "$INFILEPDF")"
  184. printf " Paper Type | %s\n" "$paperType"
  185. printf '%s\n' "------------+-----------------------------"
  186. printf '%s\n' " | WIDTH x HEIGHT"
  187. printf " Points | %+8s x %-8s\n" "$PGWIDTH" "$PGHEIGHT"
  188. printf " Milimeters | %+8s x %-8s\n" "$(pointsToMilimeters $PGWIDTH)" "$(pointsToMilimeters $PGHEIGHT)"
  189. printf " Inches | %+8s x %-8s\n" "$(pointsToInches $PGWIDTH)" "$(pointsToInches $PGHEIGHT)"
  190. exit $EXIT_SUCCESS
  191. fi
  192. return $EXIT_SUCCESS
  193. }
  194. ###################### GHOSTSCRIPT CALLS #######################
  195. # Runs the ghostscript scaling script
  196. pageScale() {
  197. # Compute translation factors to position pages
  198. CENTERXTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGWIDTH" | "$BCBIN")
  199. CENTERYTRANS=$(echo "scale=6; 0.5*(1.0-$SCALE)/$SCALE*$PGHEIGHT" | "$BCBIN")
  200. BXTRANS=$CENTERXTRANS
  201. BYTRANS=$CENTERYTRANS
  202. if [[ "$VERT_ALIGN" = "TOP" ]]; then
  203. BYTRANS=$(echo "scale=6; 2*$CENTERYTRANS" | "$BCBIN")
  204. elif [[ "$VERT_ALIGN" = "BOTTOM" ]]; then
  205. BYTRANS=0
  206. fi
  207. if [[ "$HOR_ALIGN" = "LEFT" ]]; then
  208. BXTRANS=0
  209. elif [[ "$HOR_ALIGN" = "RIGHT" ]]; then
  210. BXTRANS=$(echo "scale=6; 2*$CENTERXTRANS" | "$BCBIN")
  211. fi
  212. vprint " Vert-Align: $VERT_ALIGN"
  213. vprint " Hor-Align: $HOR_ALIGN"
  214. XTRANS=$(echo "scale=6; $BXTRANS + $XTRANSOFFSET" | "$BCBIN")
  215. YTRANS=$(echo "scale=6; $BYTRANS + $YTRANSOFFSET" | "$BCBIN")
  216. vprint "$(printf ' Translation X: %.2f = %.2f + %.2f (offset)' $XTRANS $BXTRANS $XTRANSOFFSET)"
  217. vprint "$(printf ' Translation Y: %.2f = %.2f + %.2f (offset)' $YTRANS $BYTRANS $YTRANSOFFSET)"
  218. local increase=$(echo "scale=0; (($SCALE - 1) * 100)/1" | "$BCBIN")
  219. vprint " Run Scaling: $increase %"
  220. vprint " Background: $BACKGROUNDLOG"
  221. GS_RUN_STATUS="$GS_RUN_STATUS""$(gsPageScale 2>&1)"
  222. GS_CALL_STRING="$GS_CALL_STRING"$'[GS SCALE CALL STARTS]\n'"$(gsPrintPageScale)"$'\n[GS SCALE CALL ENDS]\n'
  223. return $? # Last command is always returned I think
  224. }
  225. # Runs GS call for scaling, nothing else should run here
  226. gsPageScale() {
  227. if isDryRun; then
  228. return $TRUE
  229. fi
  230. # Scale page
  231. "$GSBIN" \
  232. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  233. -dCompatibilityLevel="1.5" -dPDFSETTINGS="$PDF_SETTINGS" \
  234. -dColorImageResolution=$IMAGE_RESOLUTION -dGrayImageResolution=$IMAGE_RESOLUTION \
  235. -dColorImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" -dGrayImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" \
  236. -dColorConversionStrategy=/LeaveColorUnchanged \
  237. -dSubsetFonts=true -dEmbedAllFonts=true \
  238. -dDEVICEWIDTHPOINTS=$PGWIDTH -dDEVICEHEIGHTPOINTS=$PGHEIGHT \
  239. -sOutputFile="$OUTFILEPDF" \
  240. -c "<</BeginPage{$BACKGROUNDCALL$SCALE $SCALE scale $XTRANS $YTRANS translate}>> setpagedevice" \
  241. -f "$INFILEPDF"
  242. }
  243. # Prints GS call for scaling
  244. gsPrintPageScale() {
  245. local _call_str=""
  246. # Print Scale page command
  247. read -d '' _call_str<< _EOF_
  248. "$GSBIN" \
  249. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  250. -dCompatibilityLevel="1.5" -dPDFSETTINGS="$PDF_SETTINGS" \
  251. -dColorImageResolution=$IMAGE_RESOLUTION -dGrayImageResolution=$IMAGE_RESOLUTION \
  252. -dColorImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" -dGrayImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" \
  253. -dColorConversionStrategy=/LeaveColorUnchanged \
  254. -dSubsetFonts=true -dEmbedAllFonts=true \
  255. -dDEVICEWIDTHPOINTS=$PGWIDTH -dDEVICEHEIGHTPOINTS=$PGHEIGHT \
  256. -sOutputFile="$OUTFILEPDF" \
  257. -c "<</BeginPage{$BACKGROUNDCALL$SCALE $SCALE scale $XTRANS $YTRANS translate}>> setpagedevice" \
  258. -f "$INFILEPDF"
  259. _EOF_
  260. echo -ne "$_call_str"
  261. }
  262. # Runs the ghostscript paper resize script
  263. pageResize() {
  264. # Get paper sizes from source if not resizing
  265. isResizePaperSource && { RESIZE_WIDTH=$PGWIDTH; RESIZE_HEIGHT=$PGHEIGHT; }
  266. # Get new paper sizes if not custom or source paper
  267. isNotCustomPaper && ! isResizePaperSource && getGSPaperSize "$RESIZE_PAPER_TYPE"
  268. vprint " Auto Rotate: $(basename $AUTO_ROTATION)"
  269. runFlipDetect
  270. vprint " Run Resizing: $(uppercase "$RESIZE_PAPER_TYPE") ( "$RESIZE_WIDTH" x "$RESIZE_HEIGHT" ) pts"
  271. GS_RUN_STATUS="$GS_RUN_STATUS""$(gsPageResize 2>&1)"
  272. GS_CALL_STRING="$GS_CALL_STRING"$'[GS RESIZE CALL STARTS]\n'"$(gsPrintPageResize)"$'\n[GS RESIZE CALL ENDS]\n'
  273. return $?
  274. }
  275. # Runs GS call for resizing, nothing else should run here
  276. gsPageResize() {
  277. if isDryRun; then
  278. return $TRUE
  279. fi
  280. # Change page size
  281. "$GSBIN" \
  282. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  283. -dCompatibilityLevel="1.5" -dPDFSETTINGS="$PDF_SETTINGS" \
  284. -dColorImageResolution=$IMAGE_RESOLUTION -dGrayImageResolution=$IMAGE_RESOLUTION \
  285. -dColorImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" -dGrayImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" \
  286. -dColorConversionStrategy=/LeaveColorUnchanged \
  287. -dSubsetFonts=true -dEmbedAllFonts=true \
  288. -dDEVICEWIDTHPOINTS=$RESIZE_WIDTH -dDEVICEHEIGHTPOINTS=$RESIZE_HEIGHT \
  289. -dAutoRotatePages=$AUTO_ROTATION \
  290. -dFIXEDMEDIA $FIT_PAGE \
  291. -sOutputFile="$OUTFILEPDF" \
  292. -f "$INFILEPDF"
  293. return $?
  294. }
  295. # Prints GS call for resizing
  296. gsPrintPageResize() {
  297. # Print Resize page command
  298. local _call_str=""
  299. # Print Scale page command
  300. read -d '' _call_str<< _EOF_
  301. "$GSBIN" \
  302. -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER \
  303. -dCompatibilityLevel="1.5" -dPDFSETTINGS="$PDF_SETTINGS" \
  304. -dColorImageResolution=$IMAGE_RESOLUTION -dGrayImageResolution=$IMAGE_RESOLUTION \
  305. -dColorImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" -dGrayImageDownsampleType="$IMAGE_DOWNSAMPLE_TYPE" \
  306. -dColorConversionStrategy=/LeaveColorUnchanged \
  307. -dSubsetFonts=true -dEmbedAllFonts=true \
  308. -dDEVICEWIDTHPOINTS=$RESIZE_WIDTH -dDEVICEHEIGHTPOINTS=$RESIZE_HEIGHT \
  309. -dAutoRotatePages=$AUTO_ROTATION \
  310. -dFIXEDMEDIA $FIT_PAGE \
  311. -sOutputFile="$OUTFILEPDF" \
  312. -f "$INFILEPDF"
  313. _EOF_
  314. echo -ne "$_call_str"
  315. }
  316. # Returns $TRUE if we should use the source paper size, $FALSE otherwise
  317. isResizePaperSource() {
  318. [[ "$RESIZE_PAPER_TYPE" = 'source' ]] && return $TRUE
  319. return $FALSE
  320. }
  321. # Filp-Detect Logic
  322. runFlipDetect() {
  323. if isFlipForced; then
  324. vprint " Flip Detect: Forced Mode!"
  325. applyFlipRevert
  326. elif isFlipDetectionEnabled && shouldFlip; then
  327. vprint " Flip Detect: Wrong orientation detected!"
  328. applyFlipRevert
  329. elif ! isFlipDetectionEnabled; then
  330. vprint " Flip Detect: Disabled"
  331. else
  332. vprint " Flip Detect: No change needed"
  333. fi
  334. }
  335. # Inverts $RESIZE_HEIGHT with $RESIZE_WIDTH
  336. applyFlipRevert() {
  337. local tmpInverter=""
  338. tmpInverter=$RESIZE_HEIGHT
  339. RESIZE_HEIGHT=$RESIZE_WIDTH
  340. RESIZE_WIDTH=$tmpInverter
  341. vprint " Inverting Width <-> Height"
  342. }
  343. # Returns the $FLIP_DETECTION flag
  344. isFlipDetectionEnabled() {
  345. return $FLIP_DETECTION
  346. }
  347. # Returns the $FLIP_FORCE flag
  348. isFlipForced() {
  349. return $FLIP_FORCE
  350. }
  351. # Returns $TRUE if the the paper size will invert orientation from source, $FALSE otherwise
  352. shouldFlip() {
  353. [[ $PGWIDTH -gt $PGHEIGHT && $RESIZE_WIDTH -lt $RESIZE_HEIGHT ]] || [[ $PGWIDTH -lt $PGHEIGHT && $RESIZE_WIDTH -gt $RESIZE_HEIGHT ]] && return $TRUE
  354. return $FALSE
  355. }
  356. ########################## INITIALIZERS #########################
  357. # Loads external dependencies and checks for errors
  358. initDeps() {
  359. GREPBIN="$(which grep 2>/dev/null)"
  360. GSBIN="$(which gs 2>/dev/null)"
  361. BCBIN="$(which bc 2>/dev/null)"
  362. IDBIN=$(which identify 2>/dev/null)
  363. MDLSBIN="$(which mdls 2>/dev/null)"
  364. PDFINFOBIN="$(which pdfinfo 2>/dev/null)"
  365. vprint "Checking for basename, grep, ghostscript and bcmath"
  366. basename "" >/dev/null 2>&1 || printDependency 'basename'
  367. isNotAvailable "$GREPBIN" && printDependency 'grep'
  368. isNotAvailable "$GSBIN" && printDependency 'ghostscript'
  369. isNotAvailable "$BCBIN" && printDependency 'bc'
  370. return $TRUE
  371. }
  372. # Checks for dependencies errors, run after getting options
  373. checkDeps() {
  374. if [[ $MODE = "IDENTIFY" ]]; then
  375. vprint "Checking for imagemagick's identify"
  376. if isNotAvailable "$IDBIN"; then printDependency 'imagemagick'; fi
  377. fi
  378. if [[ $MODE = "PDFINFO" ]]; then
  379. vprint "Checking for pdfinfo"
  380. if isNotAvailable "$PDFINFOBIN"; then printDependency 'pdfinfo'; fi
  381. fi
  382. if [[ $MODE = "MDLS" ]]; then
  383. vprint "Checking for MacOS mdls"
  384. if isNotAvailable "$MDLSBIN"; then
  385. initError 'mdls executable was not found! Is this even MacOS?' $EXIT_MAC_MDLS_NOT_FOUND
  386. fi
  387. fi
  388. return $TRUE
  389. }
  390. ######################### CLI OPTIONS ##########################
  391. # Parse options
  392. getOptions() {
  393. local _optArgs=() # things that do not start with a '-'
  394. local _tgtFile="" # to set $OUTFILEPDF
  395. local _currParam="" # to enable case-insensitiveness
  396. while [ ${#} -gt 0 ]; do
  397. if [[ "${1:0:2}" = '--' ]]; then
  398. # Long Option, get lowercase version
  399. _currParam="$(lowercase ${1})"
  400. elif [[ "${1:0:1}" = '-' ]]; then
  401. # short Option, just assign
  402. _currParam="${1}"
  403. else
  404. # file name arguments, store as is and reset loop
  405. _optArgs+=("$1")
  406. shift
  407. continue
  408. fi
  409. case "$_currParam" in
  410. -v|--verbose)
  411. ((VERBOSE++))
  412. shift
  413. ;;
  414. -n|--no-overwrite|--nooverwrite)
  415. ABORT_ON_OVERWRITE=$TRUE
  416. shift
  417. ;;
  418. -h|--help)
  419. printHelp
  420. exit $EXIT_SUCCESS
  421. ;;
  422. -V|--version)
  423. printVersion 3
  424. exit $EXIT_SUCCESS
  425. ;;
  426. -i|--identify|--info)
  427. JUST_IDENTIFY=$TRUE
  428. shift
  429. ;;
  430. -s|--scale|--setscale|--set-scale)
  431. shift
  432. parseScale "$1"
  433. shift
  434. ;;
  435. -m|--mode|--paperdetect|--paper-detect|--pagesizemode|--page-size-mode)
  436. shift
  437. parseMode "$1"
  438. shift
  439. ;;
  440. -r|--resize)
  441. shift
  442. parsePaperResize "$1"
  443. shift
  444. ;;
  445. -p|--printpapers|--print-papers|--listpapers|--list-papers)
  446. printPaperInfo
  447. exit $EXIT_SUCCESS
  448. ;;
  449. -f|--flipdetection|--flip-detection|--flip-mode|--flipmode|--flipdetect|--flip-detect)
  450. shift
  451. parseFlipDetectionMode "$1"
  452. shift
  453. ;;
  454. -a|--autorotation|--auto-rotation|--autorotate|--auto-rotate)
  455. shift
  456. parseAutoRotationMode "$1"
  457. shift
  458. ;;
  459. --fit-page)
  460. shift
  461. parseFitPageMode "$1"
  462. shift
  463. ;;
  464. --background-gray)
  465. shift
  466. parseGrayBackground $1
  467. shift
  468. ;;
  469. --background-rgb)
  470. shift
  471. parseRGBBackground $1
  472. shift
  473. ;;
  474. --background-cmyk)
  475. shift
  476. parseCMYKBackground $1
  477. shift
  478. ;;
  479. --pdf-settings)
  480. shift
  481. parsePDFSettings "$1"
  482. shift
  483. ;;
  484. --image-downsample)
  485. shift
  486. parseImageDownSample "$1"
  487. shift
  488. ;;
  489. --image-resolution)
  490. shift
  491. parseImageResolution "$1"
  492. shift
  493. ;;
  494. --horizontal-alignment|--hor-align|--xalign|--x-align)
  495. shift
  496. parseHorizontalAlignment "$1"
  497. shift
  498. ;;
  499. --vertical-alignment|--ver-align|--vert-align|--yalign|--y-align)
  500. shift
  501. parseVerticalAlignment "$1"
  502. shift
  503. ;;
  504. --xtrans|--xtrans-offset|--xoffset)
  505. shift
  506. parseXTransOffset "$1"
  507. shift
  508. ;;
  509. --ytrans|--ytrans-offset|--yoffset)
  510. shift
  511. parseYTransOffset "$1"
  512. shift
  513. ;;
  514. --simulate|--dry-run)
  515. SIMULATE=$TRUE
  516. shift
  517. ;;
  518. --install|--self-install)
  519. RUN_SELF_INSTALL=$TRUE
  520. shift
  521. if [[ ${1:0:1} != "-" ]]; then
  522. TARGET_LOC="$1"
  523. shift
  524. fi
  525. ;;
  526. --upgrade|--self-upgrade)
  527. RUN_SELF_UPGRADE=$TRUE
  528. shift
  529. ;;
  530. --insecure|--no-check-certificate)
  531. HTTPS_INSECURE=$TRUE
  532. shift
  533. ;;
  534. --yes|--assume-yes)
  535. ASSUME_YES=$TRUE
  536. shift
  537. ;;
  538. --print-gs-call|--gs-call)
  539. PRINT_GS_CALL=$TRUE
  540. shift
  541. ;;
  542. *)
  543. initError "Invalid Parameter: \"$1\"" $EXIT_INVALID_OPTION
  544. ;;
  545. esac
  546. done
  547. shouldInstall && selfInstall "$TARGET_LOC" # WILL EXIT HERE
  548. shouldUpgrade && selfUpgrade # WILL EXIT HERE
  549. isEmpty "${_optArgs[2]}" || initError "Seems like you passed an extra file name?"$'\n'"Invalid option: ${_optArgs[2]}" $EXIT_INVALID_OPTION
  550. if [[ $JUST_IDENTIFY -eq $TRUE ]]; then
  551. isEmpty "${_optArgs[1]}" || initError "Seems like you passed an extra file name?"$'\n'"Invalid option: ${_optArgs[1]}" $EXIT_INVALID_OPTION
  552. VERBOSE=0 # remove verboseness if present
  553. fi
  554. # Validate input PDF file
  555. INFILEPDF="${_optArgs[0]}"
  556. isEmpty "$INFILEPDF" && initError "Input file is empty!" $EXIT_NO_INPUT_FILE
  557. isPDF "$INFILEPDF" || initError "Input file is not a PDF file: $INFILEPDF" $EXIT_INPUT_NOT_PDF
  558. isFile "$INFILEPDF" || initError "Input file not found: $INFILEPDF" $EXIT_FILE_NOT_FOUND
  559. isReadable "$INFILEPDF" || initError "No read access to input file: $INFILEPDF"$'\nPermission Denied' $EXIT_NOREAD_PERMISSION
  560. checkDeps
  561. if [[ $JUST_IDENTIFY -eq $TRUE ]]; then
  562. return $TRUE # no need to get output file, so return already
  563. fi
  564. _tgtFile="${_optArgs[1]}"
  565. local _autoName="${INFILEPDF%.*}" # remove possible stupid extension, like .pDF
  566. if isMixedMode; then
  567. isEmpty "$_tgtFile" && OUTFILEPDF="${_autoName}.$(uppercase $RESIZE_PAPER_TYPE).SCALED.pdf"
  568. elif isResizeMode; then
  569. isEmpty "$_tgtFile" && OUTFILEPDF="${_autoName}.$(uppercase $RESIZE_PAPER_TYPE).pdf"
  570. else
  571. isEmpty "$_tgtFile" && OUTFILEPDF="${_autoName}.SCALED.pdf"
  572. fi
  573. isNotEmpty "$_tgtFile" && OUTFILEPDF="${_tgtFile%.pdf}.pdf"
  574. validateOutFile
  575. }
  576. # Returns $TRUE if the install flag is set
  577. shouldInstall() {
  578. return $RUN_SELF_INSTALL
  579. }
  580. # Returns $TRUE if the upgrade flag is set
  581. shouldUpgrade() {
  582. return $RUN_SELF_UPGRADE
  583. }
  584. # Install pdfScale
  585. selfInstall() {
  586. CURRENT_LOC="$(readlink -f $0)"
  587. TARGET_LOC="$1"
  588. isEmpty "$TARGET_LOC" && TARGET_LOC="/usr/local/bin/pdfscale"
  589. VERBOSE=0
  590. NEED_SUDO=$FALSE
  591. printVersion 3 " - Self Install"
  592. echo ""
  593. echo "Current location : $CURRENT_LOC"
  594. echo "Target location : $TARGET_LOC"
  595. if [[ "$CURRENT_LOC" = "$TARGET_LOC" ]]; then
  596. echo $'\n'"Error! Source and Target locations are the same!"
  597. echo "Cannot copy to itself..."
  598. exit $EXIT_INVALID_OPTION
  599. fi
  600. TARGET_FOLDER="$(dirname $TARGET_LOC)"
  601. local _answer="NO"
  602. if isNotDir "$TARGET_FOLDER"; then
  603. echo $'\nThe target folder does not exist\n > '"$TARGET_FOLDER"
  604. if assumeYes; then
  605. echo ''
  606. _answer="y"
  607. else
  608. read -p $'\nCreate the target folder? Y/y to continue > ' _answer
  609. _answer="$(lowercase $_answer)"
  610. fi
  611. if [[ "$_answer" = "y" || "$_answer" = "yes" ]]; then
  612. _answer="no"
  613. if mkdir -p "$TARGET_FOLDER" 2>/dev/null; then
  614. echo " > Folder Created!"
  615. else
  616. echo $'\n'"There was an error when trying to create the folder."
  617. if assumeYes; then
  618. echo $'\nTrying again with sudo, enter password if needed > '
  619. _answer="y"
  620. else
  621. read -p $'\nDo you want to try again with sudo (as root)? Y/y to continue > ' _answer
  622. _answer="$(lowercase $_answer)"
  623. fi
  624. if [[ "$_answer" = "y" || "$_answer" = "yes" ]]; then
  625. NEED_SUDO=$TRUE
  626. if sudo mkdir -p "$TARGET_FOLDER" 2>/dev/null; then
  627. echo "Folder Created!"
  628. else
  629. echo "There was an error when trying to create the folder."
  630. exit $EXIT_ERROR
  631. fi
  632. else
  633. echo "Exiting..."
  634. exit $EXIT_ERROR
  635. fi
  636. fi
  637. else
  638. echo "Exiting... (cancelled by user)"
  639. exit $EXIT_ERROR
  640. fi
  641. fi
  642. _answer="no"
  643. if isFile "$TARGET_LOC"; then
  644. echo $'\n'"The target file already exists: $TARGET_LOC"
  645. if assumeYes; then
  646. _answer="y"
  647. else
  648. read -p "Y/y to overwrite, anything else to cancel > " _answer
  649. _answer="$(lowercase $_answer)"
  650. fi
  651. if [[ "$_answer" = "y" || "$_answer" = "yes" ]]; then
  652. echo "Target will be replaced!"
  653. else
  654. echo "Exiting... (cancelled by user)"
  655. exit $EXIT_ERROR
  656. fi
  657. fi
  658. if [[ $NEED_SUDO -eq $TRUE ]]; then
  659. if sudo cp "$CURRENT_LOC" "$TARGET_LOC"; then
  660. echo $'\nSuccess! Program installed!'
  661. echo " > $TARGET_LOC"
  662. exit $EXIT_SUCCESS
  663. else
  664. echo "There was an error when trying to install the program."
  665. exit $EXIT_ERROR
  666. fi
  667. fi
  668. if cp "$CURRENT_LOC" "$TARGET_LOC"; then
  669. echo $'\nSuccess! Program installed!'
  670. echo " > $TARGET_LOC"
  671. exit $EXIT_SUCCESS
  672. else
  673. _answer="no"
  674. echo "There was an error when trying to install pdfScale."
  675. if assumeYes; then
  676. echo $'\nTrying again with sudo, enter password if needed > '
  677. _answer="y"
  678. else
  679. read -p $'Do you want to try again with sudo (as root)? Y/y to continue > ' _answer
  680. _answer="$(lowercase $_answer)"
  681. fi
  682. if [[ "$_answer" = "y" || "$_answer" = "yes" ]]; then
  683. NEED_SUDO=$TRUE
  684. if sudo cp "$CURRENT_LOC" "$TARGET_LOC"; then
  685. echo $'\nSuccess! Program installed!'
  686. echo " > $TARGET_LOC"
  687. exit $EXIT_SUCCESS
  688. else
  689. echo "There was an error when trying to install the program."
  690. exit $EXIT_ERROR
  691. fi
  692. else
  693. echo "Exiting... (cancelled by user)"
  694. exit $EXIT_ERROR
  695. fi
  696. fi
  697. exit $EXIT_ERROR
  698. }
  699. # Tries to download with curl or wget
  700. getUrl() {
  701. useInsecure && echo $'\nHTTPS Insecure flag is enabled!\nCertificates will be ignored by curl/wget\n'
  702. local url="$1"
  703. local target="$2"
  704. local _stat=""
  705. if isEmpty "$url" || isEmpty "$target"; then
  706. echo "Error! Invalid parameters for download."
  707. echo "URL > $url"
  708. echo "TARGET > $target"
  709. exit $EXIT_INVALID_OPTION
  710. fi
  711. WGET_BIN="$(which wget 2>/dev/null)"
  712. CURL_BIN="$(which curl 2>/dev/null)"
  713. if isExecutable "$WGET_BIN"; then
  714. useInsecure && WGET_BIN="$WGET_BIN --no-check-certificate"
  715. echo "Downloading file with wget"
  716. _stat="$($WGET_BIN -O "$target" "$url" 2>&1)"
  717. if [[ $? -eq 0 ]]; then
  718. return $TRUE
  719. else
  720. echo "Error when downloading file!"
  721. echo " > $url"
  722. echo "Status:"
  723. echo "$_stat"
  724. exit $EXIT_ERROR
  725. fi
  726. elif isExecutable "$CURL_BIN"; then
  727. useInsecure && CURL_BIN="$CURL_BIN --insecure"
  728. echo "Downloading file with curl"
  729. _stat="$($CURL_BIN -o "$target" "$url" 2>&1)"
  730. if [[ $? -eq 0 ]]; then
  731. return $TRUE
  732. else
  733. echo "Error when downloading file!"
  734. echo " > $url"
  735. echo "Status:"
  736. echo "$_stat"
  737. exit $EXIT_ERROR
  738. fi
  739. else
  740. echo "Error! Could not find Wget or Curl to perform download."
  741. echo "Please install either curl or wget and try again."
  742. exit $EXIT_FILE_NOT_FOUND
  743. fi
  744. }
  745. # Tries to remove temporary files from upgrade
  746. clearUpgrade() {
  747. echo $'\nCleaning up downloaded files from /tmp'
  748. if isFile "$TMP_TARGET"; then
  749. echo -n " > $TMP_TARGET > "
  750. rm "$TMP_TARGET" 2>/dev/null && echo "Ok" || echo "Fail"
  751. else
  752. echo " > no temporary tarball was found to remove"
  753. fi
  754. if isDir "$TMP_EXTRACTED"; then
  755. echo -n " > $TMP_EXTRACTED > "
  756. rm -rf "$TMP_EXTRACTED" 2>/dev/null && echo "Ok" || echo "Fail"
  757. else
  758. echo " > no temporary master folder was found to remove"
  759. fi
  760. }
  761. # Exit upgrade with message and status code
  762. # $1 Mensagem (printed if not empty)
  763. # $2 Status (defaults to $EXIT_ERROR)
  764. exitUpgrade() {
  765. isDir "$_cwd" && cd "$_cwd"
  766. isNotEmpty "$1" && echo "$1"
  767. clearUpgrade
  768. isNotEmpty "$2" && exit $2
  769. exit $EXIT_ERROR
  770. }
  771. # Downloads current version from github's MASTER branch
  772. selfUpgrade() {
  773. CURRENT_LOC="$(readlink -f $0)"
  774. _cwd="$(pwd)"
  775. local _cur_tstamp="$(date '+%Y%m%d-%H%M%S')"
  776. TMP_DIR='/tmp'
  777. TMP_TARGET="$TMP_DIR/pdfScale_$_cur_tstamp.tar.gz"
  778. TMP_EXTRACTED="$TMP_DIR/$PROJECT_NAME-$PROJECT_BRANCH"
  779. local _answer="no"
  780. printVersion 3 " - Self Upgrade"
  781. echo $'\n'"Preparing download to temp folder"
  782. echo " > $TMP_TARGET"
  783. getUrl "$PROJECT_URL/archive/$PROJECT_BRANCH.tar.gz" "$TMP_TARGET"
  784. if isNotFile "$TMP_TARGET"; then
  785. echo "Error! Could not find downloaded file!"
  786. exit $EXIT_FILE_NOT_FOUND
  787. fi
  788. echo $'\n'"Extracting compressed file"
  789. cd "$TMP_DIR"
  790. if ! (tar xzf "$TMP_TARGET" 2>/dev/null || gtar xzf "$TMP_TARGET" 2>/dev/null); then
  791. exitUpgrade "Extraction error."
  792. fi
  793. if ! cd "$TMP_EXTRACTED" 2>/dev/null; then
  794. exitUpgrade $'Error when accessing temporary folder\n > '"$TMP_EXTRACTED"
  795. fi
  796. if ! chmod +x pdfScale.sh; then
  797. exitUpgrade $'Error when setting new pdfScale to executable\n > '"$TMP_EXTRACTED/pdfScale.sh"
  798. fi
  799. local newver="$(./pdfScale.sh --version 2>/dev/null)"
  800. local curver="$(printVersion 3 2>/dev/null)"
  801. newver=($newver)
  802. curver=($curver)
  803. newver=${newver[1]#v}
  804. curver=${curver[1]#v}
  805. echo $'\n'" Current Version is: $curver"
  806. echo "Downloaded Version is: $newver"$'\n'
  807. if [[ "$newver" = "$curver" ]]; then
  808. echo "Seems like we have downloaded the same version that is installed."
  809. elif isBiggerVersion "$newver" "$curver"; then
  810. echo "Seems like the downloaded version is newer that the one installed."
  811. elif isBiggerVersion "$curver" "$newver"; then
  812. echo "Seems like the downloaded version is older that the one installed."
  813. echo "It is basically a miracle or you have came from the future with this version!"
  814. echo "BE CAREFUL NOT TO DELETE THE BETA/ALPHA VERSION WITH THIS UPDATE!"
  815. else
  816. exitUpgrade "An unidentified error has ocurred. Exiting..."
  817. fi
  818. if assumeYes; then
  819. echo $'\n'"Assume yes activated, current version will be replaced with master branch"
  820. _answer="y"
  821. else
  822. echo $'\n'"Are you sure that you want to replace the current installation with the downloaded one?"
  823. read -p "Y/y to continue, anything else to cancel > " _answer
  824. _answer="$(lowercase $_answer)"
  825. fi
  826. echo
  827. if [[ "$_answer" = "y" || "$_answer" = "yes" ]]; then
  828. echo "Upgrading..."
  829. if cp "./pdfScale.sh" "$CURRENT_LOC" 2>/dev/null; then
  830. exitUpgrade $'\n'"Success! Upgrade finished!"$'\n'" > $CURRENT_LOC" $EXIT_SUCCESS
  831. else
  832. _answer="no"
  833. echo $'\n'"There was an error when copying the new version."
  834. if assumeYes; then
  835. echo $'\nAssume yes activated, retrying with sudo.\nEnter password if needed > \n'
  836. _answer="y"
  837. else
  838. echo "Do you want to retry using sudo (as root)?"
  839. read -p "Y/y to continue, anything else to cancel > " _answer
  840. fi
  841. _answer="$(lowercase $_answer)"
  842. if [[ "$_answer" = "y" || "$_answer" = "yes" ]]; then
  843. echo "Upgrading with sudo..."
  844. if sudo cp "./pdfScale.sh" "$CURRENT_LOC" 2>/dev/null; then
  845. exitUpgrade $'\n'"Success! Upgrade finished!"$'\n'" > $CURRENT_LOC" $EXIT_SUCCESS
  846. else
  847. exitUpgrade "There was an error when copying the new version."
  848. fi
  849. else
  850. exitUpgrade "Exiting... (cancelled by user)"
  851. fi
  852. fi
  853. exitUpgrade "An unidentified error has ocurred. Exiting..."
  854. else
  855. exitUpgrade "Exiting... (cancelled by user)"
  856. fi
  857. exitUpgrade "An unidentified error has ocurred. Exiting..."
  858. }
  859. # Compares versions with x.x.x format
  860. isBiggerVersion() {
  861. local OIFS=$IFS
  862. IFS='.'
  863. local _first=($1)
  864. local _second=($2)
  865. local _ret=$FALSE
  866. if [[ ${_first[0]} -gt ${_second[0]} ]]; then
  867. _ret=$TRUE
  868. elif [[ ${_first[0]} -lt ${_second[0]} ]]; then
  869. _ret=$FALSE
  870. elif [[ ${_first[1]} -gt ${_second[1]} ]]; then
  871. _ret=$TRUE
  872. elif [[ ${_first[1]} -lt ${_second[1]} ]]; then
  873. _ret=$FALSE
  874. elif [[ ${_first[2]} -gt ${_second[2]} ]]; then
  875. _ret=$TRUE
  876. elif [[ ${_first[2]} -lt ${_second[2]} ]]; then
  877. _ret=$FALSE
  878. fi
  879. IFS=$OIFS
  880. return $_ret
  881. }
  882. # Checks if output file is valid and writable
  883. validateOutFile() {
  884. local _tgtDir="$(dirname "$OUTFILEPDF")"
  885. isDir "$_tgtDir" || initError "Output directory does not exist!"$'\n'"Target Dir: $_tgtDir" $EXIT_NOWRITE_PERMISSION
  886. isAbortOnOverwrite && isFile "$OUTFILEPDF" && initError $'Output file already exists and --no-overwrite was used!\nRemove the "-n" or "--no-overwrite" option if you want to overwrite the file\n'"Target File: $OUTFILEPDF" $EXIT_NOWRITE_PERMISSION
  887. isTouchable "$OUTFILEPDF" || initError "Could not get write permission for output file!"$'\n'"Target File: $OUTFILEPDF"$'\nPermission Denied' $EXIT_NOWRITE_PERMISSION
  888. }
  889. # Returns $TRUE if we should not overwrite $OUTFILEPDF, $FALSE otherwise
  890. isAbortOnOverwrite() {
  891. return $ABORT_ON_OVERWRITE
  892. }
  893. # Returns $TRUE if we should print the GS call to stdout
  894. shouldPrintGSCall() {
  895. return $PRINT_GS_CALL
  896. }
  897. # Returns $TRUE if we are simulating, dry-run (no GS execution)
  898. isDryRun() {
  899. return $SIMULATE
  900. }
  901. # Parses and validates the scaling factor
  902. parseScale() {
  903. AUTOMATIC_SCALING=$FALSE
  904. if ! isFloatBiggerThanZero "$1"; then
  905. printError "Invalid factor: $1"
  906. printError "The factor must be a floating point number greater than 0"
  907. printError "Example: for 80% use 0.8"
  908. exit $EXIT_INVALID_SCALE
  909. fi
  910. SCALE="$1"
  911. }
  912. # Parse a forced mode of operation
  913. parseMode() {
  914. local param="$(lowercase $1)"
  915. case "${param}" in
  916. c|catgrep|'cat+grep'|grep|g)
  917. ADAPTIVEMODE=$FALSE
  918. MODE="CATGREP"
  919. return $TRUE
  920. ;;
  921. i|imagemagick|identify)
  922. ADAPTIVEMODE=$FALSE
  923. MODE="IDENTIFY"
  924. return $TRUE
  925. ;;
  926. m|mdls|quartz|mac)
  927. ADAPTIVEMODE=$FALSE
  928. MODE="MDLS"
  929. return $TRUE
  930. ;;
  931. p|pdfinfo)
  932. ADAPTIVEMODE=$FALSE
  933. MODE="PDFINFO"
  934. return $TRUE
  935. ;;
  936. a|auto|automatic|adaptive)
  937. ADAPTIVEMODE=$TRUE
  938. MODE=""
  939. return $TRUE
  940. ;;
  941. *)
  942. initError "Invalid PDF Size Detection Mode: \"$1\"" $EXIT_INVALID_OPTION
  943. return $FALSE
  944. ;;
  945. esac
  946. return $FALSE
  947. }
  948. # Parses and validates the scaling factor
  949. parseFlipDetectionMode() {
  950. local param="$(lowercase $1)"
  951. case "${param}" in
  952. d|disable)
  953. FLIP_DETECTION=$FALSE
  954. FLIP_FORCE=$FALSE
  955. ;;
  956. f|force)
  957. FLIP_DETECTION=$FALSE
  958. FLIP_FORCE=$TRUE
  959. ;;
  960. a|auto|automatic)
  961. FLIP_DETECTION=$TRUE
  962. FLIP_FORCE=$FALSE
  963. ;;
  964. *)
  965. initError "Invalid Flip Detection Mode: \"$1\"" $EXIT_INVALID_OPTION
  966. return $FALSE
  967. ;;
  968. esac
  969. }
  970. # Parses and validates the scaling factor
  971. parseAutoRotationMode() {
  972. local param="$(lowercase $1)"
  973. case "${param}" in
  974. n|none|'/none')
  975. AUTO_ROTATION='/None'
  976. ;;
  977. a|all|'/all')
  978. AUTO_ROTATION='/All'
  979. ;;
  980. p|pagebypage|'/pagebypage'|auto)
  981. AUTO_ROTATION='/PageByPage'
  982. ;;
  983. *)
  984. initError "Invalid Auto Rotation Mode: \"$1\"" $EXIT_INVALID_OPTION
  985. return $FALSE
  986. ;;
  987. esac
  988. }
  989. # Parses and validates the resize fit page
  990. parseFitPageMode() {
  991. local param="$(lowercase $1)"
  992. case "${param}" in
  993. n|no)
  994. FIT_PAGE=''
  995. ;;
  996. f|fit)
  997. FIT_PAGE='-dPDFFitPage'
  998. ;;
  999. *)
  1000. initError "Invalid Resize Fit Page Mode: \"$1\"" $EXIT_INVALID_OPTION
  1001. return $FALSE
  1002. ;;
  1003. esac
  1004. }
  1005. # Validades the a paper resize CLI option and sets the paper to $RESIZE_PAPER_TYPE
  1006. parsePaperResize() {
  1007. isEmpty "$1" && initError 'Invalid Paper Type: (empty)' $EXIT_INVALID_PAPER_SIZE
  1008. local lowercasePaper="$(lowercase $1)"
  1009. local customPaper=($lowercasePaper)
  1010. if [[ "$customPaper" = 'same' || "$customPaper" = 'keep' || "$customPaper" = 'source' ]]; then
  1011. RESIZE_PAPER_TYPE='source'
  1012. elif [[ "${customPaper[0]}" = 'custom' ]]; then
  1013. if isNotValidMeasure "${customPaper[1]}" || ! isFloatBiggerThanZero "${customPaper[2]}" || ! isFloatBiggerThanZero "${customPaper[3]}"; then
  1014. initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom <measurement> <width> <height>'"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION
  1015. fi
  1016. RESIZE_PAPER_TYPE="custom"
  1017. CUSTOM_RESIZE_PAPER=$TRUE
  1018. if isMilimeter "${customPaper[1]}"; then
  1019. RESIZE_WIDTH="$(milimetersToPoints "${customPaper[2]}")"
  1020. RESIZE_HEIGHT="$(milimetersToPoints "${customPaper[3]}")"
  1021. elif isInch "${customPaper[1]}"; then
  1022. RESIZE_WIDTH="$(inchesToPoints "${customPaper[2]}")"
  1023. RESIZE_HEIGHT="$(inchesToPoints "${customPaper[3]}")"
  1024. elif isPoint "${customPaper[1]}"; then
  1025. RESIZE_WIDTH="${customPaper[2]}"
  1026. RESIZE_HEIGHT="${customPaper[3]}"
  1027. else
  1028. initError "Invalid Custom Paper Definition!"$'\n'"Use: -r 'custom <measurement> <width> <height>'"$'\n'"Measurements: mm, in, pts" $EXIT_INVALID_OPTION
  1029. fi
  1030. else
  1031. isPaperName "$lowercasePaper" || initError "Invalid Paper Type: $1" $EXIT_INVALID_PAPER_SIZE
  1032. RESIZE_PAPER_TYPE="$lowercasePaper"
  1033. fi
  1034. }
  1035. # Goes to GS -dColorImageResolution and -dGrayImageResolution parameters
  1036. parseImageResolution() {
  1037. if isNotAnInteger "$1"; then
  1038. printError "Invalid image resolution: $1"
  1039. printError "The image resolution must be an integer"
  1040. exit $EXIT_INVALID_IMAGE_RESOLUTION
  1041. fi
  1042. IMAGE_RESOLUTION="$1"
  1043. }
  1044. # Goes to GS -dColorImageDownsampleType and -dGrayImageDownsampleType parameters
  1045. parseImageDownSample() {
  1046. local param="$(lowercase $1)"
  1047. case "${param}" in
  1048. s|subsample|'/subsample')
  1049. IMAGE_DOWNSAMPLE_TYPE='/Subsample'
  1050. ;;
  1051. a|average|'/average')
  1052. IMAGE_DOWNSAMPLE_TYPE='/Average'
  1053. ;;
  1054. b|bicubic|'/bicubic'|auto)
  1055. IMAGE_DOWNSAMPLE_TYPE='/Bicubic'
  1056. ;;
  1057. *)
  1058. initError "Invalid Image Downsample Mode: \"$1\"" $EXIT_INVALID_OPTION
  1059. return $FALSE
  1060. ;;
  1061. esac
  1062. }
  1063. # Goes to GS -dColorImageDownsampleType and -dGrayImageDownsampleType parameters
  1064. parsePDFSettings() {
  1065. local param="$(lowercase $1)"
  1066. case "${param}" in
  1067. s|screen|'/screen')
  1068. PDF_SETTINGS='/screen'
  1069. ;;
  1070. e|ebook|'/ebook')
  1071. PDF_SETTINGS='/ebook'
  1072. ;;
  1073. p|printer|'/printer'|auto)
  1074. PDF_SETTINGS='/printer'
  1075. ;;
  1076. r|prepress|'/prepress')
  1077. PDF_SETTINGS='/prepress'
  1078. ;;
  1079. d|default|'/default')
  1080. PDF_SETTINGS='/default'
  1081. ;;
  1082. *)
  1083. initError "Invalid PDF Setting Profile: \"$1\""$'\nValid > printer, screen, ebook, prepress, default' $EXIT_INVALID_OPTION
  1084. return $FALSE
  1085. ;;
  1086. esac
  1087. }
  1088. # How to position the resized pages (sets translation)
  1089. parseHorizontalAlignment() {
  1090. local param="$(lowercase $1)"
  1091. case "${param}" in
  1092. l|left)
  1093. HOR_ALIGN='LEFT'
  1094. ;;
  1095. r|right)
  1096. HOR_ALIGN='RIGHT'
  1097. ;;
  1098. c|center|middle)
  1099. HOR_ALIGN='CENTER'
  1100. ;;
  1101. *)
  1102. initError "Invalid Horizontal Alignment Setting: \"$1\""$'\nValid > left, right, center' $EXIT_INVALID_OPTION
  1103. return $FALSE
  1104. ;;
  1105. esac
  1106. }
  1107. # How to position the resized pages (sets translation)
  1108. parseVerticalAlignment() {
  1109. local param="$(lowercase $1)"
  1110. case "${param}" in
  1111. t|top)
  1112. VERT_ALIGN='TOP'
  1113. ;;
  1114. b|bottom|bot)
  1115. VERT_ALIGN='BOTTOM'
  1116. ;;
  1117. c|center|middle)
  1118. VERT_ALIGN='CENTER'
  1119. ;;
  1120. *)
  1121. initError "Invalid Vertical Alignment Setting: \"$1\""$'\nValid > top, bottom, center' $EXIT_INVALID_OPTION
  1122. return $FALSE
  1123. ;;
  1124. esac
  1125. }
  1126. # Set X Translation Offset
  1127. parseXTransOffset() {
  1128. if isFloat "$1"; then
  1129. XTRANSOFFSET="$1"
  1130. return $TRUE
  1131. fi
  1132. printError "Invalid X Translation Offset: $1"
  1133. printError "The X Translation Offset must be a floating point number"
  1134. exit $EXIT_INVALID_OPTION
  1135. }
  1136. # Set Y Translation Offset
  1137. parseYTransOffset() {
  1138. if isFloat "$1"; then
  1139. YTRANSOFFSET="$1"
  1140. return $TRUE
  1141. fi
  1142. printError "Invalid Y Translation Offset: $1"
  1143. printError "The Y Translation Offset must be a floating point number"
  1144. exit $EXIT_INVALID_OPTION
  1145. }
  1146. # Parse Gray Background color
  1147. parseGrayBackground() {
  1148. if isFloatPercentage "$1"; then
  1149. BACKGROUNDCOLOR="$1"
  1150. BACKGROUNDCALL="$BACKGROUNDCOLOR setgray clippath fill " # the space at the end is important!
  1151. BACKGROUNDTYPE="GRAY"
  1152. BACKGROUNDLOG="$GrayColor Mode > $BACKGROUNDCOLOR"
  1153. return $TRUE
  1154. fi
  1155. printError "Invalid Gray Background color."
  1156. printError "Need 1 floating point number between 0 and 1."
  1157. printError "Eg: --background-gray \"0.80\""
  1158. printError "Invalid Param => $1"
  1159. exit $EXIT_INVALID_OPTION
  1160. }
  1161. # Parse CMYK Background color
  1162. parseCMYKBackground() {
  1163. if isFloatPercentage "$1" && isFloatPercentage "$2" && isFloatPercentage "$3" && isFloatPercentage "$4"; then
  1164. BACKGROUNDCOLOR="$1 $2 $3 $4"
  1165. BACKGROUNDCALL="$BACKGROUNDCOLOR setcmykcolor clippath fill " # the space at the end is important!
  1166. BACKGROUNDTYPE="CMYK"
  1167. BACKGROUNDLOG="$BACKGROUNDTYPE Mode > $BACKGROUNDCOLOR"
  1168. return $TRUE
  1169. fi
  1170. printError "Invalid CMYK Background colors."
  1171. printError "Need 4 floating point numbers between 0 and 1 in CMYK order."
  1172. printError "Eg: --background-cmyk \"C M Y K\""
  1173. printError " [C] => $1"
  1174. printError " [M] => $2"
  1175. printError " [Y] => $3"
  1176. printError " [K] => $4"
  1177. exit $EXIT_INVALID_OPTION
  1178. }
  1179. # Just loads the RGB Vars (without testing anything)
  1180. loadRGBVars(){
  1181. local rP="$(rgbToPercentage $1)"
  1182. local gP="$(rgbToPercentage $2)"
  1183. local bP="$(rgbToPercentage $3)"
  1184. BACKGROUNDCOLOR="$rP $gP $bP"
  1185. BACKGROUNDCALL="$BACKGROUNDCOLOR setrgbcolor clippath fill " # the space at the end is important!
  1186. BACKGROUNDTYPE="RGB"
  1187. BACKGROUNDLOG="$BACKGROUNDTYPE Mode > $1($(printf %.2f $rP)) $2($(printf %.2f $gP)) $3($(printf %.2f $bP))"
  1188. }
  1189. # Converts 255-based RGB to Percentage
  1190. rgbToPercentage() {
  1191. local per=$(echo "scale=8; $1 / 255" | "$BCBIN")
  1192. printf '%.7f' "$per" # Print rounded conversion
  1193. }
  1194. # Parse RGB Background color
  1195. parseRGBBackground() {
  1196. if isRGBInteger "$1" && isRGBInteger "$2" && isRGBInteger "$3" ; then
  1197. loadRGBVars "$1" "$2" "$3"
  1198. return $TRUE
  1199. fi
  1200. printError "Invalid RGB Background colors. Need 3 parameters in RGB order."
  1201. printError "Numbers must be RGB integers between 0 and 255."
  1202. printError "Eg: --background-rgb \"34 123 255\""
  1203. printError " [R] => $1"
  1204. printError " [G] => $2"
  1205. printError " [B] => $3"
  1206. exit $EXIT_INVALID_OPTION
  1207. }
  1208. ################### PDF PAGE SIZE DETECTION ####################
  1209. ################################################################
  1210. # Detects operation mode and also runs the adaptive mode
  1211. # PAGESIZE LOGIC
  1212. # 1- Try to get Mediabox with GREP
  1213. # 2- MacOS => try to use mdls
  1214. # 3- Try to use pdfinfo
  1215. # 4- Try to use identify (imagemagick)
  1216. # 5- Fail
  1217. ################################################################
  1218. getPageSize() {
  1219. if isNotAdaptiveMode; then
  1220. vprint " Get Page Size: Adaptive Disabled"
  1221. if [[ $MODE = "CATGREP" ]]; then
  1222. vprint " Method: Grep"
  1223. getPageSizeCatGrep
  1224. elif [[ $MODE = "MDLS" ]]; then
  1225. vprint " Method: Mac Quartz mdls"
  1226. getPageSizeMdls
  1227. elif [[ $MODE = "PDFINFO" ]]; then
  1228. vprint " Method: PDFInfo"
  1229. getPageSizePdfInfo
  1230. elif [[ $MODE = "IDENTIFY" ]]; then
  1231. vprint " Method: ImageMagick's Identify"
  1232. getPageSizeImagemagick
  1233. else
  1234. printError "Error! Invalid Mode: $MODE"
  1235. printError "Aborting execution..."
  1236. exit $EXIT_INVALID_OPTION
  1237. fi
  1238. return $TRUE
  1239. fi
  1240. vprint " Get Page Size: Adaptive Enabled"
  1241. vprint " Method: Grep"
  1242. getPageSizeCatGrep
  1243. if pageSizeIsInvalid && [[ $OSNAME = "Darwin" ]]; then
  1244. vprint " Failed"
  1245. vprint " Method: Mac Quartz mdls"
  1246. getPageSizeMdls
  1247. fi
  1248. if pageSizeIsInvalid; then
  1249. vprint " Failed"
  1250. vprint " Method: PDFInfo"
  1251. getPageSizePdfInfo
  1252. fi
  1253. if pageSizeIsInvalid; then
  1254. vprint " Failed"
  1255. vprint " Method: ImageMagick's Identify"
  1256. getPageSizeImagemagick
  1257. fi
  1258. if pageSizeIsInvalid; then
  1259. vprint " Failed"
  1260. printError "Error when detecting PDF paper size!"
  1261. printError "All methods of detection failed"
  1262. printError "You may want to install pdfinfo or imagemagick"
  1263. exit $EXIT_INVALID_PAGE_SIZE_DETECTED
  1264. fi
  1265. return $TRUE
  1266. }
  1267. # Gets page size using imagemagick's identify
  1268. getPageSizeImagemagick() {
  1269. # Sanity and Adaptive together
  1270. if isNotFile "$IDBIN" && isNotAdaptiveMode; then
  1271. notAdaptiveFailed "Make sure you installed ImageMagick and have identify on your \$PATH" "ImageMagick's Identify"
  1272. elif isNotFile "$IDBIN" && isAdaptiveMode; then
  1273. return $FALSE
  1274. fi
  1275. # get data from image magick
  1276. local identify="$("$IDBIN" -format '%[fx:w] %[fx:h]BREAKME' "$INFILEPDF" 2>/dev/null)"
  1277. if isEmpty "$identify" && isNotAdaptiveMode; then
  1278. notAdaptiveFailed "ImageMagicks's Identify returned an empty string!"
  1279. elif isEmpty "$identify" && isAdaptiveMode; then
  1280. return $FALSE
  1281. fi
  1282. identify="${identify%%BREAKME*}" # get page size only for 1st page
  1283. identify=($identify) # make it an array
  1284. PGWIDTH=$(printf '%.0f' "${identify[0]}") # assign
  1285. PGHEIGHT=$(printf '%.0f' "${identify[1]}") # assign
  1286. return $TRUE
  1287. }
  1288. # Gets page size using Mac Quarts mdls
  1289. getPageSizeMdls() {
  1290. # Sanity and Adaptive together
  1291. if isNotFile "$MDLSBIN" && isNotAdaptiveMode; then
  1292. notAdaptiveFailed "Are you even trying this on a Mac?" "Mac Quartz mdls"
  1293. elif isNotFile "$MDLSBIN" && isAdaptiveMode; then
  1294. return $FALSE
  1295. fi
  1296. local identify="$("$MDLSBIN" -mdls -name kMDItemPageHeight -name kMDItemPageWidth "$INFILEPDF" 2>/dev/null)"
  1297. if isEmpty "$identify" && isNotAdaptiveMode; then
  1298. notAdaptiveFailed "Mac Quartz mdls returned an empty string!"
  1299. elif isEmpty "$identify" && isAdaptiveMode; then
  1300. return $FALSE
  1301. fi
  1302. identify=${identify//$'\t'/ } # change tab to space
  1303. identify=($identify) # make it an array
  1304. if [[ "${identify[5]}" = "(null)" || "${identify[2]}" = "(null)" ]] && isNotAdaptiveMode; then
  1305. notAdaptiveFailed "There was no metadata to read from the file! Is Spotlight OFF?"
  1306. elif [[ "${identify[5]}" = "(null)" || "${identify[2]}" = "(null)" ]] && isAdaptiveMode; then
  1307. return $FALSE
  1308. fi
  1309. PGWIDTH=$(printf '%.0f' "${identify[5]}") # assign
  1310. PGHEIGHT=$(printf '%.0f' "${identify[2]}") # assign
  1311. return $TRUE
  1312. }
  1313. # Gets page size using Linux PdfInfo
  1314. getPageSizePdfInfo() {
  1315. # Sanity and Adaptive together
  1316. if isNotFile "$PDFINFOBIN" && isNotAdaptiveMode; then
  1317. notAdaptiveFailed "Do you have pdfinfo installed and available on your \$PATH?" "Linux pdfinfo"
  1318. elif isNotFile "$PDFINFOBIN" && isAdaptiveMode; then
  1319. return $FALSE
  1320. fi
  1321. # get data from image magick
  1322. local identify="$("$PDFINFOBIN" "$INFILEPDF" 2>/dev/null | "$GREPBIN" -i 'Page size:' )"
  1323. if isEmpty "$identify" && isNotAdaptiveMode; then
  1324. notAdaptiveFailed "Linux PdfInfo returned an empty string!"
  1325. elif isEmpty "$identify" && isAdaptiveMode; then
  1326. return $FALSE
  1327. fi
  1328. identify="${identify##*Page size:}" # remove stuff
  1329. identify=($identify) # make it an array
  1330. PGWIDTH=$(printf '%.0f' "${identify[0]}") # assign
  1331. PGHEIGHT=$(printf '%.0f' "${identify[2]}") # assign
  1332. return $TRUE
  1333. }
  1334. # Gets page size using cat and grep
  1335. getPageSizeCatGrep() {
  1336. # get MediaBox info from PDF file using grep, these are all possible
  1337. # /MediaBox [0 0 595 841]
  1338. # /MediaBox [ 0 0 595.28 841.89]
  1339. # /MediaBox[ 0 0 595.28 841.89 ]
  1340. # Get MediaBox data if possible
  1341. local mediaBox="$("$GREPBIN" -a -e '/MediaBox' -m 1 "$INFILEPDF" 2>/dev/null)"
  1342. mediaBox="${mediaBox##*/MediaBox}"
  1343. mediaBox="${mediaBox##*[}"
  1344. mediaBox="${mediaBox%%]*}"
  1345. #echo "mediaBox=$mediaBox"
  1346. # No page size data available
  1347. if isEmpty "$mediaBox" && isNotAdaptiveMode; then
  1348. notAdaptiveFailed "There is no MediaBox in the pdf document!"
  1349. elif isEmpty "$mediaBox" && isAdaptiveMode; then
  1350. return $FALSE
  1351. fi
  1352. mediaBox=($mediaBox) # make it an array
  1353. mbCount=${#mediaBox[@]} # array size
  1354. # sanity
  1355. if [[ $mbCount -lt 4 ]] || ! isFloat "${mediaBox[2]}" || ! isFloat "${mediaBox[3]}" || isZero "${mediaBox[2]}" || isZero "${mediaBox[3]}"; then
  1356. if isNotAdaptiveMode; then
  1357. notAdaptiveFailed $'Error when reading the page size!\nThe page size information is invalid!'
  1358. fi
  1359. return $FALSE
  1360. fi
  1361. # we are done
  1362. PGWIDTH=$(printf '%.0f' "${mediaBox[2]}") # Get Round Width
  1363. PGHEIGHT=$(printf '%.0f' "${mediaBox[3]}") # Get Round Height
  1364. #echo "PGWIDTH=$PGWIDTH // PGHEIGHT=$PGHEIGHT"
  1365. return $TRUE
  1366. }
  1367. isZero() {
  1368. [[ "$1" == "0" ]] && return $TRUE
  1369. [[ "$1" == "0.0" ]] && return $TRUE
  1370. [[ "$1" == "0.00" ]] && return $TRUE
  1371. [[ "$1" == "0.000" ]] && return $TRUE
  1372. return $FALSE
  1373. }
  1374. # Prints error message and exits execution
  1375. notAdaptiveFailed() {
  1376. local errProgram="$2"
  1377. local errStr="$1"
  1378. if isEmpty "$2"; then
  1379. printError "Error when reading input file!"
  1380. printError "Could not determine the page size!"
  1381. else
  1382. printError "Error! $2 was not found!"
  1383. fi
  1384. isNotEmpty "$errStr" && printError "$errStr"
  1385. printError "Aborting! You may want to try the adaptive mode."
  1386. exit $EXIT_INVALID_PAGE_SIZE_DETECTED
  1387. }
  1388. # Verbose print of the Width and Height (Source or New) to screen
  1389. vPrintPageSizes() {
  1390. vprint " $1 Width: $PGWIDTH postscript-points"
  1391. vprint "$1 Height: $PGHEIGHT postscript-points"
  1392. }
  1393. #################### GHOSTSCRIPT PAPER INFO ####################
  1394. # Loads valid paper info to memory
  1395. getPaperInfo() {
  1396. # name inchesW inchesH mmW mmH pointsW pointsH
  1397. sizesUS="\
  1398. 11x17 11.0 17.0 279 432 792 1224
  1399. ledger 17.0 11.0 432 279 1224 792
  1400. legal 8.5 14.0 216 356 612 1008
  1401. letter 8.5 11.0 216 279 612 792
  1402. lettersmall 8.5 11.0 216 279 612 792
  1403. archE 36.0 48.0 914 1219 2592 3456
  1404. archD 24.0 36.0 610 914 1728 2592
  1405. archC 18.0 24.0 457 610 1296 1728
  1406. archB 12.0 18.0 305 457 864 1296
  1407. archA 9.0 12.0 229 305 648 864"
  1408. sizesISO="\
  1409. a0 33.1 46.8 841 1189 2384 3370
  1410. a1 23.4 33.1 594 841 1684 2384
  1411. a2 16.5 23.4 420 594 1191 1684
  1412. a3 11.7 16.5 297 420 842 1191
  1413. a4 8.3 11.7 210 297 595 842
  1414. a4small 8.3 11.7 210 297 595 842
  1415. a5 5.8 8.3 148 210 420 595
  1416. a6 4.1 5.8 105 148 297 420
  1417. a7 2.9 4.1 74 105 210 297
  1418. a8 2.1 2.9 52 74 148 210
  1419. a9 1.5 2.1 37 52 105 148
  1420. a10 1.0 1.5 26 37 73 105
  1421. isob0 39.4 55.7 1000 1414 2835 4008
  1422. isob1 27.8 39.4 707 1000 2004 2835
  1423. isob2 19.7 27.8 500 707 1417 2004
  1424. isob3 13.9 19.7 353 500 1001 1417
  1425. isob4 9.8 13.9 250 353 709 1001
  1426. isob5 6.9 9.8 176 250 499 709
  1427. isob6 4.9 6.9 125 176 354 499
  1428. c0 36.1 51.1 917 1297 2599 3677
  1429. c1 25.5 36.1 648 917 1837 2599
  1430. c2 18.0 25.5 458 648 1298 1837
  1431. c3 12.8 18.0 324 458 918 1298
  1432. c4 9.0 12.8 229 324 649 918
  1433. c5 6.4 9.0 162 229 459 649
  1434. c6 4.5 6.4 114 162 323 459"
  1435. sizesJIS="\
  1436. jisb0 NA NA 1030 1456 2920 4127
  1437. jisb1 NA NA 728 1030 2064 2920
  1438. jisb2 NA NA 515 728 1460 2064
  1439. jisb3 NA NA 364 515 1032 1460
  1440. jisb4 NA NA 257 364 729 1032
  1441. jisb5 NA NA 182 257 516 729
  1442. jisb6 NA NA 128 182 363 516"
  1443. sizesOther="\
  1444. flsa 8.5 13.0 216 330 612 936
  1445. flse 8.5 13.0 216 330 612 936
  1446. halfletter 5.5 8.5 140 216 396 612
  1447. hagaki 3.9 5.8 100 148 283 420"
  1448. sizesAll="\
  1449. $sizesUS
  1450. $sizesISO
  1451. $sizesJIS
  1452. $sizesOther"
  1453. }
  1454. # Gets a paper size in points and sets it to RESIZE_WIDTH and RESIZE_HEIGHT
  1455. getGSPaperSize() {
  1456. isEmpty "$sizesall" && getPaperInfo
  1457. while read l; do
  1458. local cols=($l)
  1459. if [[ "$1" == ${cols[0]} ]]; then
  1460. RESIZE_WIDTH=${cols[5]}
  1461. RESIZE_HEIGHT=${cols[6]}
  1462. return $TRUE
  1463. fi
  1464. done <<< "$sizesAll"
  1465. }
  1466. # Gets a paper size in points and sets it to RESIZE_WIDTH and RESIZE_HEIGHT
  1467. getGSPaperName() {
  1468. local w="$(printf "%.0f" $1)"
  1469. local h="$(printf "%.0f" $2)"
  1470. isEmpty "$sizesall" && getPaperInfo
  1471. # Because US Standard has inverted sizes, I need to scan 2 times
  1472. # instead of just testing if width is bigger than height
  1473. while read l; do
  1474. local cols=($l)
  1475. if [[ "$w" == ${cols[5]} && "$h" == ${cols[6]} ]]; then
  1476. printf "%s Portrait" $(uppercase ${cols[0]})
  1477. return $TRUE
  1478. fi
  1479. done <<< "$sizesAll"
  1480. while read l; do
  1481. local cols=($l)
  1482. if [[ "$w" == ${cols[6]} && "$h" == ${cols[5]} ]]; then
  1483. printf "%s Landscape" $(uppercase ${cols[0]})
  1484. return $TRUE
  1485. fi
  1486. done <<< "$sizesAll"
  1487. return $FALSE
  1488. }
  1489. # Loads an array with paper names to memory
  1490. getPaperNames() {
  1491. 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 \
  1492. 11x17 ledger legal letter lettersmall archE archD archC archB archA \
  1493. jisb0 jisb1 jisb2 jisb3 jisb4 jisb5 jisb6 \
  1494. flsa flse halfletter hagaki)
  1495. }
  1496. # Prints uppercase paper names to screen (used in help)
  1497. printPaperNames() {
  1498. isEmpty "$paperNames" && getPaperNames
  1499. for i in "${!paperNames[@]}"; do
  1500. [[ $i -eq 0 ]] && echo -n -e ' '
  1501. [[ $i -ne 0 && $((i % 5)) -eq 0 ]] && echo -n -e $'\n '
  1502. ppN="$(uppercase ${paperNames[i]})"
  1503. printf "%-14s" "$ppN"
  1504. done
  1505. echo ""
  1506. }
  1507. # Returns $TRUE if $! is a valid paper name, $FALSE otherwise
  1508. isPaperName() {
  1509. isEmpty "$1" && return $FALSE
  1510. isEmpty "$paperNames" && getPaperNames
  1511. for i in "${paperNames[@]}"; do
  1512. [[ "$i" = "$1" ]] && return $TRUE
  1513. done
  1514. return $FALSE
  1515. }
  1516. # Prints all tables with ghostscript paper information
  1517. printPaperInfo() {
  1518. printVersion 3
  1519. echo $'\n'"Paper Sizes Information"$'\n'
  1520. getPaperInfo
  1521. printPaperTable "ISO STANDARD" "$sizesISO"; echo
  1522. printPaperTable "US STANDARD" "$sizesUS"; echo
  1523. printPaperTable "JIS STANDARD *Aproximated Points" "$sizesJIS"; echo
  1524. printPaperTable "OTHERS" "$sizesOther"; echo
  1525. }
  1526. # GS paper table helper, prints a full line
  1527. printTableLine() {
  1528. echo '+-----------------------------------------------------------------+'
  1529. }
  1530. # GS paper table helper, prints a line with dividers
  1531. printTableDivider() {
  1532. echo '+-----------------+-------+-------+-------+-------+-------+-------+'
  1533. }
  1534. # GS paper table helper, prints a table header
  1535. printTableHeader() {
  1536. echo '| Name | inchW | inchH | mm W | mm H | pts W | pts H |'
  1537. }
  1538. # GS paper table helper, prints a table title
  1539. printTableTitle() {
  1540. printf "| %-64s%s\n" "$1" '|'
  1541. }
  1542. # GS paper table printer, prints a table for a paper variable
  1543. printPaperTable() {
  1544. printTableLine
  1545. printTableTitle "$1"
  1546. printTableLine
  1547. printTableHeader
  1548. printTableDivider
  1549. while read l; do
  1550. local cols=($l)
  1551. printf "| %-15s | %+5s | %+5s | %+5s | %+5s | %+5s | %+5s |\n" ${cols[*]};
  1552. done <<< "$2"
  1553. printTableDivider
  1554. }
  1555. # Returns $TRUE if $1 is a valid measurement for a custom paper, $FALSE otherwise
  1556. isNotValidMeasure() {
  1557. isMilimeter "$1" || isInch "$1" || isPoint "$1" && return $FALSE
  1558. return $TRUE
  1559. }
  1560. # Returns $TRUE if $1 is a valid milimeter string, $FALSE otherwise
  1561. isMilimeter() {
  1562. [[ "$1" = 'mm' || "$1" = 'milimeters' || "$1" = 'milimeter' ]] && return $TRUE
  1563. return $FALSE
  1564. }
  1565. # Returns $TRUE if $1 is a valid inch string, $FALSE otherwise
  1566. isInch() {
  1567. [[ "$1" = 'in' || "$1" = 'inch' || "$1" = 'inches' ]] && return $TRUE
  1568. return $FALSE
  1569. }
  1570. # Returns $TRUE if $1 is a valid point string, $FALSE otherwise
  1571. isPoint() {
  1572. [[ "$1" = 'pt' || "$1" = 'pts' || "$1" = 'point' || "$1" = 'points' ]] && return $TRUE
  1573. return $FALSE
  1574. }
  1575. # Returns $TRUE if a custom paper is being used, $FALSE otherwise
  1576. isCustomPaper() {
  1577. return $CUSTOM_RESIZE_PAPER
  1578. }
  1579. # Returns $FALSE if a custom paper is being used, $TRUE otherwise
  1580. isNotCustomPaper() {
  1581. isCustomPaper && return $FALSE
  1582. return $TRUE
  1583. }
  1584. ######################### CONVERSIONS ##########################
  1585. # Prints the lowercase char value for $1
  1586. lowercaseChar() {
  1587. case "$1" in
  1588. [A-Z])
  1589. n=$(printf "%d" "'$1")
  1590. n=$((n+32))
  1591. printf \\$(printf "%o" "$n")
  1592. ;;
  1593. *)
  1594. printf "%s" "$1"
  1595. ;;
  1596. esac
  1597. }
  1598. # Prints the lowercase version of a string
  1599. lowercase() {
  1600. word="$@"
  1601. for((i=0;i<${#word};i++))
  1602. do
  1603. ch="${word:$i:1}"
  1604. lowercaseChar "$ch"
  1605. done
  1606. }
  1607. # Prints the uppercase char value for $1
  1608. uppercaseChar(){
  1609. case "$1" in
  1610. [a-z])
  1611. n=$(printf "%d" "'$1")
  1612. n=$((n-32))
  1613. printf \\$(printf "%o" "$n")
  1614. ;;
  1615. *)
  1616. printf "%s" "$1"
  1617. ;;
  1618. esac
  1619. }
  1620. # Prints the uppercase version of a string
  1621. uppercase() {
  1622. word="$@"
  1623. for((i=0;i<${#word};i++))
  1624. do
  1625. ch="${word:$i:1}"
  1626. uppercaseChar "$ch"
  1627. done
  1628. }
  1629. # Prints the postscript points rounded equivalent from $1 mm
  1630. milimetersToPoints() {
  1631. local pts=$(echo "scale=8; $1 * 72 / 25.4" | "$BCBIN")
  1632. printf '%.0f' "$pts" # Print rounded conversion
  1633. }
  1634. # Prints the postscript points rounded equivalent from $1 inches
  1635. inchesToPoints() {
  1636. local pts=$(echo "scale=8; $1 * 72" | "$BCBIN")
  1637. printf '%.0f' "$pts" # Print rounded conversion
  1638. }
  1639. # Prints the mm equivalent from $1 postscript points
  1640. pointsToMilimeters() {
  1641. local pts=$(echo "scale=8; $1 / 72 * 25.4" | "$BCBIN")
  1642. printf '%.0f' "$pts" # Print rounded conversion
  1643. }
  1644. # Prints the inches equivalent from $1 postscript points
  1645. pointsToInches() {
  1646. local pts=$(echo "scale=8; $1 / 72" | "$BCBIN")
  1647. printf '%.1f' "$pts" # Print rounded conversion
  1648. }
  1649. ######################## MODE-DETECTION ########################
  1650. # Returns $TRUE if the scale was set manually, $FALSE if we are using automatic scaling
  1651. isManualScaledMode() {
  1652. [[ $AUTOMATIC_SCALING -eq $TRUE ]] && return $FALSE
  1653. return $TRUE
  1654. }
  1655. # Returns true if we are resizing a paper (ignores scaling), false otherwise
  1656. isResizeMode() {
  1657. isEmpty $RESIZE_PAPER_TYPE && return $FALSE
  1658. return $TRUE
  1659. }
  1660. # Returns true if we are resizing a paper and the scale was manually set
  1661. isMixedMode() {
  1662. isResizeMode && isManualScaledMode && return $TRUE
  1663. return $FALSE
  1664. }
  1665. # Return $TRUE if adaptive mode is enabled, $FALSE otherwise
  1666. isAdaptiveMode() {
  1667. return $ADAPTIVEMODE
  1668. }
  1669. # Return $TRUE if adaptive mode is disabled, $FALSE otherwise
  1670. isNotAdaptiveMode() {
  1671. isAdaptiveMode && return $FALSE
  1672. return $TRUE
  1673. }
  1674. ########################## VALIDATORS ##########################
  1675. # Returns $TRUE if we don't need to create a background
  1676. noBackground() {
  1677. [[ "$BACKGROUNDTYPE" == "CMYK" ]] && return $FALSE
  1678. [[ "$BACKGROUNDTYPE" == "RGB" ]] && return $FALSE
  1679. [[ "$BACKGROUNDTYPE" == "GRAY" ]] && return $FALSE
  1680. return $TRUE
  1681. }
  1682. # Returns $TRUE if we need to create a background
  1683. hasBackground() {
  1684. [[ "$BACKGROUNDTYPE" == "CMYK" ]] && return $TRUE
  1685. [[ "$BACKGROUNDTYPE" == "RGB" ]] && return $TRUE
  1686. [[ "$BACKGROUNDTYPE" == "GRAY" ]] && return $TRUE
  1687. return $FALSE
  1688. }
  1689. # Returns $TRUE if $PGWIDTH OR $PGWIDTH are empty or NOT an Integer, $FALSE otherwise
  1690. pageSizeIsInvalid() {
  1691. if isNotAnInteger "$PGWIDTH" || isNotAnInteger "$PGHEIGHT"; then
  1692. return $TRUE
  1693. fi
  1694. return $FALSE
  1695. }
  1696. # Return $TRUE if $1 is empty, $FALSE otherwise
  1697. isEmpty() {
  1698. [[ -z "$1" ]] && return $TRUE
  1699. return $FALSE
  1700. }
  1701. # Return $TRUE if $1 is NOT empty, $FALSE otherwise
  1702. isNotEmpty() {
  1703. [[ -z "$1" ]] && return $FALSE
  1704. return $TRUE
  1705. }
  1706. # Returns $TRUE if $1 is an integer, $FALSE otherwise
  1707. isAnInteger() {
  1708. case $1 in
  1709. ''|*[!0-9]*) return $FALSE ;;
  1710. *) return $TRUE ;;
  1711. esac
  1712. }
  1713. # Returns $TRUE if $1 is NOT an integer, $FALSE otherwise
  1714. isNotAnInteger() {
  1715. case $1 in
  1716. ''|*[!0-9]*) return $TRUE ;;
  1717. *) return $FALSE ;;
  1718. esac
  1719. }
  1720. # Returns $TRUE if $1 is an integer, $FALSE otherwise
  1721. isRGBInteger() {
  1722. isAnInteger "$1" && [[ $1 -ge 0 ]] && [[ $1 -le 255 ]] && return $TRUE
  1723. return $FALSE
  1724. }
  1725. # Returns $TRUE if $1 is a floating point number (or an integer), $FALSE otherwise
  1726. isFloat() {
  1727. [[ -n "$1" && "$1" =~ ^-?[0-9]*([.][0-9]+)?$ ]] && return $TRUE
  1728. return $FALSE
  1729. }
  1730. # Returns $TRUE if $1 is a floating point number bigger than zero, $FALSE otherwise
  1731. isFloatBiggerThanZero() {
  1732. isFloat "$1" && [[ (( $1 > 0 )) ]] && return $TRUE
  1733. return $FALSE
  1734. }
  1735. # Returns $TRUE if $1 is a floating point number between 0 and 1, $FALSE otherwise
  1736. isFloatPercentage() {
  1737. [[ -n "$1" && "$1" =~ ^-?[0]*([.][0-9]+)?$ ]] && return $TRUE
  1738. [[ "$1" == "1" ]] && return $TRUE
  1739. return $FALSE
  1740. }
  1741. # Returns $TRUE if $1 is readable, $FALSE otherwise
  1742. isReadable() {
  1743. [[ -r "$1" ]] && return $TRUE
  1744. return $FALSE;
  1745. }
  1746. # Returns $TRUE if $1 is a directory, $FALSE otherwise
  1747. isDir() {
  1748. [[ -d "$1" ]] && return $TRUE
  1749. return $FALSE;
  1750. }
  1751. # Returns $FALSE if $1 is a directory, $TRUE otherwise
  1752. isNotDir() {
  1753. isDir "$1" && return $FALSE
  1754. return $TRUE;
  1755. }
  1756. # Returns 0 if succeded, other integer otherwise
  1757. isTouchable() {
  1758. touch "$1" 2>/dev/null
  1759. }
  1760. # Returns $TRUE if $1 has a .pdf extension, false otherwsie
  1761. isPDF() {
  1762. [[ "$(lowercase $1)" =~ ^..*\.pdf$ ]] && return $TRUE
  1763. return $FALSE
  1764. }
  1765. # Returns $TRUE if $1 is a file, false otherwsie
  1766. isFile() {
  1767. [[ -f "$1" ]] && return $TRUE
  1768. return $FALSE
  1769. }
  1770. # Returns $TRUE if $1 is NOT a file, false otherwsie
  1771. isNotFile() {
  1772. [[ -f "$1" ]] && return $FALSE
  1773. return $TRUE
  1774. }
  1775. # Returns $TRUE if $1 is executable, false otherwsie
  1776. isExecutable() {
  1777. [[ -x "$1" ]] && return $TRUE
  1778. return $FALSE
  1779. }
  1780. # Returns $TRUE if $1 is NOT executable, false otherwsie
  1781. isNotExecutable() {
  1782. [[ -x "$1" ]] && return $FALSE
  1783. return $TRUE
  1784. }
  1785. # Returns $TRUE if $1 is a file and executable, false otherwsie
  1786. isAvailable() {
  1787. if isFile "$1" && isExecutable "$1"; then
  1788. return $TRUE
  1789. fi
  1790. return $FALSE
  1791. }
  1792. # Returns $TRUE if $1 is NOT a file or NOT executable, false otherwsie
  1793. isNotAvailable() {
  1794. if isNotFile "$1" || isNotExecutable "$1"; then
  1795. return $TRUE
  1796. fi
  1797. return $FALSE
  1798. }
  1799. # Returns $TRUE if we should avoid https certificate (on upgrade)
  1800. useInsecure() {
  1801. return $HTTPS_INSECURE
  1802. }
  1803. # Returns $TRUE if we should not ask anything and assume yes as answer
  1804. assumeYes() {
  1805. return $ASSUME_YES
  1806. }
  1807. # Returns $TRUE if we should ask the user for input
  1808. shouldAskUser() {
  1809. assumeYes && return $FALSE
  1810. return $TRUE
  1811. }
  1812. ###################### PRINTING TO SCREEN ######################
  1813. # Prints version
  1814. printVersion() {
  1815. local vStr=""
  1816. [[ "$2" = 'verbose' ]] && vStr=" - Verbose Execution"
  1817. local strBanner="$PDFSCALE_NAME v$VERSION$vStr"
  1818. if [[ $1 -eq 2 ]]; then
  1819. printError "$strBanner"
  1820. elif [[ $1 -eq 3 ]]; then
  1821. local extra="$(isNotEmpty "$2" && echo "$2")"
  1822. echo "$strBanner$extra"
  1823. else
  1824. vprint "$strBanner"
  1825. fi
  1826. }
  1827. # Prints input, output file info, if verbosing
  1828. vPrintFileInfo() {
  1829. vprint " Input File: $INFILEPDF"
  1830. vprint " Output File: $OUTFILEPDF"
  1831. }
  1832. # Prints the scale factor to screen, or custom message
  1833. vPrintScaleFactor() {
  1834. local scaleMsg="$SCALE"
  1835. isNotEmpty "$1" && scaleMsg="$1"
  1836. vprint " Scale Factor: $scaleMsg"
  1837. }
  1838. # Prints help info
  1839. printHelp() {
  1840. printVersion 3
  1841. local paperList="$(printPaperNames)"
  1842. echo "
  1843. Usage: $PDFSCALE_NAME <inFile.pdf>
  1844. $PDFSCALE_NAME -i <inFile.pdf>
  1845. $PDFSCALE_NAME [-v] [-s <factor>] [-m <page-detection>] <inFile.pdf> [outfile.pdf]
  1846. $PDFSCALE_NAME [-v] [-r <paper>] [-f <flip-detection>] [-a <auto-rotation>] <inFile.pdf> [outfile.pdf]
  1847. $PDFSCALE_NAME -p
  1848. $PDFSCALE_NAME -h
  1849. $PDFSCALE_NAME -V
  1850. Parameters:
  1851. -v, --verbose
  1852. Verbose mode, prints extra information
  1853. Use twice for timestamp
  1854. -h, --help
  1855. Print this help to screen and exits
  1856. -V, --version
  1857. Prints version to screen and exits
  1858. --install, --self-install [target-path]
  1859. Install itself to [target-path] or /usr/local/bin/pdfscale if not specified
  1860. Should contain the full path with the desired executable name
  1861. --upgrade, --self-upgrade
  1862. Upgrades itself in-place (same path/name of the pdfScale.sh caller)
  1863. Downloads the master branch tarball and tries to self-upgrade
  1864. --insecure, --no-check-certificate
  1865. Use curl/wget without SSL library support
  1866. --yes, --assume-yes
  1867. Will answer yes to any prompt on install or upgrade, use with care
  1868. -n, --no-overwrite
  1869. Aborts execution if the output PDF file already exists
  1870. By default, the output file will be overwritten
  1871. -m, --mode <mode>
  1872. Paper size detection mode
  1873. Modes: a, adaptive Default mode, tries all the methods below
  1874. g, grep Forces the use of Grep method
  1875. m, mdls Forces the use of MacOS Quartz mdls
  1876. p, pdfinfo Forces the use of PDFInfo
  1877. i, identify Forces the use of ImageMagick's Identify
  1878. -i, --info <file>
  1879. Prints <file> Paper Size information to screen and exits
  1880. -s, --scale <factor>
  1881. Changes the scaling factor or forces mixed mode
  1882. Defaults: $SCALE (scale mode) / Disabled (resize mode)
  1883. MUST be a number bigger than zero
  1884. Eg. -s 0.8 for 80% of the original size
  1885. -r, --resize <paper>
  1886. Triggers the Resize Paper Mode, disables auto-scaling of $SCALE
  1887. Resize PDF and fit-to-page
  1888. <paper> can be: source, custom or a valid std paper name, read below
  1889. -f, --flip-detect <mode>
  1890. Flip Detection Mode, defaults to 'auto'
  1891. Inverts Width <-> Height of a Resized PDF
  1892. Modes: a, auto Keeps source orientation, default
  1893. f, force Forces flip W <-> H
  1894. d, disable Disables flipping
  1895. -a, --auto-rotate <mode>
  1896. Setting for GS -dAutoRotatePages, defaults to 'PageByPage'
  1897. Uses text-orientation detection to set Portrait/Landscape
  1898. Modes: p, pagebypage Auto-rotates pages individually
  1899. n, none Retains orientation of each page
  1900. a, all Rotates all pages (or none) depending
  1901. on a kind of \"majority decision\"
  1902. --fit-page <mode>
  1903. Use of GS option dPDFFitPage, used by default
  1904. This option is only valid in resize mode
  1905. Modes: f, fit Fit page
  1906. n, no Do not fit page
  1907. --hor-align, --horizontal-alignment <left|center|right>
  1908. Where to translate the scaled page
  1909. Default: center
  1910. Options: left, right, center
  1911. --vert-align, --vertical-alignment <top|center|bottom>
  1912. Where to translate the scaled page
  1913. Default: center
  1914. Options: top, bottom, center
  1915. --xoffset, --xtrans-offset <FloatNumber>
  1916. Add/Subtract from the X translation (move left-right)
  1917. Default: 0.0 (zero)
  1918. Options: Positive or negative floating point number
  1919. --yoffset, --ytrans-offset <FloatNumber>
  1920. Add/Subtract from the Y translation (move top-bottom)
  1921. Default: 0.0 (zero)
  1922. Options: Positive or negative floating point number
  1923. --pdf-settings <gs-pdf-profile>
  1924. Ghostscript PDF Profile to use in -dPDFSETTINGS
  1925. Default: printer
  1926. Options: screen, ebook, printer, prepress, default
  1927. --image-downsample <gs-downsample-method>
  1928. Ghostscript Image Downsample Method
  1929. Default: bicubic
  1930. Options: subsample, average, bicubic
  1931. --image-resolution <dpi>
  1932. Resolution in DPI of color and grayscale images in output
  1933. Default: 300
  1934. --background-gray <percentage>
  1935. Creates a background with a gray color setting on PDF scaling
  1936. Percentage is a floating point percentage number between 0(black) and 1(white)
  1937. --background-cmyk <\"C M Y K\">
  1938. Creates a background with a CMYK color setting on PDF scaling
  1939. Must be quoted into a single parameter as in \"0.2 0.2 0.2 0.2\"
  1940. Each color parameter is a floating point percentage number (between 0 and 1)
  1941. --background-rgb <\"R G B\">
  1942. Creates a background with a RGB color setting on PDF scaling
  1943. Must be quoted into a single parameter as in \"100 100 200\"
  1944. RGB numbers are integers between 0 and 255 (255 122 50)
  1945. --dry-run, --simulate
  1946. Just simulate execution. Will not run ghostscript
  1947. --print-gs-call, --gs-call
  1948. Print GS call to stdout. Will print at the very end between markers
  1949. -p, --print-papers
  1950. Prints Standard Paper info tables to screen and exits
  1951. Scaling Mode:
  1952. - The default mode of operation is scaling mode with fixed paper
  1953. size and scaling pre-set to $SCALE
  1954. - By not using the resize mode you are using scaling mode
  1955. - Flip-Detection and Auto-Rotation are disabled in Scaling mode,
  1956. you can use '-r source -s <scale>' to override.
  1957. - Ghostscript placement is from bottom-left position. This means that
  1958. a bottom-left placement has ZERO for both X and Y translations.
  1959. Resize Paper Mode:
  1960. - Disables the default scaling factor! ($SCALE)
  1961. - Changes the PDF Paper Size in points. Will fit-to-page
  1962. Mixed Mode:
  1963. - In mixed mode both the -s option and -r option must be specified
  1964. - The PDF will be first resized then scaled
  1965. Output filename:
  1966. - Having the extension .pdf on the output file name is optional,
  1967. it will be added if not present.
  1968. - The output filename is optional. If no file name is passed
  1969. the output file will have the same name/destination of the
  1970. input file with added suffixes:
  1971. .SCALED.pdf is added to scaled files
  1972. .<PAPERSIZE>.pdf is added to resized files
  1973. .<PAPERSIZE>.SCALED.pdf is added in mixed mode
  1974. Standard Paper Names: (case-insensitive)
  1975. $paperList
  1976. Custom Paper Size:
  1977. - Paper size can be set manually in Milimeters, Inches or Points
  1978. - Custom paper definition MUST be quoted into a single parameter
  1979. - Actual size is applied in points (mms and inches are transformed)
  1980. - Measurements: mm, mms, milimeters
  1981. pt, pts, points
  1982. in, inch, inches
  1983. Use: $PDFSCALE_NAME -r 'custom <measurement> <width> <height>'
  1984. Ex: $PDFSCALE_NAME -r 'custom mm 300 300'
  1985. Using Source Paper Size: (no-resizing)
  1986. - Wildcard 'source' is used used to keep paper size the same as the input
  1987. - Usefull to run Auto-Rotation without resizing
  1988. - Eg. $PDFSCALE_NAME -r source ./input.pdf
  1989. Backgrounding: (paint a background)
  1990. - Backgrounding only happens when scaling
  1991. - Use a scale of 1.0 to force mixed mode and add background while resizing
  1992. Options and Parameters Parsing:
  1993. - From v2.1.0 (long-opts) there is no need to pass file names at the end
  1994. - Anything that is not a short-option is case-insensitive
  1995. - Short-options: case-sensitive Eg. -v for Verbose, -V for Version
  1996. - Long-options: case-insensitive Eg. --SCALE and --scale are the same
  1997. - Subparameters: case-insensitive Eg. -m PdFinFo is valid
  1998. - Grouping short-options is not supported Eg. -vv, or -vs 0.9
  1999. Additional Notes:
  2000. - File and folder names with spaces should be quoted or escaped
  2001. - Using a scale bigger than 1.0 may result on cropping parts of the PDF
  2002. - For detailed paper types information, use: $PDFSCALE_NAME -p
  2003. Examples:
  2004. $PDFSCALE_NAME myPdfFile.pdf
  2005. $PDFSCALE_NAME -i '/home/My Folder/My PDF File.pdf'
  2006. $PDFSCALE_NAME myPdfFile.pdf \"My Scaled Pdf\"
  2007. $PDFSCALE_NAME -v -v myPdfFile.pdf
  2008. $PDFSCALE_NAME -s 0.85 myPdfFile.pdf My\\ Scaled\\ Pdf.pdf
  2009. $PDFSCALE_NAME -m pdfinfo -s 0.80 -v myPdfFile.pdf
  2010. $PDFSCALE_NAME -v -v -m i -s 0.7 myPdfFile.pdf
  2011. $PDFSCALE_NAME -r A4 myPdfFile.pdf
  2012. $PDFSCALE_NAME -v -v -r \"custom mm 252 356\" -s 0.9 -f \"../input file.pdf\" \"../my new pdf\"
  2013. "
  2014. }
  2015. # Prints usage info
  2016. usage() {
  2017. [[ "$2" != 'nobanner' ]] && printVersion 2
  2018. isNotEmpty "$1" && printError $'\n'"$1"
  2019. printError $'\n'"Usage: $PDFSCALE_NAME [-v] [-s <factor>] [-m <mode>] [-r <paper> [-f <mode>] [-a <mode>]] <inFile.pdf> [outfile.pdf]"
  2020. printError "Help : $PDFSCALE_NAME -h"
  2021. }
  2022. # Prints Verbose information
  2023. vprint() {
  2024. [[ $VERBOSE -eq 0 ]] && return $TRUE
  2025. timestamp=""
  2026. [[ $VERBOSE -gt 1 ]] && timestamp="$(date +%Y-%m-%d:%H:%M:%S) | "
  2027. echo "$timestamp$1"
  2028. }
  2029. # Prints dependency information and aborts execution
  2030. printDependency() {
  2031. printVersion 2
  2032. local brewName="$1"
  2033. [[ "$1" = 'pdfinfo' && "$OSNAME" = "Darwin" ]] && brewName="xpdf"
  2034. printError $'\n'"ERROR! You need to install the package '$1'"$'\n'
  2035. printError "Linux apt-get.: sudo apt-get install $1"
  2036. printError "Linux yum.....: sudo yum install $1"
  2037. printError "MacOS homebrew: brew install $brewName"
  2038. printError $'\n'"Aborting..."
  2039. exit $EXIT_MISSING_DEPENDENCY
  2040. }
  2041. # Prints initialization errors and aborts execution
  2042. initError() {
  2043. local errStr="$1"
  2044. local exitStat=$2
  2045. isEmpty "$exitStat" && exitStat=$EXIT_ERROR
  2046. usage "ERROR! $errStr" "$3"
  2047. exit $exitStat
  2048. }
  2049. # Prints to stderr
  2050. printError() {
  2051. echo >&2 "$@"
  2052. }
  2053. ########################## EXECUTION ###########################
  2054. initDeps
  2055. getOptions "${@}"
  2056. main
  2057. exit $?