Skip to content

Instantly share code, notes, and snippets.

@doraTeX
Created December 24, 2023 05:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doraTeX/693c286638abfa4ee32c8f3740b6c0bc to your computer and use it in GitHub Desktop.
Save doraTeX/693c286638abfa4ee32c8f3740b6c0bc to your computer and use it in GitHub Desktop.
A shell script to join PDFs using macOS API ( https://doratex.hatenablog.jp/entry/20220330/1648629672 )
#!/bin/bash
SCRIPTNAME=$(basename "$0")
function realpath () {
f=$@;
if [ -d "$f" ]; then
base="";
dir="$f";
else
base="/$(basename "$f")";
dir=$(dirname "$f");
fi;
dir=$(cd "$dir" && /bin/pwd);
echo "$dir$base"
}
function joinPDF () {
/usr/bin/osascript \
-e 'use framework "Quartz"' \
-e "global CA, NSURL, PDFDocument" \
-e "set CA to current application" \
-e "set NSURL to CA's NSURL" \
-e "set PDFDocument to CA's PDFDocument" \
-e "on pdfPageCount(pdfPath)" \
-e "set url to NSURL's fileURLWithPath:pdfPath" \
-e "set doc to PDFDocument's alloc's initWithURL:url" \
-e "doc's pageCount()" \
-e "end pdfPageCount" \
-e "on joinPDF(pdfPaths, outputPath)" \
-e "set newPDF to PDFDocument's alloc's init" \
-e "set pageCount to 0" \
-e "repeat with pdfPath in pdfPaths" \
-e "set url to (NSURL's fileURLWithPath:pdfPath)" \
-e "set doc to (PDFDocument's alloc's initWithURL:url)" \
-e "set lastIndex to ((my pdfPageCount(pdfPath)) - 1)" \
-e "repeat with i from 0 to lastIndex" \
-e "(newPDF's insertPage:(doc's pageAtIndex:i) atIndex:pageCount)" \
-e "set pageCount to (pageCount + 1)" \
-e "end repeat" \
-e "end repeat" \
-e "newPDF's writeToFile:outputPath" \
-e "end joinPDF" \
-e "my joinPDF({$1}, \"$2\")" \
> /dev/null
}
function usage() {
echo "Usage: $SCRIPTNAME -o <output> <input1> <input2> ..."
echo
echo "options:"
echo " -h, --help Show help"
echo " -o <output>, --output <output> Specify output file"
echo
}
# parse arguments
declare -a args=("$@")
declare -a params=()
OUTPUT=""
I=0
while [ $I -lt ${#args[@]} ]; do
OPT="${args[$I]}"
case $OPT in
-h | --help )
usage
exit 0
;;
-o | --output )
if [[ -z "${args[$(($I+1))]}" ]]; then
echo "$SCRIPTNAME: option requires an argument -- $OPT" 1>&2
exit 1
fi
OUTPUT="${args[$(($I+1))]}"
I=$(($I+1))
;;
-- | -)
I=$(($I+1))
while [ $I -lt ${#args[@]} ]; do
params+=("${args[$I]}")
I=$(($I+1))
done
break
;;
-*)
echo "$SCRIPTNAME: illegal option -- '$(echo $OPT | sed 's/^-*//')'" 1>&2
exit 1
;;
*)
if [[ ! -z "$OPT" ]] && [[ ! "$OPT" =~ ^-+ ]]; then
params+=( "$OPT" )
fi
;;
esac
I=$(($I+1))
done
# handle invalid arguments
if [ ${#params[@]} -eq 0 ]; then
echo "$SCRIPTNAME: too few arguments" 1>&2
echo "Try '$SCRIPTNAME --help' for more information." 1>&2
exit 1
fi
if [ "$OUTPUT" = "" ]; then
echo "Option -o cannot be omitted."
echo "Try '$SCRIPTNAME --help' for more information." 1>&2
exit 1
fi
# change input path list into AppleScript style
declare -a list=()
for FILE in "${params[@]}"; do
list+=("\"$(realpath $FILE)\"")
done
INPUTS="$(echo "$(IFS=","; echo "${list[*]}")")"
# join PDFs
joinPDF "$INPUTS" "$OUTPUT"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment