Lire le tag EXIF de rotation d'image JPG

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Pour faire suite à SaveImage creer une rotation
https://www.purebasic.fr/french/viewtop ... 46#p200946

Voici une bafouille pour lire le Tag d'orientation d'une image JPG dans les EXIFs.
Prenez quelques photos en mode vertical et horizontal avec un APN ou un téléphone et testez.

Oui, une lib existe sur le forum us, mais j'aime bien réinventer le roue (pour comprendre) et surtout ne pas charger des centaines de lignes là où une dizaine suffit.

Commentaires et liens dans le sources pour ceux que ça intéresse.
Optimisation bienvenue.

Code : Tout sélectionner

; Lire le Tag EXIF concernant l'orientation d'une image
; Marc56 - 15/08/18

; Tag ID	Tag Name 	    Writable	Group	
; 0x0112 	Orientation 	int16u 	    IFD0 	
; DEC 274

; Values / Notes
; 1 = Horizontal (normal)
; 2 = Mirror horizontal
; 3 = Rotate 180
; 4 = Mirror vertical
; 5 = Mirror horizontal And rotate 270 CW
; 6 = Rotate 90 CW
; 7 = Mirror horizontal And rotate 90 CW
; 8 = Rotate 270 CW

; Ressources:
; https://fr.wikipedia.org/wiki/Exchangeable_image_file_format
; http://owl.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
; Editeur Hexa https://mh-nexus.de/en/ ou http://frhed.sourceforge.net/

Declare Search_Orientation(Fichier$)

; Test
; Utiliser une photo prise à la verticale et une à l'horizontale
; Vérifier avant dans un viewer (ie: irfanview) que le tag orientation est rempli
; On devrait normalement trouver 
; 1 pour une photo normale (horizontale)
; 6 ou 8 pour une photo prise à la verticale
Search_Orientation("C:\DataTest\EXIF_V6.JPG")
Search_Orientation("C:\DataTest\EXIF_H.JPG")
Search_Orientation("C:\DataTest\EXIF_V8.JPG")

; --- Procédures
Procedure Search_Orientation(Fichier$)
    Debug "Fichier: " + Fichier$
    If Not ReadFile(0, Fichier$, #PB_Unicode) 
        Debug "Fichier illisible"
        ProcedureReturn 
    EndIf
    length = Lof(0) 
    Debug "Taille : " + FormatNumber(length, 0) + " octets"
    For i = 0 To length          
        FileSeek(0, i)  
        If ReadUnicodeCharacter(0) = $0112 ; ou 274 den décimal
            Debug "Offset : " + i
            FileSeek(0, 6, #PB_Relative)
            ID = ReadCharacter(0)
            Debug "Valeur : " + ID
            Select ID
                Case 1 : Debug "Image Horizontale"
                Case 6 : Debug "Image à tourner vers Gauche"
                Case 8 : Debug "Image à tourner vers Droite"
            EndSelect
            Break 
        EndIf
    Next 
    CloseFile(0)
    Debug ""
EndProcedure
Résultat

Code : Tout sélectionner

Fichier: C:\DataTest\EXIF_V6.JPG
Taille : 6,818,304 octets
Offset : 46
Valeur : 6
Image à tourner vers Gauche

Fichier: C:\DataTest\EXIF_H.JPG
Taille : 2,832,384 octets
Offset : 46
Valeur : 1
Image Horizontale

Fichier: C:\DataTest\EXIF_V8.JPG
Taille : 3,677,696 octets
Offset : 46
Valeur : 8
Image à tourner vers Droite
PS. Je n'ai pas compris pourquoi j'ai dû faire un FileSeek de 6 positions pour trouver la bonne valeur ? j'ai dû faire par approche.
Logiquement 1 position aurait suffit.

Peut-être que je m’embête aussi à scanner tout le fichier alors que l'offset est le même (46) :oops:
À voir sur d'autres exemples, selon la version d'EXIF générée par l'APN...

:wink:
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Si on considère que l'info de rotation est toujours à l'offset 54, on peut simplifier

Code : Tout sélectionner

; Lire le Tag EXIF concernant l'orientation d'une image
; Read_Exif_Lite.pb
; Marc56 - 15/08/18

;{ Informations
; Tag ID	Tag Name 	    Writable	Group	
; 0x0112 	Orientation 	int16u 	    IFD0 	
; DEC 274

; Values / Notes
; 1 = Horizontal (normal)
; 2 = Mirror horizontal
; 3 = Rotate 180
; 4 = Mirror vertical
; 5 = Mirror horizontal And rotate 270 CW
; 6 = Rotate 90 CW
; 7 = Mirror horizontal And rotate 90 CW
; 8 = Rotate 270 CW

; Ressources:
; https://fr.wikipedia.org/wiki/Exchangeable_image_file_format
; http://owl.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
; Editeur Hexa https://mh-nexus.de/en/ ou http://frhed.sourceforge.net/
;}

Declare Search_Orientation(Fichier$)

Search_Orientation("C:\DataTest\EXIF_V6.JPG")
Search_Orientation("C:\DataTest\EXIF_H.JPG")
Search_Orientation("C:\DataTest\EXIF_V8.JPG")

; --- Procédures
Procedure Search_Orientation(Fichier$)
    Debug "Fichier: " + Fichier$
    If Not ReadFile(0, Fichier$, #PB_Unicode) 
        Debug "Fichier illisible"
        ProcedureReturn 
    EndIf
    
    Debug "Taille : " + FormatNumber(Lof(0), 0) + " octets"
    
    FileSeek(0, 54)
    ID = ReadCharacter(0)
    Select ID
        Case 1 : Debug "ID     : " + ID + " -> Image Horizontale"
        Case 6 : Debug "ID     : " + ID + " -> Image à tourner vers Gauche"
        Case 8 : Debug "ID     : " + ID + " -> Image à tourner vers Droite"
    EndSelect
    
    CloseFile(0)
    Debug ""
EndProcedure

Code : Tout sélectionner

Fichier: C:\DataTest\EXIF_V6.JPG
Taille : 6,818,304 octets
ID     : 6 -> Image à tourner vers Gauche

Fichier: C:\DataTest\EXIF_H.JPG
Taille : 2,832,384 octets
ID     : 1 -> Image Horizontale

Fichier: C:\DataTest\EXIF_V8.JPG
Taille : 3,677,696 octets
ID     : 8 -> Image à tourner vers Droite
Il ne reste plus qu'à tourner l'image après chargement et avant redimensionnement avec la lib VectorDrawing
https://www.purebasic.com/french/docume ... nates.html

:wink:
Avatar de l’utilisateur
Micoute
Messages : 2522
Inscription : dim. 02/oct./2011 16:17
Localisation : 35520 La Mézière

Re: Lire le tag EXIF de rotation d'image JPG

Message par Micoute »

Merci Marc56, c'est du très bon travail.
Microsoft Windows 10 Famille 64 bits : Carte mère : ASRock 970 Extreme3 R2.0 : Carte Graphique NVIDIA GeForce RTX 3080 : Processeur AMD FX 6300 6 cœurs 12 threads 3,50 GHz PB 5.73 PB 6.00 LTS (x64)
Un homme doit être poli, mais il doit aussi être libre !
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Pas encore au point, car si je liste un répertoire, j'ai parfois des valeurs supérieures à 8

Code : Tout sélectionner

EnableExplicit

Enumeration 
    #hDir    
    #hFile
EndEnumeration

Define Repertoire$ = PathRequester("Répertoire à lister", GetUserDirectory(#PB_Directory_Pictures))

If ExamineDirectory(#hDir, Repertoire$, "*.jpg")  
    While NextDirectoryEntry(#hDir)
        If DirectoryEntryType(#hDir) = #PB_DirectoryEntry_File
            Define Fichier$ = DirectoryEntryName(#hDir)
            Debug Fichier$ + " ?"
            If ReadFile(#hFile, Repertoire$ + Fichier$, #PB_Unicode) 
                
                Debug "   - Taille : " + FormatNumber(Lof(#hFile), 0) + " octets"
                
                FileSeek(#hFile, 54)
                Define ID = ReadCharacter(#hFile)
                ; 1 = Horizontal (normal)
                ; 2 = Mirror horizontal
                ; 3 = Rotate 180
                ; 4 = Mirror vertical
                ; 5 = Mirror horizontal And rotate 270 CW
                ; 6 = Rotate 90 CW
                ; 7 = Mirror horizontal And rotate 90 CW
                ; 8 = Rotate 270 CW
                Select ID
                    Case 1  : Debug "   - ID     : " + ID + " -> Image Horizontale"
                    Case 2  : Debug "   - ID     : " + ID + " -> Image en Miroir Horizontale"
                    Case 6  : Debug "   - ID     : " + ID + " -> Image à tourner vers Gauche"
                    Case 8  : Debug "   - ID     : " + ID + " -> Image à tourner vers Droite"
                    Default : Debug "   - ID     : " + ID + " ?"
                EndSelect
                
                CloseFile(#hFile)
            Else 
                Debug "   - Pas d'EXIF"
            EndIf
        EndIf
        Debug ""
    Wend
    FinishDirectory(#hDir)
EndIf
:|
boby
Messages : 261
Inscription : jeu. 07/juin/2007 22:54

Re: Lire le tag EXIF de rotation d'image JPG

Message par boby »

Merci de te prendre la tête à notre place Marc :p

Si tu t'en sors dans la lecture des EXIF ça fera un bon code à se garder sous la main :lol:
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Marc56 a écrit :Pas encore au point, car si je liste un répertoire, j'ai parfois des valeurs supérieures à 8
J'suis bête :oops: c'est quand il n'y a pas d'EXIF
Il faut tester avant, la présence du mot « Exif » à l'offset 6

Code : Tout sélectionner

                FileSeek(#hFile, 6)
                If ReadString(#hFile) = "Exif"

Code : Tout sélectionner

EnableExplicit

Enumeration 
    #hDir    
    #hFile
EndEnumeration

Define Repertoire$ = PathRequester("Répertoire à lister", GetUserDirectory(#PB_Directory_Pictures))

If ExamineDirectory(#hDir, Repertoire$, "*.jpg")  
    While NextDirectoryEntry(#hDir)
        If DirectoryEntryType(#hDir) = #PB_DirectoryEntry_File
            Define Fichier$ = DirectoryEntryName(#hDir)
            Debug Fichier$ + " ?"
            If ReadFile(#hFile, Repertoire$ + Fichier$) ;, #PB_Unicode) 
                
                Debug "   - Taille : " + FormatNumber(Lof(#hFile), 0) + " octets"
                FileSeek(#hFile, 6)
                If ReadString(#hFile) = "Exif"
                    FileSeek(#hFile, 54)
                    Define ID = ReadByte(#hFile)
                    Select ID
                        Case 1  : Debug "   - ID     : " + ID + " -> Horizontal (normal)"
                        Case 2  : Debug "   - ID     : " + ID + " -> Mirror horizontal"
                        Case 3  : Debug "   - ID     : " + ID + " -> Rotate 180"
                        Case 4  : Debug "   - ID     : " + ID + " -> Mirror vertical"
                        Case 5  : Debug "   - ID     : " + ID + " -> Mirror horizontal And rotate 270 CW"
                        Case 6  : Debug "   - ID     : " + ID + " -> Rotate 90 CW"
                        Case 7  : Debug "   - ID     : " + ID + " -> Mirror horizontal And rotate 90 CW"
                        Case 8  : Debug "   - ID     : " + ID + " -> Rotate 270 CW"
                        Default : Debug "   - ID     : " + ID + " ?"
                    EndSelect
                Else
                    Debug "   - Pas d'EXIF"
                EndIf
                
                CloseFile(#hFile)
            Else 
                Debug "   - Pas d'EXIF"
            EndIf
        EndIf
        Debug ""
    Wend
    FinishDirectory(#hDir)
EndIf

End
:wink:
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Lire le tag EXIF de rotation d'image JPG

Message par Kwai chang caine »

Merci Marc 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Lire le tag EXIF de rotation d'image JPG

Message par Ar-S »

Marc
Merci pour cette tentative.
Je viens de tester sur 8 photos que j'ai pris avec mon smartphone (Samsung J7)
Si je les redimensionne et les sauve, les verticales finissent horizontales.
Ton code n'affiche pourtant aucun exif sur toutes les originales. Y'a une couille dans l'potage.
J'ai vérifié avec ExifViewer et il y a pourtant bien une info exif (rotation gauche) sur les images concernées.
0112 / Orientation / 8
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Bien vu. :)
Je viens aussi de regarder celles prises avec mon S4, il affiche comme ID -98 pour des photos à la verticale alors qu'Irfanview affiche Right-Top (donc doit tourner vers la droite)
Je pense que c'est une question de version d'EXIF

On ne peut donc pas se fier à l'offset, il faut chercher la balise, comme indiqué dans la doc et dans mon premier exemple

Code : Tout sélectionner

; --- Procédures
Procedure Search_Orientation(Fichier$)
    Debug "Fichier: " + Fichier$
    If Not ReadFile(0, Fichier$, #PB_Unicode) 
        Debug "Fichier illisible"
        ProcedureReturn 
    EndIf
    length = Lof(0) 
    Debug "Taille : " + FormatNumber(length, 0) + " octets"
    For i = 0 To length          
        FileSeek(0, i)  
        If ReadUnicodeCharacter(0) = $0112 ; ou 274 en décimal
            Debug "Offset : " + i
            FileSeek(0, 6, #PB_Relative)
            ID = ReadCharacter(0)
            Debug "Valeur : " + ID
            Select ID
                Case 1 : Debug "Image Horizontale"
                Case 6 : Debug "Image à tourner vers Droite"
                Case 8 : Debug "Image à tourner vers Gauche"
            EndSelect
            Break 
        EndIf
    Next 
    CloseFile(0)
    Debug ""
EndProcedure

Search_Orientation(" ")
J'avais aussi inversé gauche et droite.

:idea: Je vais reprendre mon ACME Viewer et lui ajouter l'affichage des exifs et la rotation automatique des images verticales.

:wink:
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Lire le tag EXIF de rotation d'image JPG

Message par Ar-S »

C'est mieux ainsi ;)
Du coup tu vas procéder comment ? Tu vires l'exif et tu appliques une rotation physique via vectordrawing ? (ça risque d'être long)
ou tu vas recréer l'info exif. Si tu optes pour cette dernière solution je veux bien savoir comment tu procèdes.

---edit---
sur ce topic wichtel lit et crée un fichier ne contenant que l'exif qu'il regreffe ensuite à la nouvelle image.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Ar-S a écrit :C'est mieux ainsi ;)
Du coup tu vas procéder comment ? Tu vires l'exif et tu appliques une rotation physique via vectordrawing ? (ça risque d'être long)
ou tu vas recréer l'info exif. Si tu optes pour cette dernière solution je veux bien savoir comment tu procèdes.
Vectordrawing va vite pour faire tourner l'image 8)
1. Je charge l'image d'origine
2. Je créé une image cible de proportions inversées
3. Je déplace le point zéro
4. Je tourne le système de coordonnées (RotateCoordinates(0, 0, 90))
5. Je trace l'image
6. Je sauvegarde

Code : Tout sélectionner

EnableExplicit

Enumeration 
    #gImg
    #Img_In    
    #Img_Out
EndEnumeration

#File_IN  = "C:\DataTest\EXIF_V6.JPG"       ; Image test: 4200x2800 6.5 Mo verticale avec exif
#File_OUT = "C:\DataTest\EXIF_V6_OUT.JPG"

UseJPEGImageDecoder()
UseJPEGImageEncoder()

Define Start_Time = ElapsedMilliseconds()

If LoadImage(#Img_In, #File_IN)
    Debug "Image chargée. (" + #File_IN + ")"
    Define W = ImageWidth(#Img_In)    : Debug "Largeur: " + W
    Define H = ImageHeight(#Img_In)   : Debug "Hauteur: " + H
    CreateImage(#Img_Out, H, W) ; Proportions inversées
    
    If StartVectorDrawing(ImageVectorOutput(#Img_Out))
        Debug "Rotation..."
        MovePathCursor(H, 0)
        RotateCoordinates(0, 0, 90)
        DrawVectorImage(ImageID(#Img_In))
        StopVectorDrawing()
        Debug "Rotation Terminée."
        Debug FormatNumber( (ElapsedMilliseconds() - Start_Time) / 1000.0, 2) + " Secondes"
        
        If SaveImage(#Img_Out, #File_OUT, #PB_ImagePlugin_JPEG)
            Debug "Sauvegarde OK"
        Else
            Debug "Sauvegarde KO"
        EndIf
    EndIf
Else
    Debug "Je ne peux pas charger l'image :-("
    End
EndIf

RunProgram(#File_OUT, "", "")

End
On doit pouvoir faire bien mieux, je ne suis pas un pro du binaire et des images.
Test simple, avec une image tournée à droite (il faut donc lire l'orientation avant pour tourner dans le bon sens)
Ici, avec une image de test de 4200x2800 pour 6.5 Mo, mon petit i3 met 1.5 secondes :) ce qui me suffit car je ne fais pas en série
Évidement, SaveImage fait perdre tous les exifs, il faudrait donc les sauver avant puis les réécrire et modifier celui de l'orientation
C'est quand même bien de pouvoir faire tout ça avec ce qu'il y a en standard dans PB. Merci Fred

Les références du format EXIF sont là
https://fr.wikipedia.org/wiki/Exchangea ... ile_format
http://owl.phy.queensu.ca/~phil/exiftoo ... /EXIF.html

:wink:
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Re: Lire le tag EXIF de rotation d'image JPG

Message par Ollivier »

Question con : les 6 1ers octets ils ressemblent à quoi?
C'est pas un Byte Order Mark en unicode (3 * 2 octets)?
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Ollivier a écrit :Question con : les 6 1ers octets ils ressemblent à quoi?
C'est pas un Byte Order Mark en unicode (3 * 2 octets)?
Le 3 premiers sont FF D8 FF (lu avec un éditeur hexa)
C'est l'indicateur de fichier JPEG
https://www.filesignatures.net/index.ph ... 0&mode=SIG

Le reste est décrit dans les liens externes de Wikipedia sur les EXIF
y compris le PDF officiel (190 pages)
https://fr.wikipedia.org/wiki/Exchangea ... ile_format

:wink:
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Lire le tag EXIF de rotation d'image JPG

Message par Ar-S »

@Marc56
Petit retour sur ce topic pour te dire que j'ai appliqué ton code à mon resizer gold et je m'occupe de pivoter les images exif 3, 6 et 8 dans le bon sens via la vectordrawing.
Le rendu est un peu plus lent vu qu'il y a quelques photos à retourner en générale dans un lot mais dans l'ensemble ça reste performant.
Merci pour tes contributions précieuses.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Marc56
Messages : 2146
Inscription : sam. 08/févr./2014 15:19

Re: Lire le tag EXIF de rotation d'image JPG

Message par Marc56 »

Spécial merci en retour à Dobro|Spock|Zorro :) pour ses très nombreux exemples, certes parfois fouillis :mrgreen: mais ô combien utiles et abondamment commentés grâce auxquels j'ai pu comprendre et enfin oser "peekorer" (= avancer octet par octet et lire un bloc à chaque pas) directement dans les fichiers binaires plutôt que d'utiliser des libs tiers non Fred' Certified.
(Quand on a qu'une seule info à extraire c'est plus simple de le faire directement plutôt que d'inclure des centaines de lignes.)

:idea: Pour la vitesse de recherche, il doit y avoir moyen d'aller directement à l'information en chargeant la taille de la structure. Information qu'on doit trouver dans la doc, mais mon anglais est trop mauvais pour tout comprendre :(

Merci aussi à l'ensemble du forum pour l'aide en général (ex: les conversion de fonction ascii/unicode)

8)
Répondre