Une image JPEG issue de mon appareil photo numérique (Nikon Coolpix E995) contient les données suivantes :

  • les données graphique de l'image principale (2048x1536 en compression FINE) ;
  • les métadonnées EXIF ;
  • l'image de prévisualisation (PreviewImage) au format 320x240, pour l'affichage sur l'écran de l'APN : c'est un fichier JPEG complet embarqué ;
  • l'image de prévisualisation (ThumbnailImage) au format 160x120, pour l'affichage dans les logiviles de classement, dans Nautilus ou l'Explorateur Windows.

jpegtran sait faire la rotation de l'image principale sans perte (c'est à dire, pas de décompression/compression) en préservant les données EXIF, mais il copie les imagettes telles quelles, sans les tourner. exiftran tourne bien l'image principale et la ThumbnailImage mais il corrompt (d'après exiftool) les MarkerNotes et la PreviewImage.

exiftool, un outil très complet de modification des données EXIF, dispose d'une fonctionnalité permettant d'extraire les imagettes, et plus tard de les remplacer. Cette fonction est également utile pour vérifier que la rotation de l'imagette a bien été effectuée.

Exemple :

$ exiftool -b -ThumbnailImage DSCN4821.JPG | exiftool -
ExifTool Version Number         : 6.90
File Type                       : JPEG
MIME Type                       : image/jpeg
Image Width                     : 160
Image Height                    : 120
Image Size                      : 160x120
$ exiftool -b -PreviewImage DSCN4821.JPG | exiftool -
ExifTool Version Number         : 6.90
File Type                       : JPEG
MIME Type                       : image/jpeg
Image Width                     : 320
Image Height                    : 240
Image Size                      : 320x240

J'ai donc combiné jpegtran et exiftool en appliquant jpegtran à l'image principale puis aux imagettes. Le fichier est converti en place (l'original est écrasé) et la date de création du fichier est définie comme la date de prise de vue extraite des informations EXIF. J'en ai aussi profité pour appliquer l'option -optimize de jpegtran pour gagner au passage quelques kilo-octets.

Voici le code :

#!/bin/bash

# http://o.mengue.free.fr/


function _jpegrot
{
        typeset angle="$1"
        typeset f="$2"
        [[ "x$2" = *.[jJ][pP]*[gG] ]] || return 0
        typeset b=$(expr "x$f" : 'x\(.*\)\....$')
        typeset new="$b.tmp.JPG"
        typeset prv="$b.prv.JPG"
        typeset thb="$b.thb.JPG"
        exiftool -b -PreviewImage -w ".prv.JPG" -execute -b -ThumbnailImage -w ".thb.JPG" -common_args "$f"
        jpegtran -rotate "$angle" -optimize -perfect -copy all "$f" > "$new"
        mv -f -- "$new" "$f"
        jpegtran -rotate "$angle" -optimize -perfect -copy all "$prv" | exiftool -overwrite_original "$f" '-PreviewImage<=-' > /dev/null
        jpegtran -rotate "$angle" -optimize -perfect -copy all "$thb" | exiftool -overwrite_original "$f" '-ThumbnailImage<=-' '-DateTimeOriginal>FileModifyDate' > /dev/null
        rm -f -- "$prv" "$thb"
}

typeset angle="$1"
shift
for f in "$@"
do
        _jpegrot "$angle" "$f"
done

Exemple d'utilisation :

$ jpegrot 90 DSCN4821.JPG