Trouver les "exifs" des fichiers image avec exiftool
Bonjour,
Je rappelle que les fichiers "jpg" (et beaucoup d'autres!) ont souvent des informations supplémentaires, appelées "exifs", en plus de l'image elle-même, comme celles sur la prise de vue ou sur le réglage de l'appareil photo utilisé.
Comme je fais des photos depuis longtemps, je voulais trouver les informations de type "exif" de mes fichiers jpg. J'ai essayé pas mal de solutions avec Python (voir dans pypi), mais la solution la plus puissante que j'ai trouvée est l'exécutable "exiftool" de Phil Harvey: https://www.sno.phy.queensu.ca/~phil/exiftool/.
C'est un exécutable prévu pour la console (donc sans Python), et il est multiplateforme. Il reconnait de très nombreux formats de fichiers, et il permet le plus souvent la lecture / écriture / création d'exifs.
Je ne me suis intéressé qu'à la version pour Windows (=> exiftool.exe). L'exécutable n'a pas besoin d'être installé: il suffit de désarchiver le zip.
Et comme je voulais l'utiliser à partir de Python, je donne ici le code que j'utilise. L'avantage d'utiliser Python, c'est qu'on peut chercher parmi toutes les photos qu'on a (env. 15.000 chez moi), celles qui correspondent à un critère donné (ex: objectif utilisé), ou même à faire des statistiques (ex: % des photos par marque d'appareils photo utilisés). Et pour que ce soit plus pratique à utiliser, rien n'empêche d'intégrer cette recherche dans un programme graphique.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #!/usr/bin/python3
# -*- coding: utf-8 -*-
# Python 3.7
import os
from collections import OrderedDict
from subprocess import Popen, PIPE, STDOUT
##############################################################################
class Cherchexif:
"""Trouve l'exif d'un fichier image par appel de l'exécutable "exiftool"
Retourne un dictionnaire ordonné => cle:valeur
Si erreur (pas d'exif, ...), retourne un dictionnaire vide
"""
#=========================================================================
def __init__(self, progexec="exiftool.exe", codout="cp850", codefic="UTF8"):
self.progexec = progexec # adresse de l'exécutable à appeler
self.codout = codout # encodage des sorties console de exiftool
self.codefic = codefic # encodage des noms de fichier de l'OS
#=========================================================================
def __call__(self, fichier):
lignes = []
if os.path.exists(fichier):
options = ["-charset", "filename={}".format(self.codefic)]
commande = [self.progexec] + options + [fichier]
with Popen(args=commande, stdout=PIPE, stderr=STDOUT) as process:
while process.poll() is None:
ligne = str(process.stdout.readline(), self.codout).strip()
if ligne!="":
cle, val = ligne.split(sep=':', maxsplit=1)
cle = cle.rstrip(" \t\n\r\x00")
val = val.rstrip(" \t\n\r\x00")
lignes.append([cle, val])
if process.poll()!=0: # => fichier sans exif
lignes = [] # retournera un dictionnaire vide
dicoexif = OrderedDict(lignes) # convertit en dictionnaire ordonné
return dicoexif |
Utilisation pour trouver les exifs d'un fichier:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
if __name__ == "__main__":
# adresse de l'exécutable à appeler
progexec = r"chemin\vers\exiftool.exe"
# adresse du fichier dont on cherche les infos "exif"
fichier = r"chemin\vers\le\fichier\maphoto.jpg"
# recherche des infos "exif"
cherchexif = Cherchexif(progexec)
dicoexif = cherchexif(fichier)
# affichage du résultat
if dicoexif:
for cle in dicoexif:
print(cle, "===>", dicoexif[cle])
else:
print("Pas d'exif ou fichier non trouvé") # retour d'un dict. vide |
On trouve de très nombreux résultats, y compris les informations spécifiques à la marque et à l'appareil photo, comme l'objectif utilisé, ou comme le nombre de déclenchements faits sur cet appareil ("shutter count").
Je ne suis pas allé plus loin avec exiftool, mais en lisant sa doc, on voit qu'il y a vraiment beaucoup de possibilités. Par exemple, quand on veut supprimer les exifs d'une photo avant de la publier sur le web, on peut faire en console:
Code:
chemin\vers\exiftool.exe -all= chemin\vers\maphoto.jpg
Il ne restera alors comme exif que les quelques infos de base comme les dates du fichier et les dimensions de la photo.
Bon amusement!
problème avec la ligne "ligne = str(process.stdout.readline(), self.codout).strip()"
Bonjour,
Je ne connais pas du tout la manipulation d'un sous processus en python.
J'ai utilisé votre code pour extraire les données exif d'une photo jpeg prise avec un pentax K1.
J'ai le message suivant au niveau de la ligne ligne = str(process.stdout.readline(), self.codout).strip() :
Code:
1 2 3 4 5 6
| Traceback (most recent call last):
File "D:\Patrice\Python\Exif photos\ChercheExif.py", line 54, in <module>
dicoexif = cherchexif(fichier)
File "D:\Patrice\Python\Exif photos\ChercheExif.py", line 30, in __call__
ligne = str(process.stdout.readlines(), self.codout).strip()
TypeError: decoding to str: need a bytes-like object, list found |
La variable ligne n'est pas vide, elle comporte à l'écran de l'idle plus de 500 lignes avec les données que je recherche, la moitié possédant des ":", l'autre moitié des "===>"
Merci de m'aider à résoudre le problème?