dimanche 26 janvier 2020

Photos

Pense-bête pour l'utilisation de exiv2, Image magick et d'autres manipulations de photos

Affichage d'une image

Si on veut afficher une image en grandeur réelle à partir de la ligne de commande:

$ display img095.jpg

Notes : Si le fichier image n'est pas dans le répertoire courant, indiquer le chemin. Pour plus d'informations voir le man de display.

Obtenir les métadonnées d'une image

Avec Exiv2

$ exiv2 img.jpg 
Nom du fichier  : img.jpg
Taille du fichier: 1752151 Octets
Type MIME       : image/jpeg
Taille de l'image: 1944 x 2592
Marque de l'appareil: WIKO
Modèle de l'appareil: Sunny3
Horodatage de l'image: 2020:01:24 16:31:18
Numéro de l'image: 
Temps d'exposition: 1/491 s
Ouverture       : F2.2
Correction d'exposition: 
Flash           : Pas de flash
Biais flash     : 
Distance focale : 2.3 mm
Distance du sujet: 
Sensibilité ISO : 50
Mode d'exposition: 
Mode de mesure  : 
Mode macro      : 
Qualité de l'image: 
Résolution Exif : 1944 x 2592
Balance des blancs: Automatique
Miniature       : image/jpeg, 8628 Octets
Droit d'auteur  : Copyright,Spreadtrum,2011
Commentaire Exif: Test un commentaire exiv2

Si on ne veut que DateTimeOriginal on peut utiliser l'option -g (grep)

$ exiv2 -g DateTimeOriginal img.jpg 
Exif.Photo.DateTimeOriginal                  Ascii      20  2020:01:24 16:31:18

Pour plus d'options voir le man de exiv2se dans l'article Album photos. Il permet d'extraire d'une photo l'une des métadonnées : le commentaire, la date de prise de la photo ou l'heure. C'est parce que exiv2 ou image magick ne me donnaient pas ces données sous une forme simple.

g++ getexif.cc -o getexif -lexiv2

source: https://www.exiv2.org/doc/exifvalue_8cpp-example.html

Usage : getexif d|t|c file

Avec Image magick

Pour obtenir la date de prise d'une photo (Exif DateTimeOriginal) :

$ DT=identify -format %[Exif:DateTimeOriginal] img095.jpg
$ echo $DT

Note : Pour obtenir les données exif possibles :

$ identify -format '%[EXIF:*]' img095.jpg
exif:ApertureValue=11/5
exif:Artist=Artist-freed
exif:BrightnessValue=0/0
exif:ColorSpace=1
exif:ComponentsConfiguration=1, 2, 3, 0
exif:Contrast=0
exif:Copyright=Copyright,Spreadtrum,2011
exif:DateTime=2020:01:24 16:20:30
exif:DateTimeDigitized=2020:01:24 16:20:30
exif:DateTimeOriginal=2020:01:24 16:20:30
...

source : stackoverflow

Numéroter des photos en fonction de la date

Avec exiv2

$ exiv2 -r'%Y:%m:%d_%H:%m:%S' rename img.jpg 
$ ls
2020:01:24_16:01:18.jpg

Avec image magick

On suppose qu'on a un certain nombre de fichiers de photos, par exemple :

$ ls Camera
IMG_20191108_203655.JPG  IMG_20200116_215146.JPG  IMG_20200124_161610.JPG
IMG_20200116_215133.JPG  IMG_20200124_161605.JPG  IMG_20200124_161615.JPG

On suppose que les noms correspondent aux dates de prise des photos, et on veut les renommer dans cet ordre 1.jpg 2.jpg ... 6.jpg.

$ ls *.JPG | cat -n | while read n f; do cp "$f" "$n.jpg"; done
$ ls
1.jpg  4.jpg  IMG_20191108_203655.JPG  IMG_20200124_161605.JPG
2.jpg  5.jpg  IMG_20200116_215133.JPG  IMG_20200124_161610.JPG
3.jpg  6.jpg  IMG_20200116_215146.JPG  IMG_20200124_161615.JPG

Source: stackoverflow. Aller à la deuxième réponse.

Admettons qu'on ait des doutes sur la fiablilté des noms d'origine. Par exemple on n'est pas sûr que l'appareil photo était mis à l'heure. C'est là qu'intervient Image Magick. Nous allons renommer d'abord ces fichiers avec la date de prise de la photo. (Cf. paragraphe précédent.)

On fait alors :

$ for f in *.JPG;
> do cp "$f" "identify -format %[Exif:DateTimeOriginal] $f".jpg;
> done
$ ls
'2019:11:08 20:36:56.jpg'  '2020:01:24 16:16:10.jpg'   IMG_20200116_215146.JPG
'2020:01:16 21:51:34.jpg'  '2020:01:24 16:16:15.jpg'   IMG_20200124_161605.JPG
'2020:01:16 21:51:47.jpg'   IMG_20191108_203655.JPG    IMG_20200124_161610.JPG
'2020:01:24 16:16:06.jpg'   IMG_20200116_215133.JPG    IMG_20200124_161615.JPG

Puis on procède comme ci-dessus en remplaçant cp par mv :

