Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,12 @@ jobs:
chmod +x shrinkpdf.sh
./shrinkpdf.sh -g -r 72 -o new.pdf orig.pdf
ls -al orig.pdf new.pdf

# Shrink the PDF in place.
- name: Shrink the PDF in place
run: |
chmod +x shrinkpdf.sh
cp orig.pdf inplace.pdf
ls -al inplace.pdf
./shrinkpdf.sh -g -r 72 -i inplace.pdf
ls -al inplace.pdf orig.pdf new.pdf
86 changes: 78 additions & 8 deletions shrinkpdf.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,40 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

create_tempdir ()
{
if command -v mktemp >/dev/null 2>&1; then
# Possibly unportable, but far more secure than the fallback below
mktemp -d
else
# Fallback method
temp_base="${TMPDIR:-/tmp}"
# $RANDOM might be undefined, but including a possibly empty string doesn't hurt
# shellcheck disable=SC3028
temp_dir="$temp_base/shrinkpdf.sh.$$.$RANDOM.$(date +%s)"

if mkdir "$temp_dir" 2>/dev/null; then
chmod 700 "$temp_dir"
echo "$temp_dir"
else
echo "could not create temporary directory $temp_dir." >&2
exit 1
fi
fi
}

cleanup_tempdir ()
{
if [ -n "$1" ] ; then
rm -f "$1/output.pdf"
# ShellCheck complains about ls and weird filenames, but we only care about the number of newlines
# shellcheck disable=SC2012
if [ "$( ls -A "$1" 2>/dev/null | wc -l )" -eq 0 ] ; then
# only rm -fr if the directory is empty to avoid recursive deletion catastrophe bugs
rm -fr "$1"
fi
fi
}

shrink ()
{
Expand Down Expand Up @@ -86,15 +120,17 @@ check_input_file ()
check_smaller ()
{
# If $1 and $2 are regular files, we can compare file sizes to
# see if we succeeded in shrinking. If not, we copy $1 over $2:
# see if we succeeded in shrinking.
if [ ! -f "$1" ] || [ ! -f "$2" ]; then
return 0;
echo 0;
return;
fi
ISIZE="$(wc -c "$1" | awk '{ print $1 }')"
OSIZE="$(wc -c "$2" | awk '{ print $1 }')"
if [ "$ISIZE" -lt "$OSIZE" ]; then
echo "Input smaller than output, doing straight copy" >&2
cp "$1" "$2"
echo 1;
else
echo 0;
fi
}

Expand All @@ -105,7 +141,7 @@ check_overwrite ()
# Unfortunately the stronger `-ef` test is not in POSIX.
if [ "$1" = "$2" ]; then
echo "The output file is the same as the input file. This would truncate the file." >&2
echo "Use a temporary file as an intermediate step." >&2
echo "Use a temporary file as an intermediate step, or use the -i flag." >&2
return 1
fi
}
Expand All @@ -123,16 +159,18 @@ usage ()
echo " -o Output file, default is standard output."
echo " -r Resolution in DPI, default is 72."
echo " -t Threshold multiplier for an image to qualify for downsampling, default is 1.5"
echo " -i Inplace operation: Overwrite the input file with the output if smaller. Use with caution."
}

# Set default option values.
grayscale=""
ofile="-"
res="72"
threshold="1.5"
inplace=0

# Parse command line options.
while getopts ':hgo:r:t:' flag; do
while getopts ':hgo:ir:t:' flag; do
case $flag in
h)
usage "$0"
Expand All @@ -142,7 +180,25 @@ while getopts ':hgo:r:t:' flag; do
grayscale="YES"
;;
o)
ofile="${OPTARG}"
if [ "-" = "$ofile" ] ; then
ofile="${OPTARG}"
else
echo "invalid combination of options -o and -i."
exit 1
fi
;;
i)
if [ "-" = "$ofile" ] ; then
temp_dir=$(create_tempdir)
# I actually want this string expanded right here.
# shellcheck disable=SC2064
trap "cleanup_tempdir \"$temp_dir\"" EXIT INT TERM
ofile="$temp_dir/output.pdf"
inplace=1
else
echo "invalid combination of options -o and -i."
exit 1
fi
;;
r)
res="${OPTARG}"
Expand Down Expand Up @@ -179,4 +235,18 @@ get_pdf_version "$ifile" || pdf_version="1.5"
shrink "$ifile" "$ofile" "$res" "$pdf_version" "$threshold" || exit $?

# Check that the output is actually smaller.
check_smaller "$ifile" "$ofile"
if [ 1 -eq "$(check_smaller "$ifile" "$ofile")" ] ; then
# file got bigger, just overwrite with the smaller original
echo "Input smaller than output, doing straight copy" >&2
cp "$ifile" "$ofile"
else
# file has shrunk
if [ 1 -eq "$inplace" ] ; then
# user requested inplace operation, so overwrite the original
# input file with the temporary and smaller output
cp "$ofile" "$ifile"

# if not inplace:
# noting to do, output has already been written to the right place
fi
fi