📜 ⬆️ ⬇️

Image optimization bash-script

The download speed of any site depends on the number and quality of images used. Therefore, it is very important to be able to optimize them. There are many web services for this, but most of them have flaws:


But first of all it should be noted that the method described below cannot be ranked among the best, if only ideally, each image should be optimized individually.

Optimize images using the command line


For each png file, optipng and pngcrush are used , and for jpg - jpegtran . First, let's try optipng:
')


Note: The -o7 optipng option works in the slowest mode. For fast, use -o0.

Then pngcrush:



JPG Optimization with jpegtran:



Script writing


The finished script can be viewed on GitHub . Below is the writing process.

First of all, you need to set the basic parameters:


Two variables for short and full parameter names:

SHORTOPTS="h,i:,o:,q,s" LONGOPTS="help,input:,output:,quiet,no-stats" 

Use getopt to pass parameters to the script, loop to call a function, or define variables to store:

Script code
 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' ;; --) shift break ;; *) shift break ;; esac shift done 


HELP


We create two functions:


They must be declared before the cycle.
Script code
 PROGNAME=${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 EO } SHORTOPTS="h,i:,o:,q,s" LONGOPTS="help,input:,output:,quiet,no-stats" ARGS=$(getopt -s bash --options $SHORTOPTS --longoptions $LONGOPTS --name $PROGNAME -- "$@") 

Check what happened.



Note: if errors occur, like "./optimize.sh: line 2: $ '\ r': command not found", then you need to open the script in Sublime Text 2 and enable Unix Mode in View> Line endings> Unix.

Main function (main)


Script code
 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 # 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 if [ "$QUIET" == "0" ]; then printf '%s\n' "$sDone" fi done # 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 } 

It is necessary to give the opportunity to set directories, or execute a script in the current one using the mkdir command. Next, you need to force the script to work correctly with files with spaces in their names. For this we use IFS (Internal File Separator). The optimize_image image-optimizing function has two parameters — for the source and final directories.

optimize_image:

 # $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 pngcrush -q -rem alla -reduce $1 $2 >/dev/null 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) } 


Output information


The result of the script should be clearly displayed, for example:

 file1 ...................... [ DONE ] file2 ...................... [ DONE ] file_with_a_long_name ...... [ DONE ] ... 

First you need to do the following steps:

  1. Determine the length of file names
  2. Replace gaps with dots
  3. Set the maximum length of the name and text "[DONE]"

As a result, the lines should contain the file name, points and DONE and should be the same length.

Script code
 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 if [ "$QUIET" == "0" ]; then printf '%s\n' "$sDone" fi done 

Check the script by running with the parameters:

 # All parameters to default ./optimize.sh # Or with custom options ./optimize.sh --input images --output optimized-images # Or with custom options and shorthand ./optimize.sh -i images -o optimized-images 



Statistics


To display the statistics of the script use input_file_size and output_file_size, which return the original and final size of the image. For the convenience of reading information, use human_readable_filesize () .

Run the script again and see the statistics:



It remains only to display the process of optimization:

 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 if [ "$QUIET" == "0" ]; then printf '%s\n' "$sDone" fi done 

Everything! The result is a script that can automatically optimize images. Download on GitHub .

Source: https://habr.com/ru/post/154683/


All Articles