$ ls *.jpg | cat -n | while read n f; do mv "$f" $n.jpg; done
$ ls
1.jpg  4.jpg  IMG_20191108_203655.JPG  IMG_20200124_161605.JPG
2.jpg  5.jpg  IMG_20200116_215133.JPG  IMG_20200124_161610.JPG
3.jpg  6.jpg  IMG_20200116_215146.JPG  IMG_20200124_161615.JPG

Remarque : Il est impératif ici de protéger la variable $f (après la commande mv) par des guillemets, car elle contient un espace. Idem pour l'utilisation de identify ci-dessus.

Rapatrier des photos depuis un mobile android

Connecter le mobile par un cable usb.

D'abord on fait reconnaître le mobile par adb:

$ adb devices
List of devices attached
JADF1930008446	device

Ensuite, on exploite le shell et sa complétion par Tab pour retrouver où sont stockées les photos. Je ne me le rappelle pas toujours, sauf que le chemin commence par storage

$ adb shell # pour trouver le chemin où il stocke les photos
MOBILE: $ ls storage/sdcard0/DCIM/
Camera
MOBILE:/ $ exit

Et enfin on peut les rapatrier.

$ adb pull storage/sdcard0/DCIM/Camera/

Voilà j'ai six photos, avec des noms à rallonge.

Je veux les renommer avec la date et l'heure de prise des photos.

$ for f in *.jpg;
> do cp "$f" "identify -format %[Exif:DateTimeOriginal] $f".img;
> done
 
$ ls
'2019:11:08 20:36:56.img'  '2020:01:24 16:16:10.img'   IMG_20200116_215146.jpg
'2020:01:16 21:51:34.img'  '2020:01:24 16:16:15.img'   IMG_20200124_161605.jpg
'2020:01:16 21:51:47.img'   IMG_20191108_203655.jpg    IMG_20200124_161610.jpg
'2020:01:24 16:16:06.img'   IMG_20200116_215133.jpg    IMG_20200124_161615.jpg

Maintenant on peut les renommer avec :

ls *.img | cat -n | while read n f; do mv "$f" "$n.img"; done

ou si on veut commencer à 13

ls *.img | cat -n | while read n f; do mv "$f" "$(($n + 13))".img; done

Notes :

J'ai pris l'extension .img pour distinguer les nouveaux fichiers des originaux.

Le passage par Exif n'est utile que si les noms des fichiers d'origine ne sont pas triés par date de façon certaine.

Exiv2 est aussi une librairie C++

Voici un exemple de programme getexif que j'utilise dans l'article Album photos. Il permet d'extraire d'une photo l'une des métadonnées : le commentaire, la date de prise de la photo ou l'heure. C'est parce que exiv2 ou image magick ne me donnaient pas ces données sous une forme simple.

/* 
g++ getexif.cc -o getexif -lexiv2
source: https://www.exiv2.org/doc/exifvalue_8cpp-example.html
 
Usage : getexif d|t|c file
Output on standard outpout date, time, or comment
getexif d file : outpout date (first part of DateTimeOriginal)
getexif t file : output time (second part)
getexif c file : output jpg comment
*/
 
#include <exiv2/exiv2.hpp>
#include <iostream>
#include <iomanip>
#include <cassert>
#include <string>
 
using namespace std;
 
string exifvalue(const char* key, const char* file)
{
   string output("");
   Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file);
   assert(image.get() != 0);
   image->readMetadata();
   Exiv2::ExifData &exifData = image->exifData();
   if ( exifData.empty()) {
      std::cerr << "no metadata found in file " << file << std::endl;
      exit(2);
   }
   try {
      output = exifData[key].toString();
   } catch (Exiv2::AnyError& e) {
      std::cerr << "Caught Exiv2 exception '" << e << "'" << std::endl;
      exit(3);
   } catch ( ... ) {
      std::cerr << "Caught a cold!" << std::endl;
      exit(4);
   }
   return output;
}
 
int main(int argc, char* const argv[])
{
   string output("");
   bool c = argc == 3 && strcmp(argv[1], "c") == 0;
   bool d = argc == 3 && strcmp(argv[1], "d") == 0;
   bool t = argc == 3 && strcmp(argv[1], "t") == 0;
   const char* file = argv[2]; 
   if(!c && !d && !t ) {
      std::cerr << "Usage: " << argv[0] << " c|d|t file\n";
      std::cerr << "   c: exif comment and not JPEG comment\n";
      std::cerr << "   d: date, first part of DateTimeOriginal\n"; 
      std::cerr << "   t: time, second part\n";
      std::cout << endl;
      return 1;
   } else if(c) {
      string comment = exifvalue("Exif.Photo.UserComment", file);
      cout << comment.substr(comment.find(' ') + 1) << endl;
      return 0;
   }
   else if( d || t) {
      string datetime = exifvalue("Exif.Photo.DateTimeOriginal", file);
      if(d) cout << datetime.substr(0, datetime.find(' ')) << endl;
      if(t) cout << datetime.substr(datetime.find(' ') + 1) << endl;
      return 0;
   }
   return 1;
}

Source : https://www.exiv2.org/doc/exifvalue_8cpp-example.html




Réalisé avec Qlam - LGPL