Skip to content

Instantly share code, notes, and snippets.

@brbsix
Created April 7, 2016 15:30
Show Gist options
  • Save brbsix/546b732a9578343b114b425691c7906f to your computer and use it in GitHub Desktop.
Save brbsix/546b732a9578343b114b425691c7906f to your computer and use it in GitHub Desktop.
wkhtmltopdf
#!/bin/bash
#
# Create a pdf from HTML or URL
cleanup(){
# check whether $TEMPDIR exists and is a subdir of /tmp
if [[ -d $TEMPDIR && $(dirname "$TEMPDIR") = /tmp ]]; then
rm -rf "$TEMPDIR"
fi
}
error(){
echo "ERROR: $@" >&2
}
getbinaries(){
local binaries bpath bversion flag tpath tversion
readarray -t binaries < <(which -a wkhtmltopdf)
if (( OPTION_NEW == 1 )) || (( OPTION_OLD == 1 )); then
declare -Al binmap
for bpath in "${binaries[@]}"; do
bversion=$(getversion "$bpath")
binmap["$bversion"]=$bpath
done
(( OPTION_NEW == 1 )) && flag=r
tversion=$(printf '%s\n' "${!binmap[@]}" | sort -V${flag} | head -n1)
tpath=${binmap["$tversion"]}
binaries=("$tpath")
fi
printf '%s\n' "${binaries[@]}"
}
getistring(){
# get major version number
local mversion=$(getversion "$1" | cut -d. -f2)
if (( mversion >= 12 )); then
echo '--load-error-handling ignore'
else
echo '--ignore-load-errors'
fi
}
getoutput(){
local bn destination fn output_determined output_supplied url
destination=$DESTINATION
url=$1
output_supplied=$2
if [[ -n $output_supplied ]]; then
# check whether supplied output is a destination directory
if [[ -d $output_supplied ]]; then
destination=$output_supplied
# check whether supplied output is a complete path
elif [[ -d $(dirname "$output_supplied") && $(dirname "$output_supplied") != . ]]; then
output_determined=$output_supplied
# check whether supplied output is a filename
else
output_determined=$destination/$output_supplied
fi
fi
if [[ -z $output_determined ]]; then
bn=$(basename "$url")
if [[ $bn = "$url" ]]; then
fn=$RANDOM
else
fn=$(sed 's/^\(.*\)\..*$/\1/' <<<"$bn")
fi
output_determined=${destination}/${fn}.pdf
fi
echo "$output_determined"
}
getversion(){
"$1" --version | awk '/wkhtmltopdf/ {print $2; exit}'
}
makepdf(){
local binaries binary istring output tempfile url
url=$1
# determine actual destination path
output=$(getoutput "$url" "$2")
# ensure destination path does not already exist
if [[ -e $output ]]; then
error "'$output' already exists"
return 1
fi
# ensure temp dir is removed upon exit
trap cleanup EXIT
# create temp dir
TEMPDIR=$(mktemp --directory --tmpdir makepdf-XXXXXX)
# generate temp file path (do not actually create the file yet)
tempfile=$(mktemp --dry-run --tmpdir="$TEMPDIR" XXXXXX.pdf)
readarray -t binaries < <(getbinaries)
for binary in "${binaries[@]}"; do
if (( OPTION_IGNORE == 1 )); then
istring=$(getistring "$binary")
fi
# execute wkhtmltopdf with options
"$binary" $istring "$url" "$tempfile"
STATUS=$?
if [[ -f $tempfile ]]; then
(( OPTION_OPEN == 1 )) && ! opener "$tempfile" && break
mkdir -p "$(dirname "$output")" && mv "$tempfile" "$output" && realpath "$output" && break
else
error "$binary failed to process '$url'"
return 1
fi
done
}
opener(){
local reply
"$PDFTOOL" "$1"
read -n1 -p "Keep file? " reply
echo
[[ $reply = [Yy] ]]
}
usage(){
cat <<-EOF
Usage: $PROGRAM [OPTION]... URL [OUTPUT]
Leverage wkhtmltopdf to create a PDF from URL or HTML.
-i, --ignore ignore load errors
--new use newest version of wkhtmltopdf
--old use oldest version of wkhtmltopdf
-o, --open open pdf with $(basename "$PDFTOOL") after creation
$program accepts the following wkhtmltopdf options:
-l --lowquality
-n --disable-javascript
default binary: ${DEFAULT:-UNAVAILABLE}
default destination: ${DESTINATION}
EOF
exit 0
}
version(){
cat <<-EOF
$PROGRAM $VERSION
Copyright (c) 2015 Six ([email protected])
EOF
exit 0
}
PROGRAM=${0##*/}
VERSION='0.0.3'
DEFAULT=$(which wkhtmltopdf)
DESTINATION=$HOME/Downloads/wkhtmltopdf
PDFTOOL='evince'
if (( $# == 1 )); then
if [[ $1 =~ ^(-h|--help|help)$ ]]; then
usage
elif [[ $1 =~ ^(-v|--version|version)$ ]]; then
version
fi
fi
shopts='i,l,n,o'
lopts='disable-javascript,ignore,lowquality,new,old,open'
params=$(getopt -o "$shopts" -l "$lopts" -n "$program" -- "$@") || exit 1
eval set -- "$params"
# parse options
for arg in "$@"; do
if (( last == 1 )); then
wkargs+=("$arg")
else
case $arg in
-i|--ignore)
OPTION_IGNORE=1
;;
--new)
OPTION_NEW=1
;;
--old)
OPTION_OLD=1
;;
-o|--open)
OPTION_OPEN=1
;;
--)
last=1
;;
esac
fi
done
# check whether arguments were supplied
if (( ${#wkargs[@]} == 0 )); then
echo "$PROGRAM: missing operand" >&2
echo "Try '$PROGRAM --help' for more information." >&2
exit 1
# ensure --new and --old are not combined
elif (( OPTION_NEW == 1 )) && (( OPTION_OLD == 1 )); then
error "'--new' and '--old' may not be used concurrently"
exit 1
# ensure wkhtmltopdf is installed
elif [[ -z $DEFAULT ]]; then
error "wkhtmltopdf is not installed"
exit 1
fi
makepdf "${wkargs[@]}"
exit "${STATUS:-1}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment