#! /bin/bash 

#######################
##     photoman      ##
## interface à exiv2 ##
## et à gpscorrelate ##
#######################


declare -i nbRep=0
declare -i nbPhotos=0
declare -A DateTab

# chemin du répertoire photo
photoRep="/media/NAS/Public/Photos/"
# chemin du GPS
GPS="/run/media/vincent/GARMIN/Garmin/GPX"

IFS=$'\n'
shopt -s nullglob

# détection du GPS
if [ -d $GPS ]; then
    find $GPS -iname "*.gpx" > /tmp/tracesGPS
    if [ $(wc -l /tmp/tracesGPS | cut -d " " -f 1) != 0 ]; then        
        echo
        read -n 1 -s -p "un ou plusieurs fichiers gpx ont été trouvé dans le GPS. Les copier dans le(s) répertoire(s) photos [O/n] ? " copieTrace
        copieTrace="${copieTrace:=o}"
        case $copieTrace in
            o|O|y|Y ) Geolocalisation=true;;
            * ) Geolocalisation=false;;
        esac
    fi
else
    read -n 1 -s -p "Le GPS n'a pas été détecté : continuer quand même [o/N] ? " question
    question="${question:=n}"
    case $question in
            o|O|y|Y ) Geolocalisation=false ;;
            * ) exit;;
    esac
fi
echo

#traitement des photos
for fichier in *
do
    if [ ! -f $fichier ]; then continue; fi
    MimeType=$(file --mime-type $fichier)
    if [[ ${MimeType:(-10)} != "image/jpeg" ]]; then continue; fi
    datePhoto=$(exiv2 -g Exif.Photo.DateTimeOriginal $fichier | sed -r 's/^ *//;s/ {1,}/ /g'| cut -d " " -f 4 | sed 's/://g')
    repertoire=$photoRep${datePhoto:0:4}"/"
    if [ -z ${DateTab[$datePhoto]} ]; then 
        echo
        read -p "Veuillez indiquer une localisation correspondant à la journée du $datePhoto puis appuyez sur [Entrée] : " localisation
        echo
        DateTab[$datePhoto]="_"$(echo $localisation | sed 's/ /-/g')
        mkdir $repertoire$datePhoto${DateTab[$datePhoto]} 2> /dev/null
        ((nbRep++))
        # copier les fichiers gpx        
        if $Geolocalisation; then
            while read line  
                do   
                cp $line $repertoire$datePhoto${DateTab[$datePhoto]}
            done < /tmp/tracesGPS
        fi
    fi 
    fichierRenomme=$repertoire$datePhoto${DateTab[$datePhoto]}"/"$(echo $fichier | sed 's/ /-/g')
    cp $fichier $fichierRenomme
    ((nbPhotos++))
    exiv2 "-r%Y%m%d_%H%M%S"${DateTab[$datePhoto]}"_:basename:" mv $fichierRenomme
done

#Bilan
if [ $nbPhotos -eq 0 ]; then 
    echo
    echo "Il n'y a aucune photo à transférer dans ce répertoire"
    echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++"
    echo
    exit
fi
echo "$nbPhotos photos ont été transférées dans $nbRep répertoire(s)."
printf '\033[7m'
read -n 1 -s -p "===> Supprimer toutes les photos dans le répertoire d'origine [o/N] ? " question
question="${question:=n}"
printf '\033[0m'echo
case $question in
        o|O|y|Y ) rm -rf *.[jJ][pP][gG] ;;
        * ) : ;;
esac

#Géolocalisation
if ! $Geolocalisation; then exit; fi
read -n 1 -s -p "Géolocaliser les photos transférées [O/n] ? " question
question="${question:=o}"
case $question in
        o|O|y|Y ) : ;;
        * ) exit;;
esac
for i in "${!DateTab[@]}"
    do 
    cd $photoRep${i:0:4}"/"$i${DateTab[$i]}
    for f in "*.[gG][pP][xX]"
        do
        gpxFileDate=$(xml_grep 'trkpt' $f --nb_results 1 | xml_grep 'time' --text_only)
        UTCHour=$(date -d $(echo $gpxFileDate | sed "s/T/ /g" | sed "s/Z//g") +%k | sed "s/ //g")
        LocalHour=$(date -d $gpxFileDate +%k)
        TimeZone=$(( $LocalHour  - $UTCHour ))
        gpscorrelate -g $f -z $TimeZone *.[jJ][pP][gG]
    done
done

Quelques explications :

Les premières lignes servent de fichier ini : emplacement du répertoire photo et point de montage du GPS

Ensuite je détecte si le GPS est connecté et je vérifie (find -iname *.gpx) et s'il y a une (ou plusieurs) traces. On y reviendra plus tard

Puis pour chaque fichier du répertoire en cours
  • je teste s'il est de type image jpg,
  • j'extrais la date de prise de vue grace à exiv2
  • s'il n'existe pas je crée un répertoire correspondant à cette date (localisation demandée), j'y copie les éventuelles traces du GPS et j'incrémente un compteur (les noms des répertoires sont stockés dans un tableau associatif date => _localisation )
  • J'y copie le fichier photo, le renomme (aaaammjj_hhmmss_localisation_nomOririnel.JPG) et incrémenter un compteur
Une fois le transfert terminé je vide éventuellement le répertoire d'origine et je commence la géolocalisation proprement dite. Une seule difficulté, déterminer automatiquement la zone horaire qui s'applique ce jour (en supposant que l'APN est correctement réglé à l'heure locale).

Les trace gpx sont des fichiers XML. On peut évidement les exploiter à la hussarde à grand coup de sed ou de awk, mais un bon parseur vous facilitera la tache. J'utilise ici xml_grep fourni par le paquet perl-xml-twig (Archlinux) ou xml-twig-tools (Debian/Ubuntu). Il me permet ici d'extraire l'horodatage (UTC) du premier trackpoint, que j'exprime en heure locale pour calculer la différence.

J'appelle enfin gpscorrelate pour chaque fichier gpx, avec le décalage horaire calculé, et je l'applique à toutes les photos. En principe une photo n'est concernée que par une seule trace mais s'il arrivait que le fichier JPG contienne déjà des données exif gps elles ne seraient pas écrasées et un message d'erreur serait affiché.

Naturellement ce script ne répond précisément qu'à mes besoins personnels et probablement pas aux vôtres mais il démontre, je l'espère, qu'il n'est pas si difficile de réaliser soi-même l'application correspondant à ses desiderata.