-
-
Save rdoursenaud/ec4836c138156b54bacf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Inplace mode added by Raphaël Doursenaud <[email protected]> | |
PROGNAME=${0##*/} | |
INPUT='' | |
QUIET='0' | |
NOSTATS='0' | |
INPLACE='0' | |
max_input_size=0 | |
max_output_size=0 | |
usage() | |
{ | |
cat <<EO | |
Usage: $PROGNAME [options] | |
Script to optimize JPG and PNG images in a directory. | |
Options: | |
EO | |
cat <<EO | column -s\& -t | |
-h, --help & shows this help | |
-q, --quiet & disables output | |
-i, --input [dir] & specify input directory (current directory by default) | |
-o, --output [dir] & specify output directory ("output" by default) | |
-ns, --no-stats & no stats at the end | |
-p, --inplace & optimizes files inplace | |
EO | |
} | |
# $1: input image | |
# $2: output image | |
optimize_image() | |
{ | |
input_file_size=$(stat -c%s "$1") | |
max_input_size=$(expr $max_input_size + $input_file_size) | |
if [ "${1##*.}" = "png" ]; then | |
optipng -o1 -clobber -quiet $1 -out $2.firstpass | |
pngcrush -q -rem alla -reduce $2.firstpass $2 >/dev/null | |
rm -fr $2.firstpass | |
fi | |
if [ "${1##*.}" = "jpg" -o "${1##*.}" = "jpeg" ]; then | |
jpegtran -copy none -progressive $1 > $2 | |
fi | |
output_file_size=$(stat -c%s "$2") | |
max_output_size=$(expr $max_output_size + $output_file_size) | |
} | |
get_max_file_length() | |
{ | |
local maxlength=0 | |
IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v $OUTPUT) | |
for CURRENT_IMAGE in $IMAGES; do | |
filename=$(basename "$CURRENT_IMAGE") | |
if [[ ${#filename} -gt $maxlength ]]; then | |
maxlength=${#filename} | |
fi | |
done | |
echo "$maxlength" | |
} | |
main() | |
{ | |
# If $INPUT is empty, then we use current directory | |
if [[ "$INPUT" == "" ]]; then | |
INPUT=$(pwd) | |
fi | |
# If $OUTPUT is empty, then we use the directory "output" in the current directory | |
if [[ "$OUTPUT" == "" ]]; then | |
OUTPUT=$(pwd)/output | |
fi | |
# If inplace, we use /tmp for output | |
if [[ "$INPLACE" == "1" ]]; then | |
OUTPUT='/tmp/optimize' | |
fi | |
# We create the output directory | |
mkdir -p $OUTPUT | |
# To avoid some troubles with filename with spaces, we store the current IFS (Internal File Separator)... | |
SAVEIFS=$IFS | |
# ...and we set a new one | |
IFS=$(echo -en "\n\b") | |
max_filelength=`get_max_file_length` | |
pad=$(printf '%0.1s' "."{1..600}) | |
sDone=' [ DONE ]' | |
linelength=$(expr $max_filelength + ${#sDone} + 5) | |
# Search of all jpg/jpeg/png in $INPUT | |
# We remove images from $OUTPUT if $OUTPUT is a subdirectory of $INPUT | |
IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v $OUTPUT) | |
if [ "$QUIET" == "0" ]; then | |
echo --- Optimizing $INPUT --- | |
echo | |
fi | |
for CURRENT_IMAGE in $IMAGES; do | |
filename=$(basename $CURRENT_IMAGE) | |
if [ "$QUIET" == "0" ]; then | |
printf '%s ' "$filename" | |
printf '%*.*s' 0 $((linelength - ${#filename} - ${#sDone} )) "$pad" | |
fi | |
optimize_image $CURRENT_IMAGE $OUTPUT/$filename | |
# Replace file | |
if [[ "$INPLACE" == "1" ]]; then | |
mv $OUTPUT/$filename $CURRENT_IMAGE | |
fi | |
if [ "$QUIET" == "0" ]; then | |
printf '%s\n' "$sDone" | |
fi | |
done | |
# Cleanup | |
if [[ "$INPLACE" == "1" ]]; then | |
rm -rf $OUTPUT | |
fi | |
# we restore the saved IFS | |
IFS=$SAVEIFS | |
if [ "$NOSTATS" == "0" -a "$QUIET" == "0" ]; then | |
echo | |
echo "Input: " $(human_readable_filesize $max_input_size) | |
echo "Output: " $(human_readable_filesize $max_output_size) | |
space_saved=$(expr $max_input_size - $max_output_size) | |
echo "Space save: " $(human_readable_filesize $space_saved) | |
fi | |
} | |
human_readable_filesize() | |
{ | |
echo -n $1 | awk 'function human(x) { | |
s=" b Kb Mb Gb Tb" | |
while (x>=1024 && length(s)>1) | |
{x/=1024; s=substr(s,4)} | |
s=substr(s,1,4) | |
xf=(s==" b ")?"%5d ":"%.2f" | |
return sprintf( xf"%s", x, s) | |
} | |
{gsub(/^[0-9]+/, human($1)); print}' | |
} | |
SHORTOPTS="h,i:,o:,q,s,p" | |
LONGOPTS="help,input:,output:,quiet,no-stats,inplace" | |
ARGS=$(getopt -s bash --options $SHORTOPTS --longoptions $LONGOPTS --name $PROGNAME -- "$@") | |
eval set -- "$ARGS" | |
while true; do | |
case $1 in | |
-h|--help) | |
usage | |
exit 0 | |
;; | |
-i|--input) | |
shift | |
INPUT=$1 | |
;; | |
-o|--output) | |
shift | |
OUTPUT=$1 | |
;; | |
-q|--quiet) | |
QUIET='1' | |
;; | |
-s|--no-stats) | |
NOSTATS='1' | |
;; | |
-p|--inplace) | |
INPLACE='1' | |
;; | |
--) | |
shift | |
break | |
;; | |
*) | |
shift | |
break | |
;; | |
esac | |
shift | |
done | |
main | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment