IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

PIL.Image - Attributs des images


Sujet :

Python

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2011
    Messages : 45
    Points : 57
    Points
    57
    Par défaut PIL.Image - Attributs des images
    Bonjour,

    Débutant sur Python, je vais peut-être poser une question dont la réponse est évidente, mais je me lance néanmoins.

    Je n'arrive pas à lire en totalité le contenu d'un attribut d'image nommé 'info'. Ci dessous la portion de code qui me pose problème:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    from PIL import Image
    image = Image.open(r"faucon.jpg")
    print(1,image.__dict__)     # {'im': None, 'mode': 'RGB', '_size': (5312, 2988), 'palette': None, 'info': {'exif': b'Exif\x00\x00II...,...},...}
    print(2,image.info)            # image.info = {'exif': b'Exif\x00\x00II*\x00\x08\x00\x00\x00\x0c\x00\x00\x01\x04\x00\x01\x00\x00\...',...}
    ma_var = image.info['exif'] # b'Exif\x00\x00II*\x00\x08\x00\x00\x00\x0c\x00\x00\x01\x04\x00\x01\x00\x00\...'
    print(3,type(ma_var))       # <class 'bytes'>
    Toutes mes tentatives pour "déchiffrer" ma_var, de la forme: ma_var.decode('utf-8'), ma_var.decode('windows-1252') ... aboutissent à une erreur de type:
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 24: invalid start byte
    Quelqu'un a-t-il un lien qui m'instruirait sur le sujet ou une idée qui me permettrait d'avancer sur ce point ?

    Merci d'avance.
    CAPLANDE

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Caplande Voir le message
    Toutes mes tentatives pour "déchiffrer" ma_var, de la forme: ma_var.decode('utf-8'), ma_var.decode('windows-1252') ... aboutissent à une erreur de type:


    Quelqu'un a-t-il un lien qui m'instruirait sur le sujet ou une idée qui me permettrait d'avancer sur ce point ?
    C'est en effet un point très important en Python que l'encoding.

    L'encoding c'est une table de traduction entre une suite de bits et la convention que représente cette suite. Dans une table une suite 1001001 voudra dire "a", dans une autre elle voudra dire "ñ".
    Une des tables les plus connues était la table iso-latin9 (nommée aussi "ascii") et depuis quelques années, la nouvelle "utf-8" a pris le relai.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    >>> c=bytes((0b01101100,))
    >>> c.decode("ascii")
    'l'
    >>> c.decode("cp1140")
    '%'

    Or Python est très très à cheval sur l'encoding (c'est d'ailleurs une très bonne chose, là ou d'autres langages te répondent n'importe quoi quitte à te pourrir ta bdd, si Python n'arrive pas à décoder dans la table donnée il renvoie une exception mais tu es au-moins assuré que s'il décode, tu obtiens alors des valeurs correctes).

    Un autre point de confusion est que le bytes est souvent confondu avec du str pour la simple et unique raison que Python, quand il l'affiche, il tente (si possible) de l'afficher sous forme de string (à mon avis ça a été une mauvaise décision de la part des concepteurs, l'afficher systématiquement au format hexa aurait évité cette confusion surtout que s'il ne peut pas l'afficher au format string il l'affiche alors en hexa). Et c'est tellement confondu que certains le nomment "byte-string". Or le byte ce n'est pas du string (dans le sens il n'est pas obligé de pouvoir être affiché). C'est simplement de l'octet brut, du binaire. Mais si tu tentes de convertir du binaire en string en lui indiquant que ça a été encodé en utf-8 et que ça ne l'est pas, tu arrives dans ce cas d'erreur.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    >>> c=bytes((0b10101001,))
    >>> c.decode("latin9")
    '©'
    >>> c.decode("utf-8")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa9 in position 0: invalid start byte

    Tu n'as pas le droit de demander bytes.decode(format) si tu ne sais pas au départ dans quel format a été encodé le byte. Il ne te viendrait jamais à l'idée de lire un livre allemand sans connaitre l'allemand ? Ben c'est pareil avec Python. Tu ne peux pas lui donner une table "au hasard" en espérant que ça tombera juste. Oui dans la majorité des cas ça tombe juste parce que dans la majorité des cas on est tous en utf-8 (format qui tend à devenir le format universel et qui, en plus, a repris la table ascii ce qui fait que l'ascii fonctionne aussi en utf-8) mais ce n'est pas parce que "souvent ça marche" qu'il faut y aller à l'aveugle.

  3. #3
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 894
    Points : 7 250
    Points
    7 250
    Par défaut
    Bonsoir,

    Pour lire et interpréter ces données correctement, vous aurez besoin d'une bibliothèque capable de traiter le format EXIF.

  4. #4
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 302
    Points : 6 782
    Points
    6 782
    Par défaut
    Salut,

    Essaye avec ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from PIL import Image
    from PIL.ExifTags import TAGS
     
    image = Image.open('wallpaper/DSCF0704.JPG')
    data = image.getexif()
    for datum in data:
        tag = TAGS.get(datum, datum)
        value = data.get(datum)
        # decode bytes 
        if isinstance(value, bytes):
            value = value.decode()
        print(f"{tag:20}: {value}")
    C'est très limité comme données:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    GPSInfo             : 1624
    PrintImageMatching  : PrintIM0250
    ResolutionUnit      : 2
    ExifOffset          : 376
    Make                : FUJIFILM
    Model               : FinePix S4800
    Software            : Digital Camera FinePix S4800 Ver1.00
    Orientation         : 1
    DateTime            : 2013:02:04 18:13:59
    YCbCrPositioning    : 2
    YResolution         : 72.0
    Copyright           : 2014 Vincent Vande Vyvre, all rights reserved.
    XResolution         : 72.0
    Artist              : Vincent Vande Vyvre
    Si tu as besoin de plus de détails, regarde du côté de python3exiv2 (dans ma signature).

  5. #5
    Membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2011
    Messages : 45
    Points : 57
    Points
    57
    Par défaut
    Merci à tous pour vos contributions. Je traduis vos réponses en disant qu'il n'est pas possible, si l'on ne connait pas l'encodage d'une séquence binaire, de la traduire en texte.
    J'ai beaucoup investigué en ligne pour obtenir ce résultat en pensant que la séquence a une signification littérale, en raison de son titre ('exif') et de la séquence de départ (b'Exif\x00\x00II*....) que j'ai essayé vainement de retrouver sur le Web. Mais, bon, pas de piste dans ce sens.
    J'ai eu recours aussi à ExifTags qui fonctionne parfaitement mais, m'étant lancé dans un comparatif des modes d'extraction des métadonnées d'une image j'avais orienté ma curiosité vers l'attribut 'info' de l'image pour éventuellement découvrir qu'il fournissait le même nombre de métadonnées que ExifTags.
    Merci encore.

    CAPLANDE

  6. #6
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 894
    Points : 7 250
    Points
    7 250
    Par défaut
    Tu as essayé une autre bibliothèque comme je te le conseille ? Par exemple piexif dans le paragraphe With PIL (Pillow)

    Tu as cet exemple,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from PIL import Image
    import piexif
     
    im = Image.open(filename)
    exif_dict = piexif.load(im.info["exif"])
    # process im and exif_dict...
    w, h = im.size
    exif_dict["0th"][piexif.ImageIFD.XResolution] = (w, 1)
    exif_dict["0th"][piexif.ImageIFD.YResolution] = (h, 1)
    exif_bytes = piexif.dump(exif_dict)
    im.save(new_file, "jpeg", exif=exif_bytes)

  7. #7
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 478
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 478
    Points : 9 278
    Points
    9 278
    Billets dans le blog
    6
    Par défaut
    Bonjour

    Il y a aussi "exiftool" qui, pour moi, est le plus complet (et de loin), non seulement pour les photos jpg, mais aussi pour beaucoup d'autres formats:
    https://exiftool.org/

    J'ai donné quelques infos sur le sujet ici:
    https://www.developpez.net/forums/d1...mage-exiftool/

    Depuis, j'ai découvert un module externe Python qui facilite l'utilisation de l'exécutable: pyexiftool:
    https://pypi.org/project/PyExifTool/

    Voilà un exemple de code qui utilise pyexiftool:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    # -*- coding: utf-8 -*-
     
    from exiftool import ExifTool, ExifToolHelper # à importer PyExifTool
    prog = r"" # donne l'adresse de l'exécutable exiftool.exe
    ExifTool(prog, encoding="utf8") # donne l'exécutable et l'encodage utilisé
     
    ##############################################################################
    def cherchexiftool(fichier):
        """Trouve toutes les clefs-valeurs de l'exif d'une image.
           Retourne un dictionnaire => clef:valeur
           Si pas d'exif, retourne un drapeau False avec le dictionnaire
           Utilise le module externe PyExifTool (avec l'exécutable exiftool.exe)
        """
        with ExifToolHelper() as et:
            for dico in et.get_metadata(fichier):
                dico["SourceFile"] = fichier # correction pour pb d'encodage
                if "EXIF:DateTimeOriginal" in dico:
                    return dico, True # exif trouvé
                else:
                    return dico, False # pas d'exif mais des infos sur le fichier
     
    ##############################################################################
    if __name__ == "__main__":
     
        fichier = r"chemin\vers\ma\photo.jpg
     
        dico, ok = cherchexiftool(fichier)
     
        for k, v in dico.items():
            print(f"{k} = {v}")
        if not ok:
            print()
            print("Exifs non trouvés")
    En fait, au lieu de parler d'exif, il vaudrait mieux parler de "métadatas", puisque même en cas d'absence d'exif, on peut encore trouver des infos sur le fichier.

  8. #8
    Membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2011
    Messages
    45
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mars 2011
    Messages : 45
    Points : 57
    Points
    57
    Par défaut
    Ma question est la suivante: je cherche à exploiter la méthode __dict__ de l'image créée à partir de PIL (voir ci-dessous)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    from PIL import Image
    image = Image.open(faucon.jpg)
    att = image.__dict__ # C'est un dictionnaire
    print(att)
    Qui retourne: voir fichier joint


    Je m'intéresse alors à la clé 'info' de att. info est lui-même un dictionnaire dont la clé 'exif' semble répondre à ma recherche de métadonnées exif.
    C'est sur la lecture de cette clef du dictionnaire 'info' que je bute.
    Mon but n'est pas de trouver une méthode qui retourne des métadonnées de l'image étudiée, il y en a, en effet une multitude, mais de répondre à l'interrogation que je pose ci-dessus.
    Fichiers attachés Fichiers attachés

  9. #9
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Caplande Voir le message
    Qui retourne: voir fichier joint
    Déjà concernant le résultat, une image dans le forum est plus adéquate qu'un fichier à télécharger sur son ordinateur.
    Et pour ta question, fred1599 a déjà donné la réponse !!!
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import piexif
    exif_dict = piexif.load(att["info"]["exif"])
    print(exif_dict)

    Et sûrement que le PyExifTool montré par tyrtamos peut aussi faire le job...

    Citation Envoyé par tyrtamos Voir le message
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for dico in et.get_metadata(fichier):
    	dico["SourceFile"] = fichier # correction pour pb d'encodage
    	if "EXIF:DateTimeOriginal" in dico:
    		return dico, True # exif trouvé
    	else:
    		return dico, False # pas d'exif mais des infos sur le fichier
    Je me trompe ou la boucle ne sert à rien
    Erreur de tabulation (il s'agirait d'un ''else de for" et non d'un "else de if") ???

Discussions similaires

  1. [Python 3.X] Problème sous PIL pour configurer des images pour Tkinter
    Par VMO_81 dans le forum Tkinter
    Réponses: 2
    Dernier message: 03/04/2020, 23h51
  2. [Python 3.X] PIL images côte à côte
    Par -feather dans le forum Calcul scientifique
    Réponses: 1
    Dernier message: 03/03/2016, 09h08
  3. MCD a MLD et les attributs des relations
    Par anis_el_madani dans le forum Schéma
    Réponses: 1
    Dernier message: 16/07/2007, 14h45
  4. Attribution des cartes réseau depuis passage a Etch
    Par himself dans le forum Debian
    Réponses: 1
    Dernier message: 12/06/2007, 10h41
  5. attribution des vlan à des adresses sous rseaux
    Par meriem_en dans le forum Développement
    Réponses: 1
    Dernier message: 27/06/2006, 15h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo