OLD | NEW |
1 #!/bin/bash | 1 #!/bin/bash |
2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 # The optimization code is based on pngslim (http://goo.gl/a0XHg) | 6 # The optimization code is based on pngslim (http://goo.gl/a0XHg) |
7 # and executes a similar pipleline to optimize the png file size. | 7 # and executes a similar pipleline to optimize the png file size. |
8 # The steps that require pngoptimizercl/pngrewrite/deflopt are omitted, | 8 # The steps that require pngoptimizercl/pngrewrite/deflopt are omitted, |
9 # but this runs all other processes, including: | 9 # but this runs all other processes, including: |
10 # 1) various color-dependent optimizations using optipng. | 10 # 1) various color-dependent optimizations using optipng. |
11 # 2) optimize the number of huffman blocks. | 11 # 2) optimize the number of huffman blocks. |
12 # 3) randomize the huffman table. | 12 # 3) randomize the huffman table. |
13 # 4) Further optimize using optipng and advdef (zlib stream). | 13 # 4) Further optimize using optipng and advdef (zlib stream). |
14 # Due to the step 3), each run may produce slightly different results. | 14 # Due to the step 3), each run may produce slightly different results. |
15 # | 15 # |
16 # Note(oshima): In my experiment, advdef didn't reduce much. I'm keeping it | 16 # Note(oshima): In my experiment, advdef didn't reduce much. I'm keeping it |
17 # for now as it does not take much time to run. | 17 # for now as it does not take much time to run. |
18 | 18 |
19 readonly ALL_DIRS=" | 19 readonly ALL_DIRS=" |
20 ash/resources | 20 ash/resources |
21 ui/resources | 21 ui/resources |
22 chrome/app/theme | 22 chrome/app/theme |
23 chrome/browser/resources | 23 chrome/browser/resources |
24 chrome/renderer/resources | 24 chrome/renderer/resources |
25 webkit/glue/resources | 25 webkit/glue/resources |
26 remoting/resources | 26 remoting/resources |
27 remoting/webapp | 27 remoting/webapp |
28 " | 28 " |
29 | 29 |
| 30 # Files larger than this file size (in bytes) will |
| 31 # use the optimization parameters tailored for large files. |
| 32 LARGE_FILE_THRESHOLD=3000 |
| 33 |
30 # Constants used for optimization | 34 # Constants used for optimization |
31 readonly MIN_BLOCK_SIZE=128 | 35 readonly DEFAULT_MIN_BLOCK_SIZE=128 |
32 readonly LIMIT_BLOCKS=256 | 36 readonly DEFAULT_LIMIT_BLOCKS=256 |
33 readonly RANDOM_TRIALS=100 | 37 readonly DEFAULT_RANDOM_TRIALS=100 |
| 38 # Taken from the recommendation in the pngslim's readme.txt. |
| 39 readonly LARGE_MIN_BLOCK_SIZE=1 |
| 40 readonly LARGE_LIMIT_BLOCKS=2 |
| 41 readonly LARGE_RANDOM_TRIALS=1 |
34 | 42 |
35 # Global variables for stats | 43 # Global variables for stats |
36 TOTAL_OLD_BYTES=0 | 44 TOTAL_OLD_BYTES=0 |
37 TOTAL_NEW_BYTES=0 | 45 TOTAL_NEW_BYTES=0 |
38 TOTAL_FILE=0 | 46 TOTAL_FILE=0 |
39 PROCESSED_FILE=0 | 47 PROCESSED_FILE=0 |
40 | 48 |
41 declare -a THROBBER_STR=('-' '\\' '|' '/') | 49 declare -a THROBBER_STR=('-' '\\' '|' '/') |
42 THROBBER_COUNT=0 | 50 THROBBER_COUNT=0 |
43 | 51 |
44 # Show throbber character at current cursor position. | 52 # Show throbber character at current cursor position. |
45 function throbber { | 53 function throbber { |
46 echo -ne "${THROBBER_STR[$THROBBER_COUNT]}\b" | 54 echo -ne "${THROBBER_STR[$THROBBER_COUNT]}\b" |
47 let THROBBER_COUNT=($THROBBER_COUNT+1)%4 | 55 let THROBBER_COUNT=($THROBBER_COUNT+1)%4 |
48 } | 56 } |
49 | 57 |
50 # Usage: pngout_loop <file> <png_out_options> ... | 58 # Usage: pngout_loop <file> <png_out_options> ... |
51 # Optimize the png file using pngout with the given options | 59 # Optimize the png file using pngout with the given options |
52 # using various block split thresholds and filter types. | 60 # using various block split thresholds and filter types. |
53 function pngout_loop { | 61 function pngout_loop { |
54 local file=$1 | 62 local file=$1 |
55 shift | 63 shift |
56 local opts=$* | 64 local opts=$* |
57 for i in 0 128 256 512; do | 65 if [ $OPTIMIZE_LEVEL == 1 ]; then |
58 for j in $(seq 0 5); do | 66 for j in $(seq 0 5); do |
59 throbber | 67 throbber |
60 pngout -q -k1 -s1 -b$i -f$j $opts $file | 68 pngout -q -k1 -s1 -f$j $opts $file |
61 done | 69 done |
62 done | 70 else |
| 71 for i in 0 128 256 512; do |
| 72 for j in $(seq 0 5); do |
| 73 throbber |
| 74 pngout -q -k1 -s1 -b$i -f$j $opts $file |
| 75 done |
| 76 done |
| 77 fi |
| 78 } |
| 79 |
| 80 # Usage: get_color_depth_list |
| 81 # Returns the list of color depth options for current optimization level. |
| 82 function get_color_depth_list { |
| 83 if [ $OPTIMIZE_LEVEL == 1 ]; then |
| 84 echo "-d0" |
| 85 else |
| 86 echo "-d1 -d2 -d4 -d8" |
| 87 fi |
63 } | 88 } |
64 | 89 |
65 # Usage: process_grayscale <file> | 90 # Usage: process_grayscale <file> |
66 # Optimize grayscale images for all color bit depths. | 91 # Optimize grayscale images for all color bit depths. |
67 # | 92 # |
68 # TODO(oshima): Experiment with -d0 w/o -c0. | 93 # TODO(oshima): Experiment with -d0 w/o -c0. |
69 function process_grayscale { | 94 function process_grayscale { |
70 echo -n "|gray" | 95 echo -n "|gray" |
71 for opt in -d1 -d2 -d4 -d8; do | 96 for opt in $(get_color_depth_list); do |
72 pngout_loop $file -c0 $opt | 97 pngout_loop $file -c0 $opt |
73 done | 98 done |
74 } | 99 } |
75 | 100 |
76 # Usage: process_grayscale_alpha <file> | 101 # Usage: process_grayscale_alpha <file> |
77 # Optimize grayscale images with alpha for all color bit depths. | 102 # Optimize grayscale images with alpha for all color bit depths. |
78 function process_grayscale_alpha { | 103 function process_grayscale_alpha { |
79 echo -n "|gray-a" | 104 echo -n "|gray-a" |
80 pngout_loop $file -c4 | 105 pngout_loop $file -c4 |
81 for opt in -d1 -d2 -d4 -d8; do | 106 for opt in $(get_color_depth_list); do |
82 pngout_loop $file -c3 $opt | 107 pngout_loop $file -c3 $opt |
83 done | 108 done |
84 } | 109 } |
85 | 110 |
86 # Usage: process_rgb <file> | 111 # Usage: process_rgb <file> |
87 # Optimize rgb images with or without alpha for all color bit depths. | 112 # Optimize rgb images with or without alpha for all color bit depths. |
88 function process_rgb { | 113 function process_rgb { |
89 echo -n "|rgb" | 114 echo -n "|rgb" |
90 for opt in -d1 -d2 -d4 -d8; do | 115 for opt in $(get_color_depth_list); do |
91 pngout_loop $file -c3 $opt | 116 pngout_loop $file -c3 $opt |
92 done | 117 done |
93 pngout_loop $file -c2 | 118 pngout_loop $file -c2 |
94 pngout_loop $file -c6 | 119 pngout_loop $file -c6 |
95 } | 120 } |
96 | 121 |
97 # Usage: huffman_blocks <file> | 122 # Usage: huffman_blocks <file> |
98 # Optimize the huffman blocks. | 123 # Optimize the huffman blocks. |
99 function huffman_blocks { | 124 function huffman_blocks { |
100 local file=$1 | 125 local file=$1 |
101 echo -n "|huffman" | 126 echo -n "|huffman" |
102 local size=$(stat -c%s $file) | 127 local size=$(stat -c%s $file) |
103 let MAX_BLOCKS=$size/$MIN_BLOCK_SIZE | 128 local min_block_size=$DEFAULT_MIN_BLOCK_SIZE |
104 if [ $MAX_BLOCKS -gt $LIMIT_BLOCKS ]; then | 129 local limit_blocks=$DEFAULT_LIMIT_BLOCKS |
105 MAX_BLOCKS=$LIMIT_BLOCKS | 130 |
| 131 if [ $size -gt $LARGE_FILE_THRESHOLD ]; then |
| 132 min_block_size=$LARGE_MIN_BLOCK_SIZE |
| 133 limit_blocks=$LARGE_LIMIT_BLOCKS |
106 fi | 134 fi |
107 for i in $(seq 2 $MAX_BLOCKS); do | 135 let max_blocks=$size/$min_block_size |
| 136 if [ $max_blocks -gt $limit_blocks ]; then |
| 137 max_blocks=$limit_blocks |
| 138 fi |
| 139 |
| 140 for i in $(seq 2 $max_blocks); do |
108 throbber | 141 throbber |
109 pngout -q -k1 -ks -s1 -n$i $file | 142 pngout -q -k1 -ks -s1 -n$i $file |
110 done | 143 done |
111 } | 144 } |
112 | 145 |
113 # Usage: random_huffman_table_trial <file> | 146 # Usage: random_huffman_table_trial <file> |
114 # Try compressing by randomizing the initial huffman table. | 147 # Try compressing by randomizing the initial huffman table. |
115 # | 148 # |
116 # TODO(oshima): Try adjusting different parameters for large files to | 149 # TODO(oshima): Try adjusting different parameters for large files to |
117 # reduce runtime. | 150 # reduce runtime. |
118 function random_huffman_table_trial { | 151 function random_huffman_table_trial { |
119 echo -n "|random" | 152 echo -n "|random" |
120 local file=$1 | 153 local file=$1 |
121 local old_size=$(stat -c%s $file) | 154 local old_size=$(stat -c%s $file) |
122 for i in $(seq 1 $RANDOM_TRIALS); do | 155 local trials_count=$DEFAULT_RANDOM_TRIALS |
| 156 |
| 157 if [ $old_size -gt $LARGE_FILE_THRESHOLD ]; then |
| 158 trials_count=$LARGE_RANDOM_TRIALS |
| 159 fi |
| 160 for i in $(seq 1 $trials_count); do |
123 throbber | 161 throbber |
124 pngout -q -k1 -ks -s0 -r $file | 162 pngout -q -k1 -ks -s0 -r $file |
125 done | 163 done |
126 local new_size=$(stat -c%s $file) | 164 local new_size=$(stat -c%s $file) |
127 if [ $new_size -lt $old_size ]; then | 165 if [ $new_size -lt $old_size ]; then |
128 random_huffman_table_trial $file | 166 random_huffman_table_trial $file |
129 fi | 167 fi |
130 } | 168 } |
131 | 169 |
132 # Usage: final_comprssion <file> | 170 # Usage: final_comprssion <file> |
133 # Further compress using optipng and advdef. | 171 # Further compress using optipng and advdef. |
134 # TODO(oshima): Experiment with 256. | 172 # TODO(oshima): Experiment with 256. |
135 function final_compression { | 173 function final_compression { |
136 echo -n "|final" | 174 echo -n "|final" |
137 local file=$1 | 175 local file=$1 |
138 for i in 32k 16k 8k 4k 2k 1k 512; do | 176 if [ $OPTIMIZE_LEVEL == 2 ]; then |
139 throbber | 177 for i in 32k 16k 8k 4k 2k 1k 512; do |
140 optipng -q -nb -nc -zw$i -zc1-9 -zm1-9 -zs0-3 -f0-5 $file | 178 throbber |
141 done | 179 optipng -q -nb -nc -zw$i -zc1-9 -zm1-9 -zs0-3 -f0-5 $file |
| 180 done |
| 181 fi |
142 for i in $(seq 1 4); do | 182 for i in $(seq 1 4); do |
143 throbber | 183 throbber |
144 advdef -q -z -$i $file | 184 advdef -q -z -$i $file |
145 done | 185 done |
146 echo -ne "\r" | 186 echo -ne "\r" |
147 } | 187 } |
148 | 188 |
149 # Usage: optimize_size <file> | 189 # Usage: optimize_size <file> |
150 # Performs png file optimization. | 190 # Performs png file optimization. |
151 function optimize_size { | 191 function optimize_size { |
(...skipping 19 matching lines...) Expand all Loading... |
171 fi | 211 fi |
172 | 212 |
173 echo -n "|filter" | 213 echo -n "|filter" |
174 optipng -q -zc9 -zm8 -zs0-3 -f0-5 $file | 214 optipng -q -zc9 -zm8 -zs0-3 -f0-5 $file |
175 pngout -q -k1 -s1 $file | 215 pngout -q -k1 -s1 $file |
176 | 216 |
177 huffman_blocks $file | 217 huffman_blocks $file |
178 | 218 |
179 # TODO(oshima): Experiment with strategy 1. | 219 # TODO(oshima): Experiment with strategy 1. |
180 echo -n "|strategy" | 220 echo -n "|strategy" |
181 for i in 3 2 0; do | 221 if [ $OPTIMIZE_LEVEL == 2 ]; then |
182 pngout -q -k1 -ks -s$i $file | 222 for i in 3 2 0; do |
183 done | 223 pngout -q -k1 -ks -s$i $file |
| 224 done |
| 225 else |
| 226 pngout -q -k1 -ks -s1 $file |
| 227 fi |
184 | 228 |
185 random_huffman_table_trial $file | 229 if [ $OPTIMIZE_LEVEL == 2 ]; then |
| 230 random_huffman_table_trial $file |
| 231 fi |
186 | 232 |
187 final_compression $file | 233 final_compression $file |
188 } | 234 } |
189 | 235 |
190 # Usage: process_file <file> | 236 # Usage: process_file <file> |
191 function process_file { | 237 function process_file { |
192 local file=$1 | 238 local file=$1 |
193 local name=$(basename $file) | 239 local name=$(basename $file) |
194 # -rem alla removes all ancillary chunks except for tRNS | 240 # -rem alla removes all ancillary chunks except for tRNS |
195 pngcrush -d $TMP_DIR -brute -reduce -rem alla $file > /dev/null | 241 pngcrush -d $TMP_DIR -brute -reduce -rem alla $file > /dev/null |
196 | 242 |
197 if [ ! -z "$OPTIMIZE" ]; then | 243 if [ $OPTIMIZE_LEVEL != 0 ]; then |
198 optimize_size $TMP_DIR/$name | 244 optimize_size $TMP_DIR/$name |
199 fi | 245 fi |
200 } | 246 } |
201 | 247 |
202 # Usage: sanitize_file <file> | 248 # Usage: sanitize_file <file> |
203 function sanitize_file { | 249 function sanitize_file { |
204 local file=$1 | 250 local file=$1 |
205 local name=$(basename $file) | 251 local name=$(basename $file) |
206 local old=$(stat -c%s $file) | 252 local old=$(stat -c%s $file) |
207 local tmp_file=$TMP_DIR/$name | 253 local tmp_file=$TMP_DIR/$name |
208 | 254 |
209 process_file $file | 255 process_file $file |
210 | 256 |
211 local new=$(stat -c%s $tmp_file) | 257 local new=$(stat -c%s $tmp_file) |
212 let diff=$old-$new | 258 let diff=$old-$new |
213 let TOTAL_OLD_BYTES+=$old | |
214 let TOTAL_NEW_BYTES+=$new | |
215 let percent=($diff*100)/$old | 259 let percent=($diff*100)/$old |
216 let TOTAL_FILE+=1 | 260 let TOTAL_FILE+=1 |
217 | 261 |
218 tput el | 262 tput el |
219 if [ $new -lt $old ]; then | 263 if [ $new -lt $old ]; then |
220 echo -ne "$file : $old => $new ($diff bytes : $percent %)\n" | 264 echo -ne "$file : $old => $new ($diff bytes : $percent %)\n" |
221 mv "$tmp_file" "$file" | 265 mv "$tmp_file" "$file" |
| 266 let TOTAL_OLD_BYTES+=$old |
| 267 let TOTAL_NEW_BYTES+=$new |
222 let PROCESSED_FILE+=1 | 268 let PROCESSED_FILE+=1 |
223 else | 269 else |
224 if [ -z "$OPTIMIZE" ]; then | 270 if [ $OPTIMIZE_LEVEL == 0 ]; then |
225 echo -ne "$file : skipped\r" | 271 echo -ne "$file : skipped\r" |
226 fi | 272 fi |
227 rm $tmp_file | 273 rm $tmp_file |
228 fi | 274 fi |
229 } | 275 } |
230 | 276 |
231 function sanitize_dir { | 277 function sanitize_dir { |
232 local dir=$1 | 278 local dir=$1 |
233 for f in $(find $dir -name "*.png"); do | 279 for f in $(find $dir -name "*.png"); do |
234 sanitize_file $f | 280 sanitize_file $f |
(...skipping 22 matching lines...) Expand all Loading... |
257 | 303 |
258 function show_help { | 304 function show_help { |
259 local program=$(basename $0) | 305 local program=$(basename $0) |
260 echo \ | 306 echo \ |
261 "Usage: $program [options] dir ... | 307 "Usage: $program [options] dir ... |
262 | 308 |
263 $program is a utility to reduce the size of png files by removing | 309 $program is a utility to reduce the size of png files by removing |
264 unnecessary chunks and compressing the image. | 310 unnecessary chunks and compressing the image. |
265 | 311 |
266 Options: | 312 Options: |
267 -o Aggressively optimize file size. Warning: this is *VERY* slow and | 313 -o<optimize_level> Specify optimization level: (default is 1) |
268 can take hours to process all files. | 314 0 Just run pngcrush. It removes unnecessary chunks and perform basic |
| 315 optimization on the encoded data. |
| 316 1 Optimize png files using pngout/optipng and advdef. This can further |
| 317 reduce addtional 5~30%. This is the default level. |
| 318 2 Aggressively optimize the size of png files. This may produce |
| 319 addtional 1%~5% reduction. Warning: this is *VERY* |
| 320 slow and can take hours to process all files. |
269 -h Print this help text." | 321 -h Print this help text." |
270 exit 1 | 322 exit 1 |
271 } | 323 } |
272 | 324 |
273 if [ ! -e ../.gclient ]; then | 325 if [ ! -e ../.gclient ]; then |
274 echo "$0 must be run in src directory" | 326 echo "$0 must be run in src directory" |
275 exit 1 | 327 exit 1 |
276 fi | 328 fi |
277 | 329 |
| 330 OPTIMIZE_LEVEL=1 |
278 # Parse options | 331 # Parse options |
279 while getopts oh opts | 332 while getopts o:h opts |
280 do | 333 do |
281 case $opts in | 334 case $opts in |
282 o) | 335 o) |
283 OPTIMIZE=true; | 336 if [[ ! "$OPTARG" =~ [012] ]]; then |
| 337 show_help |
| 338 fi |
| 339 OPTIMIZE_LEVEL=$OPTARG |
| 340 [ "$1" == "-o" ] && shift |
284 shift;; | 341 shift;; |
285 [h?]) | 342 [h?]) |
286 show_help;; | 343 show_help;; |
287 esac | 344 esac |
288 done | 345 done |
289 | 346 |
290 # Make sure we have all necessary commands installed. | 347 # Make sure we have all necessary commands installed. |
291 install_if_not_installed pngcrush | 348 install_if_not_installed pngcrush |
292 if [ ! -z "$OPTIMIZE" ]; then | 349 if [ $OPTIMIZE_LEVEL != 2 ]; then |
293 install_if_not_installed optipng | 350 install_if_not_installed optipng |
294 fail_if_not_installed advdef "http://advancemame.sourceforge.net/comp-download
.html" | 351 fail_if_not_installed advdef "http://advancemame.sourceforge.net/comp-download
.html" |
295 fail_if_not_installed pngout "http://www.jonof.id.au/kenutils" | 352 fail_if_not_installed pngout "http://www.jonof.id.au/kenutils" |
296 fi | 353 fi |
297 | 354 |
298 # Create tmp directory for crushed png file. | 355 # Create tmp directory for crushed png file. |
299 TMP_DIR=$(mktemp -d) | 356 TMP_DIR=$(mktemp -d) |
300 | 357 |
301 # Make sure we cleanup temp dir | 358 # Make sure we cleanup temp dir |
302 trap "rm -rf $TMP_DIR" EXIT | 359 trap "rm -rf $TMP_DIR" EXIT |
303 | 360 |
304 # If no directories are specified, sanitize all directories. | 361 # If no directories are specified, sanitize all directories. |
305 DIRS=$@ | 362 DIRS=$@ |
306 set ${DIRS:=$ALL_DIRS} | 363 set ${DIRS:=$ALL_DIRS} |
307 | 364 |
| 365 echo "Optimize level=$OPTIMIZE_LEVEL" |
308 for d in $DIRS; do | 366 for d in $DIRS; do |
309 echo "Sanitizing png files in $d" | 367 echo "Sanitizing png files in $d" |
310 sanitize_dir $d | 368 sanitize_dir $d |
311 echo | 369 echo |
312 done | 370 done |
313 | 371 |
314 # Print the results. | 372 # Print the results. |
315 let diff=$TOTAL_OLD_BYTES-$TOTAL_NEW_BYTES | 373 let diff=$TOTAL_OLD_BYTES-$TOTAL_NEW_BYTES |
316 let percent=$diff*100/$TOTAL_OLD_BYTES | 374 let percent=$diff*100/$TOTAL_OLD_BYTES |
317 echo "Processed $PROCESSED_FILE files (out of $TOTAL_FILE files)" \ | 375 echo "Processed $PROCESSED_FILE files (out of $TOTAL_FILE files)" \ |
318 "in $(date -u -d @$SECONDS +%T)s" | 376 "in $(date -u -d @$SECONDS +%T)s" |
319 echo "Result : $TOTAL_OLD_BYTES => $TOTAL_NEW_BYTES bytes" \ | 377 echo "Result : $TOTAL_OLD_BYTES => $TOTAL_NEW_BYTES bytes" \ |
320 "($diff bytes : $percent %)" | 378 "($diff bytes : $percent %)" |
321 | 379 |
OLD | NEW |