285 lines
8.0 KiB
Bash
Executable File
285 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# $Id: png_recompress.sh 5270 2008-01-08 21:23:59Z anmaster $
|
|
|
|
# Copyright (C) 2007-2008 Arvid Norlander <anmaster AT tele2 DOT se>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# This script recompressess .png files using optipng and
|
|
# advpng to get the smallest images. All recompression is
|
|
# looseless.
|
|
#
|
|
# This script needs at least bash 3.1, bash 3.x or 2.x will not work.
|
|
# (Note that it was only tested on bash 3.2.17 or later though.)
|
|
# Also this need the programs mentioned above (optipng and advpng).
|
|
#
|
|
# TODO:
|
|
# * Better docs
|
|
# * Check that input really are *.png
|
|
# * If advpng doesn't make a file smaller, don't run the second
|
|
# optipng pass on that file (if the first optipng pass was enabled).
|
|
|
|
# Check for new enough bash version
|
|
fail_old_bash() {
|
|
echo "Sorry your bash version is too old!"
|
|
echo "You need at least version 3.1 of bash."
|
|
echo "Please install a newer version:"
|
|
echo " * Either use your distro's packages."
|
|
echo " * Or see http://www.gnu.org/software/bash/"
|
|
exit 2
|
|
}
|
|
|
|
# Check bash version. We need at least 3.1
|
|
# Lets not use anything like =~ here because
|
|
# that may not work on old bash versions.
|
|
if [[ "${BASH_VERSINFO[0]}${BASH_VERSINFO[1]}" -lt 31 ]]; then
|
|
fail_old_bash
|
|
fi
|
|
|
|
# Version
|
|
declare -r png_recompress_version='0.0.1'
|
|
|
|
# Useful for debugging
|
|
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]} : '
|
|
|
|
print_cmd_help() {
|
|
echo 'png_recompress is a script to automate compressing of png images.'
|
|
echo ''
|
|
echo 'Usage: png_recompress [OPTION] files...'
|
|
echo ''
|
|
echo 'Options:'
|
|
echo ' -h, --help Display this help and exit.'
|
|
echo ' -V, --version Output version information and exit.'
|
|
echo ' -r, --recursive Run recursively on directories specified on command line. Will not follow symlinks.'
|
|
echo ' --skip pass Make png_recompress skip this pass (1, 2 or 3).'
|
|
echo ''
|
|
echo "Note that png_recompress can't handle short versions of options being written together like"
|
|
echo "-vv currently."
|
|
echo ''
|
|
echo 'Exit status is 0 if OK, 1 if minor problems, 2 if serious trouble.'
|
|
echo ''
|
|
echo 'Examples:'
|
|
echo ' png_recompress *.png Runs png_recompress on all *.png files in the current directory.'
|
|
exit $1
|
|
}
|
|
|
|
print_version() {
|
|
echo "png_recompress $png_recompress_version - Script to automate compressing of png images."
|
|
echo ''
|
|
echo 'Copyright (C) 2007-2008 Arvid Norlander'
|
|
echo 'This is free software; see the source for copying conditions. There is NO'
|
|
echo 'warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.'
|
|
echo ''
|
|
echo 'Written by Arvid Norlander.'
|
|
envbot_quit 0
|
|
}
|
|
|
|
#---------------------------------------------------------------------
|
|
## Checks if a space separated list contains a value.
|
|
## @param List to check.
|
|
## @param Value to check for.
|
|
## @return 0 If found.
|
|
## @return 1 If not found.
|
|
#---------------------------------------------------------------------
|
|
list_contains() {
|
|
[[ " ${!1} " = *" $2 "* ]]
|
|
}
|
|
|
|
die() {
|
|
if [[ $2 ]]; then
|
|
echo -e "\e[1mERROR\e[0m: $2"
|
|
fi
|
|
exit $1
|
|
}
|
|
|
|
# Array of paths (images or directories) to process
|
|
PATHS=()
|
|
# Option: Skip passes
|
|
SKIP=""
|
|
# Recursive?
|
|
RECURSIVE=''
|
|
if [[ $# -gt 0 ]]; then
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
'--help'|'-help'|'--usage'|'-usage'|'-h')
|
|
print_cmd_help 0
|
|
;;
|
|
'--version'|'-V')
|
|
print_version
|
|
;;
|
|
'--recursive'|'-r')
|
|
RECURSIVE=1
|
|
shift 1
|
|
;;
|
|
'--skip')
|
|
if [[ -z "$2" ]]; then
|
|
die 1 "Missing parameter to --skip. Maybe try --help"
|
|
else
|
|
case $2 in
|
|
1|2|3)
|
|
SKIP+=" $2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
die 1 "Parameter to skip must be 1, 2 or 3 (see --help)"
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
'-'*)
|
|
die 1 "Unknown option, try --help"
|
|
;;
|
|
*)
|
|
PATHS+=( "$1" )
|
|
shift 1
|
|
;;
|
|
esac
|
|
done
|
|
else
|
|
print_cmd_help 1
|
|
fi
|
|
|
|
if ! hash optipng > /dev/null 2>&1; then
|
|
echo "Can't find optipng!"
|
|
echo "This script depends on the optipng tool to be in PATH."
|
|
echo "Please install it or, if it is already installed add the"
|
|
echo "directory it is in to PATH and try again."
|
|
echo "Homepage of this tool is: http://optipng.sourceforge.net/"
|
|
die 2
|
|
fi
|
|
|
|
if ! hash advpng > /dev/null 2>&1; then
|
|
echo "Can't find advpng!"
|
|
echo "This script depends on the advpng tool to be in PATH."
|
|
echo "Please install it or, if it is already installed add the"
|
|
echo "directory it is in to PATH and try again."
|
|
echo "Homepage of this tool is: http://advancemame.sourceforge.net/comp-readme.html"
|
|
echo "Hint: For package name in your distro, try looking for \"advancecomp\" if"
|
|
echo "there is no \"advpng\"."
|
|
die 2
|
|
fi
|
|
|
|
echo -e "Please wait, this can take a \e[1mlong\e[0m time."
|
|
|
|
# Array of image files
|
|
IMAGES=()
|
|
|
|
|
|
# ${PATHS[@]} paths to process
|
|
# Sets IMAGES
|
|
collect_images_recursive() {
|
|
local image directory results
|
|
local images=()
|
|
for directory in "${PATHS[@]}"; do
|
|
if ! [[ -d $directory && -r "$directory" && -w "$directory" ]]; then
|
|
echo "$directory skipped: directory not found, not readable and/or writable, or not a directory."
|
|
continue
|
|
fi
|
|
export IFS=$'\n'
|
|
results=( $(find "$directory" -iname '*.png' -type f -print ) )
|
|
unset IFS
|
|
images+=( "${results[@]}" )
|
|
done
|
|
PATHS=( "${images[@]}" )
|
|
}
|
|
|
|
# This will check that the images in question is a png, otherwise remove it from the list
|
|
checkimages() {
|
|
local image
|
|
local failcount=0
|
|
for image in "${PATHS[@]}"; do
|
|
# First check it is a file that exists:
|
|
if ! [[ -f "$image" && -r "$image" && -w "$image" ]]; then
|
|
echo "$image skipped: file not found, not readable and/or writable, or not a normal file"
|
|
(( failcount++ ))
|
|
continue
|
|
elif ! [[ $(file -i "$image" ) == *image/png* ]]; then
|
|
echo "$image skipped: not a valid png (according to file)"
|
|
(( failcount++ ))
|
|
continue
|
|
else
|
|
IMAGES+=( "$image" )
|
|
fi
|
|
done
|
|
if [[ $failcount -ne 0 ]]; then
|
|
echo "Of the images given as parameters $failcount could not be processed (see above for reasons)"
|
|
else
|
|
echo "All images ok"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Run optipng
|
|
dooptipng() {
|
|
optipng -i 0 -o 7 "$@" | \
|
|
awk '
|
|
/^\*\* Processing:/ { print "File: " $3 }
|
|
/^Input file size/ { print "Input: " $5,$6 }
|
|
/^Output file size/ { print "Output: " $5,$6,$7,$8,$9,$10,$11,"\n" }
|
|
/is already optimized/ { print "Output: No change\n" }
|
|
'
|
|
}
|
|
|
|
# Run advpng
|
|
doadvpng() {
|
|
# I hope this matches up with the columns in all cases...
|
|
echo " In Out % Filename"
|
|
advpng -z -4 "$@"
|
|
}
|
|
|
|
# Check if pass should run, if yes print out the string as description and
|
|
# returns true. If no: returns false.
|
|
# $1 = pass number
|
|
# $2 = string to print
|
|
pass_check() {
|
|
if ! list_contains SKIP "$1"; then
|
|
echo -e "\n\e[1mPass $1: $2\e[0m\n"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
if [[ $RECURSIVE ]]; then
|
|
echo "Collecting images from directories"
|
|
collect_images_recursive
|
|
fi
|
|
|
|
pass_check 0 "verifying images (can not be skipped, checks that all images exists and are png)" && {
|
|
checkimages || die 2 "Pass 0 (check images) failed with return code $?"
|
|
}
|
|
|
|
# Hacks around issue with one more newline on optipng
|
|
echo
|
|
|
|
pass_check 1 "optipng" && {
|
|
dooptipng "${IMAGES[@]}" || die 2 "Pass 1 (optipng) failed with return code $?"
|
|
}
|
|
|
|
pass_check 2 "advpng" && {
|
|
doadvpng "${IMAGES[@]}" || die 2 "Pass 2 (advpng) failed with return code $?"
|
|
}
|
|
|
|
# Hacks around issue with one more newline on optipng
|
|
echo
|
|
|
|
pass_check 3 "optipng again (as advpng often makes optipng more effective)" && {
|
|
dooptipng "${IMAGES[@]}" || die 2 "Pass 3 (optipng) failed with return code $?"
|
|
}
|
|
|
|
# Hacks around issue with one more newline on optipng
|
|
echo
|
|
|
|
exit 0
|