Skip to content

Instantly share code, notes, and snippets.

@liweiyap
Last active September 22, 2020 11:05
Show Gist options
  • Save liweiyap/035d6fd3745f3d737e22e452a4b40dad to your computer and use it in GitHub Desktop.
Save liweiyap/035d6fd3745f3d737e22e452a4b40dad to your computer and use it in GitHub Desktop.
Script to vectorise images on Linux OS using Potrace. Use cases include scanned pages. Reduces image file size πŸ‘.
#!/bin/bash
# exit immediately when:
# - a command fails
# - undeclared variables are used
set -o errexit -o nounset
# error codes
OS_ERR=1
GETOPT_FAIL=2
WRONG_ARGS=3
PROG_ERR=4
if [[ "$OSTYPE" != "linux-gnu"* ]]; then
echo 'ERROR: Script to be run only on Linux'
exit $OS_ERR
fi
usage()
{
echo "Usage: $0 [-b|--blacklevel <black_level>][-t|--turdsize <turd_size>][-r|--rotation <angle>][<inputFileName>]
Args:
black_level: no. b/w 0 and 1.
turd_size: no. higher than 0.
angle: no. b/w 0 and 360 degrees.
inputFileName: if not provided, then the script is run for everything in current directory
Flags:
--blacklevel: if not provided, default value of black_level is 0.5.
--turdsize: if not provided, default value of turd_size is 2.
--rotation: if not provided, default value of angle is 0."
}
# make sure getopt is working
! getopt --test > /dev/null
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
echo 'ERROR: `getopt --test` failed in this environment.'
exit $GETOPT_FAIL
fi
# parse args
OPTIONS=b:t:r:
LONGOPTS=blacklevel:,turdsize:,rotate:
! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")
if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
echo 'ERROR: Wrong arguments'
usage
exit $WRONG_ARGS
fi
# read the output from getopt this way to handle the quoting right:
eval set -- "$PARSED"
black_level=0.5
turd_size=2
rotation=0
while true; do
case "$1" in
-b|--blacklevel)
black_level="$2"
shift 2
;;
-t|--turdsize)
turd_size="$2"
shift 2
;;
-r|--rotate)
rotation="$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Programming error"
exit $PROG_ERR
;;
esac
done
isIntegerGreaterThanZero()
{
regex='^[0-9]+$';
if [[ $1 =~ $regex ]]; then
true
else
false
fi
}
isNumberBetweenZeroAndOne()
{
if isIntegerGreaterThanZero $1 && ( (( $1 == 0)) || (( $1 == 1)) ); then
true
return
fi
regex='^[0-9]+\.[0-9]*$';
if [[ $1 =~ $regex ]]; then
true
else
false
fi
}
# check validity of args
if ! isIntegerGreaterThanZero $turd_size ; then
echo 'ERROR: parameter for <-t|--turdsize> must be positive integer'
usage
exit $WRONG_ARGS
fi
if ! isIntegerGreaterThanZero $rotation ; then
echo 'ERROR: parameter for <-r|--rotation> must be positive integer'
usage
exit $WRONG_ARGS
fi
if (( rotation > 360 )); then
echo 'ERROR: parameter for <-r|--rotation> must be in degrees b/w 0 and 360'
usage
exit $WRONG_ARGS
fi
if ! isNumberBetweenZeroAndOne $black_level ; then
echo 'ERROR: parameter for <-b|--black_level> must be a number b/w 0 and 1'
usage
exit $WRONG_ARGS
fi
# handle non-option arguments
if [[ $# -eq 0 ]]; then
FILES_TO_VECTORISE=*
else
FILES_TO_VECTORISE="$@"
fi
# install programs if uninstalled
if ! loc="$(type -p "potrace")" || [[ -z $loc ]]; then
sudo apt-get update
sudo apt-get install potrace
fi
if ! command -v pdftoppm -png $FILES_TO_VECTORISE &> /dev/null; then
sudo apt-get update
sudo apt-get install poppler-utils
fi
something_to_vectorise=false
# finally, vectorise
for file in $FILES_TO_VECTORISE; do
if [ ${file#*.} == "pdf" ]; then
pdftoppm -png ${file} "${file%%.*}"
mv "${file%%.*}-1.png" "${file%%.*}.png"
file="${file%%.*}.png"
fi
if [ ${file#*.} != "jpg" ] && [ ${file#*.} != "png" ] ; then
continue
fi
# convert to tmp file usable by potrace
convert ${file} "${file%%.*}.ppm"
# now, vectorise
potrace --svg --rotate $rotation --turdsize $turd_size --blacklevel $black_level "${file%%.*}.ppm"
# remove tmp file
rm "${file%%.*}.ppm"
something_to_vectorise=true
# check if filesize of svg is smaller than that of img
non_vectorised_filesize=$(stat -c%s "$file")
vectorised_filesize=$(stat -c%s "${file%%.*}.svg")
if (( vectorised_filesize > non_vectorised_filesize )); then
echo "WARNING: Vectorised file size ($vectorised_filesize bytes) is greater than pre-vectorised file size ($non_vectorised_filesize bytes) for $file"
fi
done
if [ "$something_to_vectorise" = false ] ; then
echo 'No files (.jpg, .png, .pdf) to vectorise.'
fi
echo 'End of script'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment