optimize_images.sh 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #!/bin/bash
  2. # Borrowed from https://gist.github.com/lgiraudel/6065155
  3. # Inplace mode added by Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  4. PROGNAME=${0##*/}
  5. INPUT=''
  6. QUIET='0'
  7. NOSTATS='0'
  8. INPLACE='0' # (1=Images are replaced, 0=New images are stored into $OUTPUT)
  9. max_input_size=0
  10. max_output_size=0
  11. usage()
  12. {
  13. cat <<EO
  14. Usage: $PROGNAME (list|fix) [options]
  15. Example: optimize_images.sh (list|fix) -i dirtoscan
  16. Script to optimize JPG and PNG images in a directory.
  17. Options:
  18. EO
  19. cat <<EO | column -s\& -t
  20. -h, --help & shows this help
  21. -q, --quiet & disables output
  22. -i, --input [dir] & specify input directory (current directory by default)
  23. -o, --output [dir] & specify output directory ("output" by default)
  24. -ns, --no-stats & no stats at the end
  25. -p, --inplace & optimizes files inplace
  26. EO
  27. }
  28. # $1: input image
  29. # $2: output image
  30. optimize_image()
  31. {
  32. input_file_size=$(stat -c%s "$1")
  33. max_input_size=$(expr $max_input_size + $input_file_size)
  34. if [ "${1##*.}" = "png" ]; then
  35. #optipng -o1 -clobber -quiet "$1" -out "$2.firstpass"
  36. echo optipng -o1 -quiet "$1" -out "$2.firstpass"
  37. optipng -o1 -quiet "$1" -out "$2.firstpass"
  38. pngcrush -q -rem alla -reduce "$2.firstpass" "$2" >/dev/null
  39. rm -fr "$2.firstpass"
  40. fi
  41. if [ "${1##*.}" = "jpg" -o "${1##*.}" = "jpeg" ]; then
  42. jpegtran -copy none -progressive "$1" > $2
  43. fi
  44. output_file_size=$(stat -c%s "$2")
  45. max_output_size=$(expr $max_output_size + $output_file_size)
  46. }
  47. get_max_file_length()
  48. {
  49. local maxlength=0
  50. IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v $OUTPUT)
  51. for CURRENT_IMAGE in $IMAGES; do
  52. filename=$(basename "$CURRENT_IMAGE")
  53. if [[ ${#filename} -gt $maxlength ]]; then
  54. maxlength=${#filename}
  55. fi
  56. done
  57. echo "$maxlength"
  58. }
  59. main()
  60. {
  61. test=`type pngcrush >/dev/null 2>&1`
  62. result=$?
  63. if [ "x$result" == "x1" ]; then
  64. echo "Tool pngcrush not found" && exit
  65. fi
  66. test=`type optipng >/dev/null 2>&1`
  67. result=$?
  68. if [ "x$result" == "x1" ]; then
  69. echo "Tool optipng not found" && exit
  70. fi
  71. test=`type jpegtran >/dev/null 2>&1`
  72. result=$?
  73. if [ "x$result" == "x1" ]; then
  74. echo "Tool jpegtran not found" && exit
  75. fi
  76. # If $INPUT is empty, then we use current directory
  77. if [[ "$INPUT" == "" ]]; then
  78. INPUT=$(pwd)
  79. fi
  80. # If $OUTPUT is empty, then we use the directory "output" in the current directory
  81. if [[ "$OUTPUT" == "" ]]; then
  82. OUTPUT=$(pwd)/output
  83. fi
  84. # If inplace, we use /tmp for output
  85. if [[ "$INPLACE" == "1" ]]; then
  86. OUTPUT='/tmp/optimize'
  87. fi
  88. echo "Mode is $INPLACE (1=Images are replaced, 0=New images are stored into $OUTPUT)"
  89. # We create the output directory
  90. mkdir -p $OUTPUT
  91. # To avoid some troubles with filename with spaces, we store the current IFS (Internal File Separator)...
  92. SAVEIFS=$IFS
  93. # ...and we set a new one
  94. IFS=$(echo -en "\n\b")
  95. max_filelength=`get_max_file_length`
  96. pad=$(printf '%0.1s' "."{1..600})
  97. sDone=' [ DONE ]'
  98. linelength=$(expr $max_filelength + ${#sDone} + 5)
  99. # Search of all jpg/jpeg/png in $INPUT
  100. # We remove images from $OUTPUT if $OUTPUT is a subdirectory of $INPUT
  101. echo "Scan $INPUT to find images with find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/' | grep -v '/documents/' | grep -v $OUTPUT"
  102. #echo "Scan $INPUT to find images with find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/'"
  103. IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/' | grep -v '/documents/' | grep -v $OUTPUT)
  104. #IMAGES=$(find $INPUT -regextype posix-extended -regex '.*\.(jpg|jpeg|png)' | grep -v '/gource/' | grep -v '/includes/' | grep -v '/custom/')
  105. if [ "$QUIET" == "0" ]; then
  106. echo --- Optimizing $INPUT ---
  107. echo
  108. fi
  109. for CURRENT_IMAGE in $IMAGES; do
  110. echo "Process $CURRENT_IMAGE"
  111. filename=$(basename $CURRENT_IMAGE)
  112. if [ "$QUIET" == "0" ]; then
  113. printf '%s ' "$filename"
  114. printf '%*.*s' 0 $((linelength - ${#filename} - ${#sDone} )) "$pad"
  115. fi
  116. optimize_image "$CURRENT_IMAGE" "$OUTPUT/$filename"
  117. # Replace file
  118. if [[ "$INPLACE" == "1" ]]; then
  119. mv "$OUTPUT/$filename" "$CURRENT_IMAGE"
  120. fi
  121. if [ "$QUIET" == "0" ]; then
  122. printf '%s\n' "$sDone"
  123. fi
  124. done
  125. # Cleanup
  126. if [[ "$INPLACE" == "1" ]]; then
  127. rm -rf $OUTPUT
  128. fi
  129. # we restore the saved IFS
  130. IFS=$SAVEIFS
  131. if [ "$NOSTATS" == "0" -a "$QUIET" == "0" ]; then
  132. echo
  133. echo "Input: " $(human_readable_filesize $max_input_size)
  134. echo "Output: " $(human_readable_filesize $max_output_size)
  135. space_saved=$(expr $max_input_size - $max_output_size)
  136. echo "Space save: " $(human_readable_filesize $space_saved)
  137. fi
  138. }
  139. human_readable_filesize()
  140. {
  141. echo -n $1 | awk 'function human(x) {
  142. s=" b Kb Mb Gb Tb"
  143. while (x>=1024 && length(s)>1)
  144. {x/=1024; s=substr(s,4)}
  145. s=substr(s,1,4)
  146. xf=(s==" b ")?"%5d ":"%.2f"
  147. return sprintf( xf"%s", x, s)
  148. }
  149. {gsub(/^[0-9]+/, human($1)); print}'
  150. }
  151. SHORTOPTS="h,i:,o:,q,s,p"
  152. LONGOPTS="help,input:,output:,quiet,no-stats,inplace"
  153. ARGS=$(getopt -s bash --options $SHORTOPTS --longoptions $LONGOPTS --name $PROGNAME -- "$@")
  154. # Syntax
  155. if [ "x$1" != "xlist" -a "x$1" != "xfix" ]
  156. then
  157. usage
  158. exit 0
  159. fi
  160. eval set -- "$ARGS"
  161. while true; do
  162. case $1 in
  163. -h|--help)
  164. usage
  165. exit 0
  166. ;;
  167. -i|--input)
  168. shift
  169. INPUT=$1
  170. ;;
  171. -o|--output)
  172. shift
  173. OUTPUT=$1
  174. ;;
  175. -q|--quiet)
  176. QUIET='1'
  177. ;;
  178. -s|--no-stats)
  179. NOSTATS='1'
  180. ;;
  181. -p|--inplace)
  182. INPLACE='1'
  183. ;;
  184. --)
  185. shift
  186. break
  187. ;;
  188. *)
  189. shift
  190. break
  191. ;;
  192. esac
  193. shift
  194. done
  195. # To convert
  196. if [ "x$1" = "xlist" ]
  197. then
  198. INPLACE=0
  199. fi
  200. main