#!/bin/bash
#EXIF statistics script by causa-prima 2010
#original script by spoilerhead 2009-2010
# $Id: pictstatistics.sh,v 1.5 2011/11/13 09:57:55 ks Exp ks $
# cleanup and abort on signals
trap 'echo "CANCELED"; rm -rf "${STATDIR}/temp"; exit 1' 1 2 3 15
BEGIN=$(date +%s)
### Parameters (default values)
# 0=debug,1=info,2=error,3=critical
VERBOSELEVEL=1
# directory for storing the statistical data
STATDIR="./pictstat"
# default file extension for picture data
FILEEXT=".CR2"
# filename for html index
INDEXFILE=${STATDIR}/index.html
# exposure times in decimal (d) or fraction (f) format
EXPTIMEFMT="f"
# which tool is used to draw the graphs: "gnuplot" or "google"
DRAWTOOL="gnuplot"
# dimensions of graph (only gnuplot)
GRAPHHEIGHT=600
GRAPHWIDTH=1400
# draw only new graphs from available data (0) or collect new picture data
COLLECTDATA=1
# html titles and xaxis label (only gnuplot) for the picture files
TITLE[0]="af_stats:Autofocus Mode"
TITLE[1]="apr_stats:Aperture Values"
TITLE[2]="exposure_stats:Exposure Values"
TITLE[3]="flash_stats:Flash Used"
TITLE[4]="focal_stats:Focal Length"
TITLE[5]="iso_stats:Iso Values"
TITLE[6]="lens_meter:Exposure Mode"
TITLE[7]="lens_stats:Lens Used"
TITLE[8]="orientation_stats:Orientation"
TITLE[9]="shoot_stats:Metering Mode"
# number of parallel exiftool processes to evaluate picture data
MAXPROC=8
# functions ------------------------------------------------------------------------
# output for messages depending on verbosity
# $1 severity, $2 message
# `-> 0=debug,1=info,2=error,3=critical
function msg()
{
if [ $1 -ge $VERBOSELEVEL ]; then
if [ $1 -ge 2 ]; then
# use stderr for printing the message
echo >&2 -e "$2"
else
# use stdout for printing the message
echo -e "$2"
fi
fi
if [ $1 -ge 3 ]; then
exit 3
fi
}
# print usage information
function printhelp () {
echo "usage: $0 [-h] [-d <DEBUGLEVEL>] [-e <EXTENSION>] [-f] [-g] [-p] [-n] [-P <MAXPROC>] "
echo "-h this help message"
echo "-d <n> set debug level: 0=debug,1=info,2=error,3=critical"
echo "-e <.ext> extension for picture files (ie. \".CR2\" or \".jpg\"), not case sensitive, default is $FILEEXT"
echo "-f print exposure time in fraction instead of decimal format"
echo "-g draw graph pictures with google chart tool"
echo "-p draw graph pictures with gnuplot"
echo "-g and -p are mutual exclusive, latest found option is used, default is $DRAWTOOL"
echo "-n no data gathering, use available .txt files to draw new graphs"
echo "-P <n> number of parallel processes for gathering picture data, default is $MAXPROC"
echo -e "\n"
}
# make an empty html file
# $1 file
function htmlclear()
{
msg 0 "Creating HTML file for $1."
echo -n > "$1" || msg 3 "Error creating HTML file. Stop."
}
# print a string to an html-file
# $1 string, $2 file
function htmlprint()
{
echo -e -n $1 >> "$2" || msg 3 "Error writing HTML file. Stop."
}
# setup html header
# $1 title, $2 file
function htmlheader()
{
msg 0 "Writing HTML header for $2."
htmlprint "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n" "$2"
htmlprint "<html>\n" "$2"
htmlprint "<head>\n" "$2"
htmlprint "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n" "$2"
htmlprint "<title>$1</title>\n" "$2"
htmlprint "</head>\n" "$2"
htmlprint "<body style=\"text-align: center;\">\n" "$2"
}
# write out html footer
# $1 file
function htmlfooter()
{
msg 0 "Writing HTML footer for $1."
htmlprint "<br />\n" "$1"
htmlprint "</body>\n" "$1"
htmlprint "</html>\n" "$1"
}
# $1 name of tool
function toolcheck()
{
X=`type -p $1`
if test $X && test -x $X;
then return 0
else return 1
fi
}
# draw graph wit gnuplot
# $1 = filename without extention
# $2 = labels of xaxis
function drawgraph_gnuplot
{
GNUTERM="unknown" GDFONTPATH="/usr/share/fonts/corefonts" $GNUPLOT <<EOF
reset
clear
set encoding locale
set style data histograms
set style fill solid 2 border -1
set boxwidth 2 relative
set autoscale
set ylabel "# pictures" font "arial,10"
set grid y front
set xlabel "$2" font "arial,10"
# set title "$2" font "arial,14"
# for testing
# set term x11 size ${GRAPHWIDTH},${GRAPHHEIGHT}
# where can gnuplot find the arial.ttf
# export GDFONTPATH="/usr/share/fonts/corefonts"
# output as PNG graph
set term png size ${GRAPHWIDTH},${GRAPHHEIGHT} font "arial,8"
set output '$1.png'
# to display the generated graph on the screen
# set output '| display png:-'
set xtics nomirror rotate by -90 out
plot "$1.qtxt" using 1:xticlabels(2) notitle
# output as SVG graph
set term svg size ${GRAPHWIDTH},${GRAPHHEIGHT} font "Arial,8"
set output '$1.svg'
# to display the generated graph on the screen
# set output '| display svg:-'
set xtics nomirror rotate by -90 out offset 0-1.2,graph 0
plot "$1.qtxt" using 1:xticlabels(2) notitle
EOF
}
# draw pie chart with google chart api
# $1 filename without extention for date-file (.txt) and picture-file (.png)
# $2 filename for url without extention
function drawpie_google
{
cat ${STATDIR}/$1.txt | head -1 | awk '{print $1}' >> ${STATDIR}/temp/$2.txt
echo "&cht=p&chd=t:" >> ${STATDIR}/temp/$2.txt
awk '{printf $1","}' ${STATDIR}/$1.txt | sed 's/\(.*\)./\1/' >> ${STATDIR}/temp/$2.txt
echo "&chl=" >> ${STATDIR}/temp/$2.txt
awk '{{ for (i = 2; i <= NF; i++) printf $i"+" } printf "|"}' ${STATDIR}/$1.txt | sed 's/.\{2\}$//' >> ${STATDIR}/temp/$2.txt
# awk '{printf $2"|"'} ${STATDIR}/$1.txt | sed 's/.\{1\}$//' >> ${STATDIR}/temp/$2.txt
awk '{printf $1}' ${STATDIR}/temp/$2.txt > ${STATDIR}/temp/$2.txt2
wget -i ${STATDIR}/temp/$2.txt2 -O ${STATDIR}/$1.png > /dev/null 2>&1
}
# draw histogramm with google chart api
# $1 filename without extention for date-file (.txt) and picture-file (.png)
# $2 filename for url without extention
function drawhist_google
{
sort -g -r ${STATDIR}/$1.txt | head -1 | awk '{print $1}' >> ${STATDIR}/temp/$2.txt
echo "&chbh=r,0.5,1.5&chxt=x,y&chxr=1,0," >> ${STATDIR}/temp/$2.txt
sort -g -r ${STATDIR}/$1.txt | head -1 | awk '{print $1}' >> ${STATDIR}/temp/$2.txt
awk '{print $2 , $1}' ${STATDIR}/$1.txt | sort -g | awk '{print $2 , $1}' > ${STATDIR}/$1.txt2
mv ${STATDIR}/$1.txt2 ${STATDIR}/$1.txt
echo "&cht=bvs&chd=t:" >> ${STATDIR}/temp/$2.txt
awk '{printf $1","}' ${STATDIR}/$1.txt | sed 's/\(.*\)./\1/' >> ${STATDIR}/temp/$2.txt
echo "&chl=" >> ${STATDIR}/temp/$2.txt
awk '{printf $2"|"'} ${STATDIR}/$1.txt | sed 's/.\{1\}$//' >> ${STATDIR}/temp/$2.txt
awk '{printf $1}' ${STATDIR}/temp/$2.txt > ${STATDIR}/temp/$2.txt2
wget -i ${STATDIR}/temp/$2.txt2 -O ${STATDIR}/$1.png > /dev/null 2>&1
}
# option handler ----------------
ABORT=0
while getopts "hd:e:fgpnP:" MYOPTION
do
# echo "$MYOPTION" $OPTIND $OPTARG
if [ "$MYOPTION" = "h" -o "$MYOPTION" = "?" ]; then
# print usage
ABORT=1
fi
if [ "$MYOPTION" = "d" ]; then
# set debug level
if [ $OPTARG -ge 0 -a $OPTARG -le 9 ]; then
VERBOSELEVEL=$OPTARG
msg 0 "set verbosity to $VERBOSELEVEL"
else
msg 2 "$OPTARG not valid for debug level - please provide a value between 0 and 9\n"
ABORT=1
fi
fi
if [ "$MYOPTION" = "e" ]; then
# extention for picture files
FILEEXT=$OPTARG
msg 1 "search for files with extention $FILEEXT"
if [ "${FILEEXT:0:1}" != "." ]; then
msg 3 "Extention has to start with \".\""
fi
echo $FILEEXT | grep "[[:space:]]" &>/dev/null && msg 3 "only one extention allowed"
fi
if [ "$MYOPTION" = "f" ]; then
# exposure times in fraction format
EXPTIMEFMT=f
msg 1 "exposure times in fraction format"
fi
if [ "$MYOPTION" = "g" ]; then
# draw graphs with google chart tool
DRAWTOOL="google"
msg 1 "use google chart tool for drawing the graphics"
fi
if [ "$MYOPTION" = "p" ]; then
# draw graphs with gnuplot tool
DRAWTOOL="gnuplot"
msg 1 "use gnuplot for drawing the graphics"
fi
if [ "$MYOPTION" = "n" ]; then
# don't evaluate the pictrues, draw graphs with available data
COLLECTDATA=0
msg 1 "don't collect new data and draw new graphs with the available .txt files"
fi
if [ "$MYOPTION" = "P" ]; then
# number of parallel processes for gathering picture data
MAXPROC=$OPTARG
msg 1 "set number of parallel processes to $MAXPROC"
if [ $MAXPROC -lt 1 -o $MAXPROC -gt 99 ]; then
msg 3 "unvalid value for parallel processes, use 1 to 99"
fi
fi
done # option handling
if [ $ABORT -eq 1 ]; then
# option not valid - abort script
printhelp
exit 1
fi
# Tools needed
# specify full path when not in $PATH
EXIFTOOL="exiftool"
GNUPLOT="gnuplot"
# All tools available ?
toolcheck $EXIFTOOL || msg 3 "exiftool not found."
if [ "$DRAWTOOL" == "gnuplot" ]; then
toolcheck $GNUPLOT || msg 3 "gnuplot not found."
fi
# main -----------------------------------------------------------------------------------
NOPICT=0 # number of picture files found
if [ $COLLECTDATA -eq 1 ]; then
# evaluate all pictures and create new data files
msg 1 "collecting picture data ..."
# delete old image data create necessary directories
[ -e ${STATDIR}/temp/imgdatap.txt ] && rm ${STATDIR}/temp/imgdatap.txt
[ -d ${STATDIR} ] || mkdir ${STATDIR}
[ -d ${STATDIR}/temp ] || mkdir ${STATDIR}/temp
[ -d ${STATDIR} ] || msg 3 "directory ${STATDIR} doesn\'t exist - exiting"
COUNT=1
NOPICT=$(find . -iname "*${FILEEXT}" | wc -l)
[ $NOPICT -eq 0 ] && msg 3 "no matching files with extention $FILEEXT found - exiting"
find . -iname "*${FILEEXT}" | sort | while read FILE
do
echo -ne "reading EXIF-data from file $COUNT of $NOPICT ..\r"
COUNT=$(($COUNT+1))
echo "$FILE" >>${STATDIR}/temp/imgdatap.txt
LANGUAGE=C $EXIFTOOL -ExposureTime -Aperture -FocalLength -ISO -Lensid -Flash -MeteringMode -FocusMode -ShootingMode -Orientation "$FILE" >>${STATDIR}/temp/imgdatap.txt &
#process in batches
NPROC=$(($NPROC+1))
if [ "$NPROC" -ge ${MAXPROC} ]; then
wait
NPROC=0
fi
done
#wait for all processes to finish
wait
# save number of evaluated picture files
echo ${NOPICT} > ${STATDIR}/no_of_pict.txt
msg 1 "evaluating ..."
if [ "$EXPTIMEFMT" == "f" ]; then
# exposure time as fraction
grep "Exposure.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_exp.txt
else
# exposure times in decimal
grep "Exposure.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 | awk '{ split($1, a, "/"); if (a[2]==""){a[2] = 1} $1=sprintf("%8.5f",a[1]/a[2]); printf $1; printf"\n"}' > ${STATDIR}/temp/d_exp.txt
fi
#replace infinity aperture with 999 (unknown)
grep "Aperture.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 | sed s#inf#999#g > ${STATDIR}/temp/d_apr.txt
grep "Focal.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_focal.txt
grep "ISO.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_iso.txt
grep "Lens.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_lens.txt
grep "Flash.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_flash.txt
grep "Metering.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_meter.txt
grep "Shooting.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_shoot.txt
grep "Orientation.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_orientation.txt
grep "Focus.*:" ${STATDIR}/temp/imgdatap.txt | cut --delimiter=: -f2 > ${STATDIR}/temp/d_af.txt
cut ${STATDIR}/temp/d_exp.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/exposure_stats.txt
cut ${STATDIR}/temp/d_apr.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/apr_stats.txt
cut ${STATDIR}/temp/d_focal.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/focal_stats.txt
cut ${STATDIR}/temp/d_iso.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/iso_stats.txt
cut ${STATDIR}/temp/d_lens.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/lens_stats.txt
cut ${STATDIR}/temp/d_flash.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/flash_stats.txt
cut ${STATDIR}/temp/d_meter.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/lens_meter.txt
cut ${STATDIR}/temp/d_shoot.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/shoot_stats.txt
cut ${STATDIR}/temp/d_orientation.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/orientation_stats.txt
cut ${STATDIR}/temp/d_af.txt -f2 --delimiter=: | sort | uniq -c | sort -g -r > ${STATDIR}/af_stats.txt
fi # evaluate the picture files and create new data files ?
# directory with statistic data available ?
[ -d ${STATDIR} ] || msg 3 "directory $STATDIR does not exists, no statistical data available - exiting"
[ -d ${STATDIR}/temp ] || mkdir ${STATDIR}/temp
# draw some nice graphs ...
if [ "$DRAWTOOL" == "google" ]; then
msg 1 "plotting with google charts ..."
# write first part of url to all files
echo "http://chart.apis.google.com/chart?chs=700x425&chds=0," | tee ${STATDIR}/temp/exposure_url.txt | tee ${STATDIR}/temp/apr_url.txt | tee ${STATDIR}/temp/focal_url.txt | tee ${STATDIR}/temp/iso_url.txt | tee ${STATDIR}/temp/lens_url.txt | tee ${STATDIR}/temp/flash_url.txt | tee ${STATDIR}/temp/focus_url.txt | tee ${STATDIR}/temp/lens_meter_url.txt | tee ${STATDIR}/temp/af_url.txt | tee ${STATDIR}/temp/shoot_url.txt > ${STATDIR}/temp/orientation_url.txt
#exposure
drawhist_google "exposure_stats" "exposure_url"
#apr
drawhist_google "apr_stats" "apr_url"
#focal
drawhist_google "focal_stats" "focal_url"
#iso
drawpie_google "iso_stats" "iso_url"
#lens
drawpie_google "lens_stats" "lens_url"
#flash
drawpie_google "flash_stats" "flash_url"
#focus
drawpie_google "focus_stats" "focus_url"
#lens_meter
drawpie_google "lens_meter" "lens_meter_url"
#af
drawpie_google "af_stats" "af_url"
#shoot
drawpie_google "shoot_stats" "shoot_url"
#orientation
drawpie_google "orientation_stats" "orientation_url"
elif [ "$DRAWTOOL" == "gnuplot" ]; then
msg 1 "plotting with gnuplot ..."
i=0
while [ "${TITLE[$i]}" != "" ]; do
GRAPHTITLE=${TITLE[$i]##*:}
FILE=${TITLE[$i]%%:*}
msg 0 ">>>> $FILE: $GRAPHTITLE"
# quote label fields
cat "${STATDIR}/${FILE}.txt" | awk ' { xlabel=""; printf $1 "\t""\""; for (i=2;i<=NF;i++){ xlabel=xlabel$i" ";} print substr(xlabel,1,35) " [" $1 "]\"" }' > "${STATDIR}/temp/${FILE}.txt"
mv "${STATDIR}/temp/${FILE}.txt" "${STATDIR}/${FILE}.qtxt"
# draw graphs
drawgraph_gnuplot "${STATDIR}/${FILE}" "${GRAPHTITLE}"
i=$(($i+1))
done
else
msg 3 "implemented drawing tools are \"gnuplot (-p)\" or \"google (-g)\", found \"${DRAWTOOL}\" and do not know what to do with it, exiting"
fi
# making html index file
WDIR="$(pwd)"
[ $NOPICT -eq 0 ] && [ -r "${STATDIR}/no_of_pict.txt" ] && NOPICT=$(cat "${STATDIR}/no_of_pict.txt")
htmlclear "${INDEXFILE}"
htmlheader "Picture Statistics" "${INDEXFILE}"
htmlprint "<h1>Picture Statistics of ${WDIR}</h1>\n" "${INDEXFILE}"
htmlprint "<h3>out of ${NOPICT} raw files</h3>\n<BR>\n" "${INDEXFILE}"
i=0
while [ "${TITLE[$i]}" != "" ]; do
HEADER=${TITLE[$i]##*:}
FILE=${TITLE[$i]%%:*}
EXT="png" # default: use png extention
if [ "$DRAWTOOL" == "gnuplot" ]; then
# use svg graphs when created with gnuplot
EXT="svg"
fi
htmlprint "<h2>${HEADER}</h2>\n" "${INDEXFILE}"
htmlprint "<img src=\"${FILE}.${EXT}\" alt=\"${FILE}.${EXT}\"\n<BR>\n" "${INDEXFILE}"
i=$(($i+1))
done
# do the dishes
rm -r ${STATDIR}/temp
msg 1 "done!"
NOW=$(date +%s)
DIFF=$(($NOW - $BEGIN))
MINS=$(($DIFF / 60))
SECS=$(($DIFF % 60))
echo "Time elapsed: $MINS:`printf %02d $SECS`"