Program © 2010-2012 Guillaume Dargaud.
Free use and distribution.
Last updated on 2011/12/23
Here's a simple shell script that will display the aspect ratio of an image file, 100 being a square image. It can also be used to select and copy images that are within a certain range.
#! /bin/bash
# Ratio.sh
# This script displays the image ratio of an image (or images)
# It relies on ImageMagick (or possibly GraphicsMagick) being available
# It can also selectively copy images for a range of values
# (c) Guillaume Dargaud - http://www.gdargaud.net/
# Last modification: 20010/11/25
# Options to pass to the copy command (see 'man cp')
CpOpt=-vi
# You shouldn't have to change anything below that
ShowName=1
ShowRatio=1
Min=0
Max=9999999
usage() {
cat << EOF
USAGE: $0 [Options] File [Files...]
Gives the aspect ratio of an image (100*width/height), 100 being square and more than 100 for landscape frames.
OPTIONS:
-n Display filenames but not the aspect ratio
-x Display aspect ratio but not the filenames
-r Display 'Ratio Filename' instead of 'Filename Ratio', allowing you to pipe to 'sort -n'
-g N Only display/copy if the ratio is greater then the value given (inclusive)
-l N Only display/copy if the ratio is lower then the value given (inclusive)
-c Dir Copy images that are within requested -g/-l values to a specific directory
EXAMPLES:
$0 -g \$((100*16/9)) *.jpg to list panoramic images above the 16:9 ratio
$0 -c /tmp/tv -g 133 -l 133 *.tif to copy all 4:3 images to /tmp/tv
EOF
}
while getopts hnxrg:l:c: opt; do
case $opt in
n) unset ShowRatio;;
x) unset ShowName;;
r) Reverse=1;;
g) Min=$OPTARG;;
l) Max=$OPTARG;;
c) Dest=$OPTARG;;
h) usage; exit 1;;
?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ]; then usage; exit 1; fi
if [ "$ShowName" -a "$ShowRatio" ]; then Join=" "; fi
while [ "$1" != "" ]; do
Ratio=$(($(identify -format "100 * %w / %h\n" "$1")))
if [ $Min -le $Ratio -a $Ratio -le $Max ]; then
# Deals with the displayed line
if [ $ShowName ]; then Name="$1"; fi
if [ $ShowRatio ]; then R=$Ratio; fi
if [ "$ShowName" -o "$ShowRatio" ]; then
if [ $Reverse ]; then echo "$R$Join$Name"; else echo "$Name$Join$R"; fi
fi
# Deal with the file copy
if [ $Dest ]; then cp $CpOpt "$1" "$Dest/"; fi
fi
shift
done
Here's a second similar shell script that will display the number of pixels of an image file. It can also be used to select and copy images that are within a certain range, and to make size conversions based on final number of pixels while maintaining aspect ratio.
#! /bin/bash
# MPix.sh
# This script displays the mega-pixel count of an image (or images)
# It relies on ImageMagick (or possibly GraphicsMagick) and bc being available
# It can also selectively copy/convert images for a range of values
# (c) Guillaume Dargaud - http://www.gdargaud.net/
# Last modification: 20010/11/25
# Options to pass to the copy command (see 'man cp')
CpOpt=-vi
# Additional options to pass to ImageMagick convert
#ImgOpt=-quality 92
ImgOpt=
# You shouldn't have to change anything below that
ShowName=1
ShowCount=1
Min=0
Max=9999999999
Divider="/1024/1024"
usage() {
cat << EOF
USAGE: $0 [Options] File [Files...]
Gives the pixel count of an image (10 for 10 million pixels).
OPTIONS:
-n Display filenames but not the pixel count
-x Display pixel count but not the filenames
-r Display 'MPix Filename' instead of 'Filename MPix', allowing you to pipe to 'sort -n'
-m Pixel count is in megapixels (default)
-k Pixel count is in kilopixels
-p Pixel count is in pixels
-g N Only display/copy if the pixel count is greater then the value given (inclusive)
-l N Only display/copy if the pixel count is lower then the value given (inclusive)
-c Dir Copy images that are within requested -g/-l values to a specific directory
-t Nb When used in addition to -c, will downsize the image to a given [mega][kilo]pixel count (or copied instead of enlarged)
EXAMPLES:
$0 -prg \$((1024*768)) *.jpg | sort -n to sort images bigger than 1024x768 pixels by pixel count
$0 -c /tmp/tv -t 2 -g 10 -l 12 * to copy and convert images in the 10~12 MPix range to 2 MPix in /tmp/tv
EOF
}
while getopts hnxrmkpg:l:c:t: opt; do
case $opt in
n) unset ShowCount;;
x) unset ShowName;;
r) Reverse=1;;
m) M=1;;
k) K=1; Divider="/1024";;
p) P=1; Divider="";;
g) Min=$OPTARG;;
l) Max=$OPTARG;;
c) Dest=$OPTARG;;
t) Trans=$OPTARG;;
h) usage; exit 1;;
?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
esac
done
shift $(($OPTIND - 1))
if [ $# -eq 0 ]; then usage; exit 1; fi
if [ "$ShowName" -a "$ShowCount" ]; then Join=" "; fi
while [ "$1" != "" ]; do
Count=$(($(identify -format "%w * %h$Divider\n" "$1")))
if [ $Min -le $Count -a $Count -le $Max ]; then
# Deals with the displayed line
if [ $ShowName ]; then Name="$1"; fi
if [ $ShowCount ]; then Cnt=$Count; fi
if [ "$ShowName" -o "$ShowCount" ]; then
if [ $Reverse ]; then echo "$Cnt$Join$Name"; else echo "$Name$Join$Cnt"; fi
fi
# Deals with file copy / conversion
if [ $Dest ]; then
if [ $Trans ]; then # Convert
DestFile="$Dest/$(basename "$1")"
Count=$(identify -format "%w * %h" "$1" | bc -l)
if [ $M ]; then Mult="1024*1024"; fi
if [ $K ]; then Mult="1024"; fi
if [ $P ]; then Mult="1"; fi
# bash arithmetics only work with integers, but here we need a sqrt, so we use bc
RS=$( echo "100 * sqrt ( $Trans * $Mult / $Count ) + 0.5" | bc -l | sed -e "s/\..*//")
if [ $RS -ge 100 ]; then # Simple copy
cp $CpOpt "$1" "$Dest/";
else # Resampling
convert "$1" -resize $RS% $ImgOpt "$DestFile"
fi
else # Only copy
cp $CpOpt "$1" "$Dest/";
fi
fi
fi
shift
done
The bash shell built-in getopts is used to read command line parameters passed to a script. It can read single letter parameters, single letter parameters with a single argument, possibly repeated single letter parameters, possibly joined, but not long parameters. For instance, it can read: script -h -vv -f "my file" arg1 arg2, in that case the parameters are h, f and v (twice). But it can't read -long --long -f File1 File2... Here's how you can use it, with a simplified example:
#! /bin/bash
function usage {
cat << EOF
USAGE: $0 [-v] [-h] [-f File] [args...]
EOF
}
while getopts vf:h opt; do
# 'opt' is the variable that will contain each letter in turn.
# 'vf:h' describes the list of single letter parameters,
# with a : if there's an optional argument (which ends up in $OPTARG)
case $opt in
v) echo "parameter -v";; # the order of vgh doesn't matter
f) echo "parameter -f with argument $OPTARG";; # Here we make use of the argument passed along -f
h) usage; exit 1;;
?) echo "Invalid option: -$OPTARG" >&2; exit 1;;
esac
done
shift $(($OPTIND - 1)) # This is necessary so that now the remaining arguments end up as $1, $2...
if [ $# -eq 0 ]; then usage; exit 1; fi # No other arguments, may or may not be a good thing
while [ "$1" != "" ]; do
echo "Argument: $1" # Now list all the remaining arguments
shift # Next argument
done
There are a few other options. For more info you can try help getopts since man doesn't usually work for builtins. And here's the result:
$ ./tmp -v parameter -v USAGE: ./tmp [-v] [-h] [-f File] [args...] $ ./tmp -vv -fFile1 -v -f "Big File" Arg1 Arg2 Arg3 parameter -v parameter -v parameter -f with argument File1 parameter -v parameter -f with argument Big File Argument: Arg1 Argument: Arg2 Argument: Arg3