#!bin/bash pwd=`pwd` cr=`echo -e '\n> '`; textreset=$(tput sgr0); yellow=$(tput setaf 2); red=$(tput setaf 1); qualityCompression=80; qualityLimit=20; second_run_compression=false; batch=false; echo -n "Please enter the file path: $cr"; read filePath; if [[ ! -f "$filePath" ]] then echo "File "$filePath" not found!"; exit; fi currentDir="${filePath%/*}/"; originalName="${filePath%.*}"; customExt="_MINI"; pngExt="png"; jpgExt="jpg"; jpegExt="jpeg"; function create_batch_directory() { batchFolder="${currentDir}batch_compression/"; if [[ ! -d "$batchFolder" ]] then mkdir "$batchFolder"; else rm -rf "$batchFolder"; mkdir "$batchFolder"; fi } function remove_temp_folder() { if [[ -d "$tempDir" ]] then find -f "temp" \( ! -iname "*.DS_Store" \) | xargs rm -rf fi } function make_image_copy() { tempDir="${pwd}/temp/"; if [[ ! -d "$tempDir" ]] then mkdir "$tempDir"; fi if $batch then name="${files##*/}"; name="${name%.*}"; cp "$files" "${tempDir}${name}${fileExtension}"; tempFilePath="${tempDir}${name}${fileExtension}"; else cp "$filePath" "${tempDir}_temp"; tempFilePath="${tempDir}_temp"; fi } function run_jpegoptim_quality() { if $batch then make_image_copy; jpegoptim -v --max=$qualityCompression "$tempFilePath"; mv "$tempFilePath" "$batchFolder"; imageOutput="${batchFolder}${name}${fileExtension}"; fileOutput=$(ls -l "$imageOutput" | awk '{print $5}'); else if $overwrite then currentFile=$filePath; extension=".$imageType"; else make_image_copy; currentFile=$tempFilePath; extension=$fileExtension; fi jpegoptim -v --max=$qualityCompression "$currentFile"; mv "$currentFile" "${originalName}$extension"; fileOutput=$(ls -l "${originalName}$extension" | awk '{print $5}'); fi if [[ "$fileOutput" -ge $originalLsSize ]] then echo -e "\n${red}******************************************************************************** \n********************** No compression has been performed! **********************\n******************************************************************************** \nThe size of the new file is equal or greater than the size of the original file. \n You should decrease the image quality factor to decrease the size of the file. \n********************************************************************************${textreset} \n"; remove_temp_folder; if ! $batch then qualityCompression=$((qualityCompression-1)); if [[ "$qualityCompression" -gt 0 ]] then adjustImageQuality="Do you wish to adjust the image quality factor below $qualityCompression? (Y/N): " elif [[ "$qualityCompression" -eq 0 ]] then adjustImageQuality="Do you wish to adjust the image quality factor at $qualityCompression? (Y/N): " else exit; fi while true; do read -p "$adjustImageQuality" yn case $yn in [Yy]* ) run_jpegoptim_command; break;; [Nn]* ) exit;; * ) echo "Please answer Yes or No.";; esac done else rm "$imageOutput"; fi else if $batch then outputSize=$(du -h "$imageOutput" | awk '{print $1}'); echo -e "${yellow}\n\xF0\x9f\x8d\xba Compression done! \nOutput: $outputSize, $imageOutput${textreset} \n"; remove_temp_folder; else outputSize=$(du -h "$filePath" | awk '{print $1}'); echo -e "${yellow}\n\xF0\x9f\x8d\xba Compression done! \nOutput: $outputSize, $filePath${textreset} \n"; remove_temp_folder; exit; fi fi } function run_jpegoptim_command() { if $batch then run_jpegoptim_quality; else if ! $second_run_compression then while true; do read -p "`echo $'\n> '`Do you wish to overwrite your image (Y/N)? " yn case $yn in [Yy]* ) second_run_compression=true; overwrite=true; break;; [Nn]* ) second_run_compression=true; overwrite=false; break;; * ) echo "Please answer Yes or No.";; esac done fi if $once then if [[ "$qualityCompression" -gt -1 ]] then while true; do read -p "`echo -e '\n**********************************************************************************'` `echo -e '\n************** Please enter the maximum image quality factor [0-'$qualityCompression'] **************'``echo -e '\n** Note that if you do not enter a value, the default value of' $qualityCompression 'will be used. **'``echo -e '\n**********************************************************************************'` $cr" userQualityCompression; case $userQualityCompression in [0-$qualityCompression]*) qualityCompression=$userQualityCompression ; run_jpegoptim_quality;; * ) run_jpegoptim_quality;; esac done fi else # jpegoptim -v --max=$qualityCompression "$filePath"; outputSize=$(ls -l "$filePath" | awk '{print $5}'); run_jpegoptim_twenty_kb; fi fi } function run_jpegoptim() { command -v jpegoptim >/dev/null 2>&1 || { echo -e >&2 "Jpegoptim hasn't been installed."; while true; do read -p "`echo $'\n> '`Do you wish to install this program (Y/N)? " yn case $yn in [Yy]* ) install_libjpeg;; [Nn]* ) echo "End"; exit;; * ) echo "Please answer Yes or No.";; esac done exit; } twenty_kb=20; if $batch then run_jpegoptim_command; else if [[ $originalLsSize -ge $twenty_kb ]] then while true; do read -p "`echo $'\n> '`Do you need this image to be under a certain size (Y/N)? " yn; case $yn in [Yy]* ) once=false; break;; [Nn]* ) once=true; run_jpegoptim_command;; * ) echo "Please answer Yes or No.";; esac done if ! $once then while true; do twenty_kb=20; currentSize=$(du -h "$filePath" | awk '{print $1}'); currentSize=${currentSize%?}; currentSize=$((currentSize-3)); read -p "`echo -e '\n**********************************************************************************'` `echo -e '\n************** Please enter the minimum image size in Kb [0-'$currentSize'] **************'``echo -e '\n** Note that if you do not enter a value, the default value of' $twenty_kb 'will be used. **'``echo -e '\n**********************************************************************************'` $cr" userSizeInput; if (( 0 <= $userSizeInput && $userSizeInput <= $currentSize )) then twenty_kb=$((userSizeInput*1000)); run_jpegoptim_command; else twenty_kb=$((twenty_kb*1000)); run_jpegoptim_command; fi done fi else once=true; run_jpegoptim_command; fi fi } function pause() { read -p "$*"; } function run_pngquant() { command -v pngquant >/dev/null 2>&1 || { echo -e >&2 "Pngquant command line tool hasn't been installed."; while true; do read -p "Do you wish to install this program (Y/N)? " yn case $yn in [Yy]* ) install_pngquant;; [Nn]* ) echo "End"; exit;; * ) echo "Please answer Yes or No.";; esac done exit; } if $batch then make_image_copy; imageOutput="${batchFolder}${name}${fileExtension}"; fileOutput=$(ls -l "$imageOutput" | awk '{print $5}'); pngquant -vf "$tempFilePath" --ext "$fileExtension"; mv "${tempFilePath}$fileExtension" "$batchFolder"; imageOutput="${tempFilePath}$fileExtension"; currentCompressedFile="${filesNoExt}$fileExtension"; mv "$currentCompressedFile" "$batchFolder"; imageOutput="${batchFolder}${fileNameNoExt}$fileExtension"; else while true; do read -p "`echo $'\n> '`Do you wish to overwrite your image (Y/N)? " yn case $yn in [Yy]* ) overwrite=true; break;; [Nn]* ) overwrite=false; break;; * ) echo "Please answer Yes or No.";; esac done if $overwrite then make_image_copy; pngquant -vf "$tempFilePath" --ext "$fileExtension"; imageOutput="${tempFilePath}$fileExtension"; else pngquant -vf "$filePath" --ext "$fileExtension"; imageOutput="${originalName}$fileExtension"; fi fi output=$(du -h "$imageOutput"); outputSizeFile=$(ls -l "$imageOutput" | awk '{print $5}'); if [ $outputSizeFile -ge $originalLsSize ] then if $batch then echo -e "\n${red}******************************************************************************** \n********************** No compression has been performed! ********************** \n******************************************************************************** \nThe size of the new file is equal or greater than the size of the original file. \n********************************************************************************${textreset} \n"; rm "$imageOutput"; else remove_temp_folder; rm "$imageOutput"; echo -e "\n${red}******************************************************************************** \n********** The compression has already been performed on this file. ************ \n******************************************************************************** \n"; fi else if $overwrite then if $batch then echo "rm temp" remove_temp_folder; else cp "$imageOutput" "$filePath"; remove_temp_folder; fi fi echo -e "${yellow}\n\xF0\x9f\x8d\xba Compression done! \nOutput: $output${textreset} \n"; fi } function run_batch() { create_batch_directory; batch=true; let totalOriginalFileOutput=0; while read -r files; do imageType="${files##*.}"; filesNoExt="${files%.*}"; fileNameNoExt="${filesNoExt##*/}" case ${imageType:(-1)} in [A-Z]*) upperLetter=true;; [a-z]*) upperLetter=false;; esac if $upperLetter then fileExtension="${customExt}".$imageType""; lowerCaseLetters=$(echo $imageType | awk '{print tolower($0)}'); imageType="$lowerCaseLetters"; else imageType="$imageType"; fileExtension="${customExt}".$imageType""; fi originalLsSize=$(ls -l "$files" | awk '{print $5}'); if [[ "$imageType" == *$pngExt* ]] then run_pngquant; elif [[ "$imageType" == *$jpgExt* ]] || [[ "$imageType" == *$jpegExt* ]] then run_jpegoptim; fi done < <(find "$currentDir" -maxdepth 1 \( -iregex '.*\(jpg\)' -o -iregex '.*\(png\)' -o -iregex '.*\(jpeg\)' \)) let totalNewFileOutput=0; let totalOriginalFileOutput=0; let totalSpaceSaved=0; while read -r line; do newFiles+=("$line"); originalFiles="${line##*/}"; originalFiles="${originalFiles%_MINI*}"; while read -r originalLines; do originalFileOutput=$(du -h "$originalLines" | awk '{print $1}'); originalFileOutput=${originalFileOutput%?}; originalFileOutput=${originalFileOutput%.*}; let totalOriginalFileOutput=$totalOriginalFileOutput+$originalFileOutput; done < <(find "$currentDir" -maxdepth 1 \( -iname "*$originalFiles*" \)) newFileOutput=$(du -h "$line" | awk '{print $1}'); newFileOutput=${newFileOutput%?}; newFileOutput=${newFileOutput%.*}; let totalNewFileOutput=$totalNewFileOutput+$newFileOutput; done < <(find "$batchFolder" -maxdepth 1 \( -iregex '.*\(jpg\)' -o -iregex '.*\(png\)' -o -iregex '.*\(jpeg\)' \)) let totalSpaceSaved=$totalOriginalFileOutput-$totalNewFileOutput; echo -e "\n${yellow}********************** Congratulation! You have saved "$totalSpaceSaved"K! **********************${textreset} \n"; echo -e "The new images are: \n"; for i in "${newFiles[@]}" do newFiles=$i; echo "$newFiles" newFilesName="${newFiles##*/}"; newFilesName="${newFilesName%_MINI*}"; newFilesList+=("$newFilesName"); done for y in "${newFilesList[@]}" do while read -r files; do matchingFiles+=("$files"); done < <(find "$currentDir" -maxdepth 1 \( -iname "*$y*" \)) done for z in "${originalFileList[@]}" do for k in "${matchingFiles[@]}" do if [[ "$z" = "$k" ]] then for (( i = 0; i < ${#originalFileListCopy[@]}; i++ )) do if [ "${originalFileListCopy[$i]}" = "${z}" ] then unset "originalFileList[$i]"; fi done fi done done if [ "${#originalFileList[@]}" -gt "0" ] then if [ "${#originalFileList[@]}" -eq "1" ] then imageString="image" else imageString="images" fi echo -e "\n******************************************************************************** \n\n${red}Error occurred with the following $imageString:${textreset} \n"; for f in "${originalFileList[@]}" do echo -e "${red}"$f"${textreset}"; done echo -e "\n${red}Scroll up for more details.${textreset} \n"; fi exit; } itemsCount=($(find "$currentDir" -maxdepth 1 \( -iregex '.*\(jpg\)' -o -iregex '.*\(png\)' -o -iregex '.*\(jpeg\)' \) | grep -v ^l | wc -l)); if [ "$itemsCount" -ge "2" ] then echo -e "\n******************************************************************************** \n********************** This directory contains $itemsCount images! ***********************\n******************************************************************************** \n"; while read -r files; do echo "$files"; originalFileList+=("$files"); originalFileListCopy+=("$files"); done < <(find "$currentDir" -maxdepth 1 \( -iregex '.*\(jpg\)' -o -iregex '.*\(png\)' -o -iregex '.*\(jpeg\)' \)) while true; do read -p "`echo $'\n> '`Do you want to compress these $itemsCount images? (Y/N): " yn; case $yn in [Yy]* ) run_batch; break;; [Nn]* ) break;; * ) echo "Please answer Yes or No.";; esac done fi function install_pngquant() { cd ~/Documents/; git clone git://github.com/pornel/pngquant.git; if [[ -d 'pngquant' ]] then cd pngquant; make -s; make -s install; cd ..; rm -rf ~/Documents/pngquant; command -v pngquant >/dev/null 2>&1 || { echo "Something went horribly wrong and pngquant hasn't been installed! (╯°□°)╯︵ ┻━┻"; exit; } echo -e "********************************** \n******* Installation done! ******* \n********************************** \n"; pause 'Press [Enter] key to compress your image...'; run_pngquant; else echo "Couldn't clone pngquant git repo. \nDo you have an Internet access?"; exit; fi } function install_libjpeg() { cd /usr/local/include/; if [[ -f 'jpeglib.h' ]] then install_jpegoptim; else cd ~/Documents/; curl -O http://www.ijg.org/files/jpegsrc.v8c.tar.gz tar -xf jpegsrc.v8c.tar.gz rm jpegsrc.v8c.tar.gz if [[ -d 'jpeg-8c' ]] then cd jpeg-8c/; ./configure; make; make -s install; cd ..; rm -rf jpeg-8c/; pause 'Press [Enter] key to install jpegoptim...'; install_jpegoptim; else echo -e "Something went horribly wrong and libjpeg hasn't been installed! (╯°□°)╯︵ ┻━┻ \nDo you have Internet access?"; exit; fi fi } function install_jpegoptim() { cd ~/Documents/; git clone https://github.com/tjko/jpegoptim.git; if [[ -d 'jpegoptim' ]] then cd jpegoptim; ./configure; make -s; make -s install; cd ..; rm -rf ~/Documents/jpegoptim; command -v jpegoptim >/dev/null 2>&1 || { echo "Something went horribly wrong and jpegoptim hasn't been installed! (╯°□°)╯︵ ┻━┻"; exit; } echo -e "********************************** \n******* Installation done! ******* \n********************************** \n"; pause 'Press [Enter] key to compress your image...'; run_jpegoptim; else echo -e "Couldn't get jpegoptim. \nDo you have Internet access?"; exit; fi } function run_jpegoptim_twenty_kb() { make_image_copy; copy_ext="_copy"; copyTempFilePath="${tempFilePath}$copy_ext"; cp "$tempFilePath" "$copyTempFilePath"; while [[ $twenty_kb -le $outputSize && $qualityCompression -gt $qualityLimit ]] do cp "$copyTempFilePath" "$tempFilePath"; qualityCompression=$((qualityCompression-1)); jpegoptim -v --max=$qualityCompression "$tempFilePath"; outputSize=$(ls -l "$tempFilePath" | awk '{print $5}'); done if $overwrite then extension=".$imageType"; else extension=$fileExtension; fi if [[ -d "$tempDir" ]]; then rm "$copyTempFilePath"; mv "$tempFilePath" "${originalName}$extension"; fileOutput=$(ls -l "${originalName}$extension" | awk '{print $5}'); fi if [[ "$fileOutput" -ge "$originalLsSize" ]] then echo -e "\n${red}******************************************************************************** \n********************** No compression has been performed! **********************\n******************************************************************************** \nThe size of the new file is equal or greater than the size of the original file. \n**** The minimum image quality factor of 20 might has already been reached. **** \n************* It is not adviced to go below this quality factor. *************** \n********************************************************************************${textreset} \n"; elif [ $twenty_kb -le $outputSize -a $qualityCompression -gt 0 ] then echo -e "\n${yellow}******************************************************************************** \n*********************** Compression has been performed! ************************ \n******************************************************************************** \nThe minimum quality factor has been set to 20 to avoid the image to be corrupted \n*********** Note that the size of the new file is over as 20Kb! ************ \n******************************************************************************** \n\n\xF0\x9f\x8d\xba Output: ${originalName}$extension, $outputSize${textreset} \n"; while true; do userImageSize=$((twenty_kb/1000)); read -p "`echo $'\n> '`Do you still want your file to be below $userImageSize Kb? (Y/N): " yn; case $yn in [Yy]* ) qualityLimit=0; run_jpegoptim_twenty_kb; break;; [Nn]* ) break;; * ) echo "Please answer Yes or No.";; esac done qualityCompression=19 while true; do read -p "`echo $'\n> '`Do you wish to manually set the image quality factor below $qualityCompression? (Y/N): " yn; case $yn in [Yy]* ) once=true; run_jpegoptim_command; break;; [Nn]* ) break;; * ) echo "Please answer Yes or No.";; esac done else echo -e "${yellow}\n\xF0\x9f\x8d\xba Compression done! \n\nOutput: ${originalName}$extension, $outputSize${textreset} \n"; if [ $qualityCompression -eq 0 ] then echo -e "******************************************************************************** \n*************** The image quality factor of 0 has been reached. **************** \n****************** This size is the lowest one you can get. ******************** \n******************************************************************************** \n"; fi fi remove_temp_folder; exit; } imageType="${filePath##*.}"; originalDuSizeFile=$(du -h "$filePath" | awk '{print $1}'); originalLsSize=$(ls -l "$filePath" | awk '{print $5}'); originalDuSize=${originalDuSizeFile%?}; case ${imageType:(-1)} in [A-Z]*) upperLetter=true;; [a-z]*) upperLetter=false;; esac if $upperLetter then fileExtension="${customExt}".$imageType""; lowerCaseLetters=$(echo $imageType | awk '{print tolower($0)}'); imageType="$lowerCaseLetters"; else imageType="$imageType"; fileExtension="${customExt}".$imageType""; fi if ! $batch then if [[ "$imageType" == *$pngExt* ]] then run_pngquant; exit; elif [[ "$imageType" == *$jpgExt* ]] || [[ "$imageType" == *$jpegExt* ]] then run_jpegoptim; exit; else echo "Compression works with PNG, JPG and JPEG only."; exit; fi fi