Page 1 sur 1

[R] Ecrire dans EXIF et Lire EXIF

Posté : sam. 02 juil. 2016 17:41
par GMH
Bonjour,

Est-il possible d'ajouter une ou plusieurs données dans un EXIF d'image jpg (autres que celles déjà présentes), puis ensuite de les récupérer ?
Si oui, pourriez-vous m'indiquer de quelles fonctions AutoIt dispose ? Quel include ?

Je vous remercie de vos renseignements à ce sujet.

Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : sam. 02 juil. 2016 18:57
par walkson
Bonjour,
Dans mon joyeux bord d'aile j'ai retrouvé ceci
Il répond à la question de lire les infos mais je sais que c'est possible de les modifier (j'ai le code mais où ?)

Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : sam. 02 juil. 2016 19:44
par GMH
Programme impeccable pour la lecture de l'exif. Grand merci !
J'attends avec impatience que vous retrouviez le module d'écriture ! :)

=============================

Est-ce que ce serait le fichier descript.au3 téléchargeable à l'adresse : https://www.autoitscript.com/forum/topi ... -comments/ ?

Si oui, il y a une erreur à la ligne 179.

Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : dim. 03 juil. 2016 11:14
par walkson
Bonjour,
J'ai repris descript.au3 et l'ai légèrement modifié. J'ai traduit un peu aussi parce que mon allemand s'arrête à cette phrase "ein Bier bitte" :wink:

Code : Tout sélectionner

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_outfile=descred8.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <ButtonConstants.au3>
#include <ComboConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <image_get_info.au3>

Opt("MustDeclareVars", 0)

Const $c1 = "Ce programme est utilisé pour la description des photos JPEG."
Const $c2 = ""
Const $c3 = "Mode d'emploi:"
Const $c4 = "1. Sélectionnez [...] un répertoire avec des images."
Const $c5 = "2. Remplissez les blancs ci-dessous une description de la photo affichée."
Const $c6 = "3. [Next], Ctrl {RIGHT} ou {ENTRER} à la photo suivante dans le répertoire"
Const $c7 = "4. Répétez les étapes 2 et 3 pour toutes les photos."
Const $c8 = "Chaque photo changer la description est stockée."
Const $c9 = ""
Const $c10 = "[EXIF] ou Ctrl + E montre les données Exif de la photo en cours"
Const $c11 = "[Annuler] ou Ctrl + U est la Restaure Description originale"
Const $c12 = "[Dernière] ou Ctrl + L répète la dernière description de la photo précédente"
Const $c13 = "[Retour] ou Ctrl {LINKS} modifications apportées à la photo précédente dans le répertoire."
Const $c14 = ""
Const $c15 = "Amusez-vous!"

Const $wmax = 600
Const $hmax = 400

Global $t, $Form1, $lbAnleitg, $Label2, $inVerz, $btOeffVerz, $Pic1, $Button3, $inDescr, $Group1
Global $btExif, $btZurueck, $btWeiter, $btLetzte, $btUndo, $nMsg
Global $verz, $aFiles[1], $idx, $description, $prevdescr

$Form1 = GUICreate("Description für Fotos v2", 632, 540, (@DesktopWidth - 632) / 2, (@DesktopHeight - 540) / 2 - 30)
GUISetFont(10, 400, 1, "Arial")
$t = 8 ; Verz.eingabe
$inVerz = GUICtrlCreateInput("Fotoverzeichnis", 16, $t, 550, 22)
$btOeffVerz = GUICtrlCreateButton("...", 580, $t, 33, 20, $WS_GROUP)
GUICtrlSetTip($btOeffVerz, "Fotoverzeichnis öffnen")
$t = $t + 28 ;oberer Bildrand
$Pic1 = GUICtrlCreatePic("", 16, $t, $wmax, $hmax, BitOR($SS_NOTIFY, $WS_GROUP, $WS_CLIPSIBLINGS))
$t = $t + 100
$lbAnleitg = GUICtrlCreateLabel($c1 & @CRLF & $c2 & @CRLF & $c3 & @CRLF & $c4 & @CRLF & $c5 & @CRLF & $c6 & _
		@CRLF & $c7 & @CRLF & $c8 & @CRLF & $c9 & @CRLF & $c10 & @CRLF & $c11 & @CRLF & $c12 & @CRLF & $c13 & _
		@CRLF & $c14 & @CRLF & $c15, 70, $t, 480, 250)
$t = $t + 300
$inDescr = GUICtrlCreateInput("description de la photo", 16, $t + 25, 601, 22)
$t = $t + 58 ; Button-zeile
$btExif = GUICtrlCreateButton("EXIF", 300, $t, 42, 25, $WS_GROUP)
GUICtrlSetTip($btExif, "les données montrent")
GUICtrlSetState(-1, $GUI_DISABLE)
$btUndo = GUICtrlCreateButton("annuler", 388, $t, 42, 25, $WS_GROUP)
GUICtrlSetTip($btLetzte, "description de la restauration")
GUICtrlSetState(-1, $GUI_DISABLE)
$btLetzte = GUICtrlCreateButton("dernier", 438, $t, 42, 25, $WS_GROUP)
GUICtrlSetTip($btLetzte, "Répéter la dernière Description")
GUICtrlSetState(-1, $GUI_DISABLE)
$btZurueck = GUICtrlCreateButton("dos", 530, $t, 42, 25, $WS_GROUP)
GUICtrlSetTip($btZurueck, "Enregistrer la description" & @CRLF & "et de retour dans Fotoverz.")
GUICtrlSetState(-1, $GUI_DISABLE)
$btWeiter = GUICtrlCreateButton("plus", 580, $t, 42, 25, $BS_DEFPUSHBUTTON)
GUICtrlSetTip($btWeiter, "Enregistrer la description" & @CRLF & "et en outre en ce Fotoverz.")
GUICtrlSetState(-1, $GUI_DISABLE)
$Label2 = GUICtrlCreateLabel("", 16, $t + 5, 265, 25) ; Anzeigen des Dateinamens des Fotos
Dim $AccelKeys[5][2]=[["^u", $btUndo],["^e", $btExif],["^l", $btLetzte],["^{RIGHT}", $btWeiter], ["^{LEFT}", $btZurueck]]
GUISetAccelerators($AccelKeys)

GUISetState(@SW_SHOW)


TastenStatus()
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $btOeffVerz
			OeffneVerz()
			TastenStatus()
		Case $btExif
			ZeigeExif()
		Case $btZurueck ;
			VorigesFoto()
		Case $btWeiter ;
			NaechstesFoto()
		Case $btLetzte ;
			Letzte()
		Case $btUndo ;
			GUICtrlSetData($inDescr, $description)
			SetzeCursor()
	EndSwitch
WEnd
;-----------------------------------------

Func Letzte()
	GUICtrlSetData($inDescr, $prevdescr)
	SetzeCursor()
EndFunc

Func debug($msg)
	MsgBox(0, "DEBUG", $msg)
EndFunc   ;==>debug

Func OeffneVerz()
	Local $search, $file
	$verz = FileSelectFolder("Verzeichnis mit Fotos wählen", "", 4, $verz, $Form1)
	GUICtrlSetData($inVerz, $verz)
	ReDim $aFiles[1]
	$description = ""
	FileChangeDir($verz)
	$search = FileFindFirstFile("*.jpg")
	If $search = -1 Then
		MsgBox(0, "", "Aucune photo de JPG dans le répertoire sélectionné", 5)
	Else
		While 1
			$file = FileFindNextFile($search)
			If @error Then ExitLoop
			ReDim $aFiles[UBound($aFiles) + 1]
			$aFiles[UBound($aFiles)- 1] = $file
		WEnd
		FileClose($search)
		_ArraySort($aFiles)
		$idx = 1
		GUICtrlDelete($lbAnleitg)

		ZeigeFoto()
	EndIf
EndFunc   ;==>OeffneVerz

Func TastenStatus()
	If $idx > 0 Then
		GUICtrlSetState($btExif, $GUI_ENABLE)
		GUICtrlSetState($btZurueck, $GUI_ENABLE)
		GUICtrlSetState($btWeiter, $GUI_FOCUS) ; sonst funkt. {ENTER} nicht
		GUICtrlSetState($btWeiter, $GUI_ENABLE)
		GUICtrlSetState($btLetzte, $GUI_ENABLE)
		GUICtrlSetState($btUndo, $GUI_ENABLE)
	Else
		GUICtrlSetState($btExif, $GUI_DISABLE)
		GUICtrlSetState($btZurueck, $GUI_DISABLE)
		GUICtrlSetState($btWeiter, $GUI_DISABLE)
		GUICtrlSetState($btLetzte, $GUI_DISABLE)
		GUICtrlSetState($btUndo, $GUI_DISABLE)
		GUICtrlSetState($btOeffVerz, $GUI_FOCUS)
	EndIf
EndFunc   ;==>TastenStatus

Func VorigesFoto()
	AktualDescription()
	If $idx > 1 Then
		$idx = $idx - 1
		ZeigeFoto()
	Else
		ZeigeFoto()
		MsgBox(0, "", "Première photo dans le répertoire", 1)
		TastenStatus()
	EndIf
EndFunc   ;==>VorigesFoto

Func NaechstesFoto()
	AktualDescription()
	If $idx < UBound($aFiles) - 1 Then
		$idx = $idx + 1
		ZeigeFoto()
	Else
		ZeigeFoto()
		MsgBox(0, "", "La photo précédente dans le répertoire", 1)
		TastenStatus()
	EndIf
EndFunc   ;==>NaechstesFoto

Func ZeigeFoto()
	Local $aInfo,$ew,$eh,$w,$h,$f,$x,$y
	$aInfo =_ImageGetInfo($aFiles[$idx])
	$ew = _ImageGetParam($aInfo, "Width")
	If $ew=0 Then $ew=$wmax
	$eh = _ImageGetParam($aInfo, "Height")
	If $eh=0 Then $eh=$hmax
	$f=$ew/$eh
	If $f>= $wmax/$hmax Then ;landscape
		$w=$wmax
		$h=$eh*$wmax/$ew
	Else                     ;portrait
		$h=$hmax
		$w=$ew*$hmax/$eh
	EndIf
	$x=16+($wmax-$w)/2
	$y=40+($hmax-$h)/2

	GUICtrlDelete($Pic1)
	$Pic1 = GUICtrlCreatePic("", $x, $y, $w, $h, BitOR($SS_NOTIFY, $WS_GROUP, $WS_CLIPSIBLINGS))



	GUICtrlSetData($Label2, $idx & "/" & UBound($aFiles) - 1 & "  " & $aFiles[$idx])
	GUICtrlSetImage($Pic1, $aFiles[$idx])
	LeseDescription()
	GUICtrlSetData($inDescr, $description)
	SetzeCursor()
EndFunc   ;==>ZeigeFoto

Func SetzeCursor()
	GUICtrlSetState($inDescr, $GUI_FOCUS)
	Sleep(100)
	Send("{END}")
EndFunc   ;==>SetzeCursor




Func FotoLoeschen()
	If MsgBox(4 + 32 + 256 + 262144, "", "Sicher?" & @CR & "Soll dieses Foto gelöscht werden?") = 6 Then
		FileDelete($aFiles[$idx])
		_ArrayDelete($aFiles, $idx)
		ZeigeFoto()
	EndIf
EndFunc   ;==>FotoLoeschen

Func LeseDescription() ;Beschreibung auslesen und in Formular eintragen
	Local $DescriptionR, $line, $p
	$DescriptionR = FileOpen("descript.ion", 0)
	If $DescriptionR <> -1 Then
		While 1
			$line = FileReadLine($DescriptionR)
			If @error = -1 Then ; bis zum EOF keine Beschreibung gefunden
				$description = ""
				ExitLoop ;
			Else
				If StringInStr($line, Chr(34), 2, 1, 2) Then ; Dateiname enthält '"'
					$p = StringInStr($line, Chr(34) & Chr(32)) + 1 ; Pos. nach '" '
				Else
					$p = StringInStr($line, Chr(32)) ; Pos. nach " "
				EndIf
				If StringInStr(StringLeft($line, $p), $aFiles[$idx]) Then
					$description = StringTrimLeft($line, $p)
					ExitLoop ; Beschreibung gefunden
				EndIf
			EndIf
		WEnd
		FileClose($DescriptionR)
	EndIf
EndFunc   ;==>LeseDescription

Func AktualDescription() ; EXIF auch Aktualisieren
	Local $DescriptionR, $DescriptionW, $newdescr, $fname, $line, $p, $attrib
	$newdescr = GUICtrlRead($inDescr)
	$prevdescr = $newdescr
	If $newdescr <> $description Then
		$DescriptionW = FileOpen("descript.new", 1)
		If $DescriptionW = -1 Then
			MsgBox(16, "Fehler", "Kann keine Beschreibungen speichern!" & @CRLF & "Ist das Fotoverzeichnis etwa schreibgeschützt?")
			Exit
		EndIf
		$fname = $aFiles[$idx]
		If StringInStr($fname, Chr(32)) Then $fname = Chr(34) & $fname & Chr(34) ;Dateiname mit Leerzeichen zwischen "" setzen
		If FileExists("descript.ion") Then
			$DescriptionR = FileOpen("descript.ion", 0)
			$attrib = FileGetAttrib("descript.ion")
			FileSetAttrib("descript.ion", "-RSH")
			While 1
				$line = FileReadLine($DescriptionR)
				If @error = -1 Then ; EOF
					ExitLoop ;
				Else
					If StringInStr($line, Chr(34), 2, 1, 2) Then ; Dateiname enthält '"'
						$p = StringInStr($line, Chr(34) & Chr(32)) + 1 ; Pos. nach '" '
					Else
						$p = StringInStr($line, Chr(32)) ; Pos. nach " "
					EndIf
					If Not StringInStr(StringLeft($line, $p), $aFiles[$idx]) Then
						FileWriteLine($DescriptionW, $line)
					EndIf
				EndIf
			WEnd
			FileClose($DescriptionR) ;descript.ion
		EndIf
		FileWriteLine($DescriptionW, $fname & Chr(32) & $newdescr)
		FileClose($DescriptionW) ;descript.new
		FileMove("descript.new", "descript.ion", 1) ; mit Überschreiben
		If $attrib = "" Then $attrib = "H" ; Hidden-Attribut setzen
		FileSetAttrib("descript.ion", "+" & $attrib)
	EndIf
EndFunc   ;==>AktualDescription

Func ZeigeExif()
	GUICtrlSetState($btExif, $GUI_DISABLE)
	GUICtrlSetState($btZurueck, $GUI_DISABLE)
	GUICtrlSetState($btWeiter, $GUI_DISABLE)
	GUICtrlSetState($btLetzte, $GUI_DISABLE)
	GUICtrlSetState($btUndo, $GUI_DISABLE)
	MsgBox(0, "EXIF", _ImageGetInfo($aFiles[$idx]))
	TastenStatus()
EndFunc   ;==>ZeigeExif



Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : dim. 03 juil. 2016 11:39
par orax
Il y a aussi ExifTool (utilisable en ligne de commande).

Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : dim. 03 juil. 2016 15:03
par GMH
Merci pour la correction de descript.au3 . Le programme n'affiche plus d'erreur.
Ce programme permet-il :
- et la modification de la valeur d'un tag
- et l'ajout d'un nouveau tag suivi de sa valeur ?
Dans chacun de ces cas, comment s'y prend-on ?
Je vous remercie de vos éclaircissements.

Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : dim. 03 juil. 2016 18:56
par walkson
comment s'y prend-on ?
Très bonne question ! il faut rentrer les donner dans l'input du bas. Le problème est que seul ce programme arrive à le lire...
Par contre, j'ai trouvé ce code qui fonctionne bien

Code : Tout sélectionner

#include <GDIPlus.au3>

Global Const $PropertyTagTypeByte = 1
Global Const $PropertyTagTypeASCII = 2
Global Const $PropertyTagTypeShort = 3
Global Const $PropertyTagTypeLong = 4
Global Const $PropertyTagTypeRational = 5
Global Const $PropertyTagTypeUndefined = 7
Global Const $PropertyTagTypeSLong = 9
Global Const $PropertyTagTypeSRational = 10

_GDIPlus_Startup ()

$hFile = _GDIPlus_ImageLoadFromFile(@DesktopDir & "\IMG\WANTED.jpg")

_GDIPlus_SetMetaData($hFile,"Make", "Any Old Camera")
_GDIPlus_SetMetaData($hFile,"Author", "Chris Lambert")
_GDIPlus_SetMetaData($hFile,"Software", "Chris's Application")

_GDIPlus_ImageSaveToFile($hFile,@desktopDir & "\New.jpg")

_GDIPlus_ImageDispose($hFile)

_GDIPlus_Shutdown()


Func _GDIPlus_SetMetaData($hHandle,$sTagName, $vStr)

    Local $tagPropertyItem = "ulong id; ulong length; ushort Type; ptr value"
    Local $Struct_String, $Struct_Meta, $aResult, $PropertyTagType

    Switch $sTagName

        Case "ImageWidth"
            $ID = 0x100
            $PropertyTagType = $PropertyTagTypeShort

        Case "ImageLength"
            $ID = 0x101
            $PropertyTagType = $PropertyTagTypeShort

        Case "BitsPerSample"
            $ID = 0x102
            $PropertyTagType = $PropertyTagTypeShort

        Case "Compression"
            $ID = 0x103
            $PropertyTagType = $PropertyTagTypeShort

        Case "PhotometricInterpretation"
            $ID = 0x106
            $PropertyTagType = $PropertyTagTypeShort

        Case "Orientation"
            $ID = 0x112
            $PropertyTagType = $PropertyTagTypeShort

        Case "SamplesPerPixel"
            $ID = 0x115
            $PropertyTagType = $PropertyTagTypeShort

        Case "PlanarConfiguration"
            $ID = 0x11C
            $PropertyTagType = $PropertyTagTypeShort

        Case "YCbCrSubSampling"
            $ID = 0x212
            $PropertyTagType = $PropertyTagTypeShort

        Case "YCbCrPositioning"
            $ID = 0x213
            $PropertyTagType = $PropertyTagTypeShort

        Case "XResolution"
            $ID = 0x11A
            $PropertyTagType = $PropertyTagTypeRational

        Case "YResolution"
            $ID = 0x11B
            $PropertyTagType = $PropertyTagTypeRational

        Case "ResolutionUnit"
            $ID = 0x296
            $PropertyTagType = $PropertyTagTypeShort

        Case "StripOffsets"
            $ID = 0x111
            $PropertyTagType = $PropertyTagTypeShort

        Case "RowsPerStrip"
            $ID = 0x116
            $PropertyTagType = $PropertyTagTypeShort

        Case "StripByteCounts"
            $ID = 0x117
            $PropertyTagType = $PropertyTagTypeShort

        Case "JPEGInterchangeFormat"
            $ID = 0x201
            $PropertyTagType = $PropertyTagTypeLong

        Case "JPEGInterchangeFormatLength"
            $ID = 0x202
            $PropertyTagType = $PropertyTagTypeLong

        Case "TransferFunction"
            $ID = 0x12D
            $PropertyTagType = $PropertyTagTypeShort

        Case "WhitePoint"
            $ID = 0x13E
            $PropertyTagType = $PropertyTagTypeRational

        Case "PrimaryChromaticities"
            $ID = 0x13F
            $PropertyTagType = $PropertyTagTypeRational

        Case "YCbCrCoefficients"
            $ID = 0x211
            $PropertyTagType = $PropertyTagTypeRational


        Case "ReferenceBlackWhite"
            $ID = 0x214
            $PropertyTagType = $PropertyTagTypeRational

        Case "DateTime"
            $ID = 0x132
            $PropertyTagType = $PropertyTagTypeASCII

        Case "ImageDescription"
            $ID = 0x10E
            $PropertyTagType = $PropertyTagTypeASCII

        Case "Make"
            $ID = 0x10F
            $PropertyTagType = $PropertyTagTypeASCII

        Case "Model"
            $ID = 0x110
            $PropertyTagType = $PropertyTagTypeASCII

        Case "Software"
            $ID = 0x131
            $PropertyTagType = $PropertyTagTypeASCII

        Case "Artist", "Author"
            $ID = 0x13B
            $PropertyTagType = $PropertyTagTypeASCII

        Case "Copyright"
            $ID = 0x8298
            $PropertyTagType = $PropertyTagTypeASCII

        Case Else
            Return SetError(1, -1, False)
    EndSwitch

   ; Store string in array
    $Struct_String=DllStructCreate("char[" & StringLen($vStr) +1 & "];")
    DllStructSetData($Struct_String,1,$vStr)

    $Struct_Meta = DllstructCreate($tagPropertyItem)
    DllStructSetData($Struct_Meta,"ID",$ID)
    DllStructSetData($Struct_Meta,"Length",StringLen($vStr) +1)
    DllStructSetData($Struct_Meta,"Type",$PropertyTagType)
    DllStructSetData($Struct_Meta,"Value",DllStructGetPtr($Struct_String))

    $aResult = DllCall($__g_hGDIPDll, "int", "GdipSetPropertyItem", "hwnd", $hHandle, "ptr", DllStructGetPtr($Struct_Meta))
    If @error Then Return SetError(@error, @extended, False)

    Return SetError($aResult[0], 0, $aResult[0] = 0)

EndFunc
et on retrouve bien les données
https://www.autoitscript.com/forum/topi ... ent=906946

Re: [..] Ecrire dans EXIF et Lire EXIF

Posté : dim. 03 juil. 2016 20:04
par GMH
Je ne reviens pas de l'efficacité de ce code ! C'est une véritable merveille.
Ce code allié au code image_get_info_example.au3 font un outil extraordinaire.

Je vous remercie de vos réponses qui font de mon rêve une réalité ! :D

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 09:27
par GMH
Pour ajouter un tag-maison, suffit-il d'ajouter un case dans le Switch $sTagName ?
Dans ce cas, quel nombre faudrait-il donner à la variable $ID ? Comment se ferait ce calcul ? Je ne trouve pas de régularité dans la suite :
► Afficher le texte
Je vous remercie de votre réponse.

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 11:27
par walkson
Faire un tag maison semble ne pas être possible car il relève d'une convention voir https://msdn.microsoft.com/en-us/librar ... exifdtorig
Avez vous regarder le lien à la fin de mon post? Tout à la fin, en date du 23 janvier 2014, il y a un autre exemple plus complet. Il faut juste modifier à la fin du code DllCall($ghGDIPDll en DllCall($__g_hGDIPDll mais je ne l'ai pas testé
Il serait possible d'utiliser, par exemple, "UserComments" comme tag maison

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 13:34
par GMH
Merci à vous.
Pour l'écriture dans le tag "UserComments", c'est parfait. Lorsque j'affiche l'exif de la photo dans un logiciel de graphisme, sa valeur s'affiche et est donc bien enregistrée.
Le programme "image_get_info_example.au3" affiche bien le tag "UserComments", mais il n'affiche pas sa valeur. Dois-je corriger ou ajouter quelque chose dans le code du fichier "image_get_info.au3" qui contient les fonctions ?

Fichier image_get_info.au3 :
[codeautoit];===============================================================================
;
; Description: Return JPEG, TIFF, BMP, PNG and GIF image common info:
; Size, Color Depth, Resolution etc. For JPEG files retreive
; additional information from exif tag (if exists).
; Parameter(s): File name
; Requirement(s): Autoit 3.3.0.0
; Return Value(s): On Success - string in format:
; ParamName=ParamValue
; Pairs are separated by LF char. For getting data can be used
; function _ImageGetParam($sData, $sParam), where
; $sData - string, returned by _ImageGetInfo
; $sParam - param name, for ex. Width
; On Failure sets @ERROR:
; 1 - Can't open image
; Return string become empty if no info found
; Author(s): Dmitry Yudin (Lazycat)
; Version: 2.8
; Date: 08.10.2010
;
;===============================================================================
Func _ImageGetInfo($sFile)
Local $sInfo = "", $hFile, $nClr
Local $ret = DllCall("kernel32.dll","int","CreateFile", _
"str",$sFile, _
"int",0x80000000, _
"int",0, _
"ptr",0, _
"int",3, _
"int",0x80, _
"ptr",0)

If @error OR Not $ret[0] Then
SetError(1)
Return ""
Endif
Local $hFile = $ret[0]
Local $p = _FileReadToStruct("ubyte[54]", $hFile, 0)
Local $asIdent[8] = [7, Chr(0xFF) & Chr(0xD8), "BM", Chr(0x89) & "PNG" & Chr(0x0D) & Chr(0x0A) & Chr(0x1A) & Chr(0x0A), "GIF89", "GIF87", "II", "MM"]
For $i = 1 To $asIdent[0]
If _DllStructArrayAsString($p, 1, StringLen($asIdent[$i])) = $asIdent[$i] Then
Select
Case $i = 1 ; JPEG
$sInfo = _ImageGetInfoJPG($hFile, FileGetSize($sFile))
Exitloop

EndSelect
Endif
Next
DllCall("kernel32.dll","int","CloseHandle","int", $hFile)
$p = 0
Return($sInfo)
EndFunc

;===============================================================================
; JPEG Parser
;===============================================================================
Func _ImageGetInfoJPG($hFile, $nFileSize)
Local $anSize[2], $sData, $sSeg, $nPos = 2, $sInfo = ""
Local $sUnit = "Pixel", $nMarker = 0, $nComLen
Local $p = DllStructCreate("ubyte;ubyte;ushort;byte[128]")
While ($nMarker <> 0xDA) and ($nPos < $nFileSize)
$p = _FileReadToStruct($p, $hFile, $nPos)
If DllStructGetData($p, 1) = 0xFF Then ; Valid segment start
$nMarker = DllStructGetData($p, 2)
Select
Case ($nMarker = 0xC0) or ($nMarker = 0xC1) or ($nMarker = 0xC2) or _
($nMarker = 0xC3) or ($nMarker = 0xC5) or ($nMarker = 0xC6) or _
($nMarker = 0xC7) or ($nMarker = 0xCB) or ($nMarker = 0xCD) or _
($nMarker = 0xCE) or ($nMarker = 0xCF)
$t = DllStructCreate("align 1;byte;ushort;ushort", DllStructGetPtr($p, 4))
_Add($sInfo, "Width", _IntR(DllStructGetData($t, 3)))
_Add($sInfo, "Height", _IntR(DllStructGetData($t, 2)))
Case $nMarker = 0xE0 ; JFIF header
$t = DllStructCreate("byte[5];byte;byte;ubyte;ushort;ushort", DllStructGetPtr($p, 4))
$nUnit = _IntR(DllStructGetData($t, 4))
If $nUnit = 1 Then
$sUnit = "Inch"
ElseIf $nUnit = 2 Then
$sUnit = "Cm"
EndIf
_Add($sInfo, "XResolution", _IntR(DllStructGetData($t, 5)))
_Add($sInfo, "YResolution", _IntR(DllStructGetData($t, 6)))
_Add($sInfo, "ResolutionUnit", $sUnit)
Case $nMarker = 0xE1 ; EXIF segment
$sInfo = $sInfo & ParseExif($hFile, $nPos)
Case $nMarker = 0xFE ; Comment segment
$nComLen = _IntR(DllStructGetData($p, 3)) - 2
$t = _FileReadToStruct("byte[" & $nComLen & "]", $hFile, $nPos + 4)
_Add($sInfo, "Comment", _DllStructArrayAsString($t, 1, $nComLen))
$t = 0
Case Else
EndSelect
$nPos= $nPos + _IntR(DllStructGetData($p, 3)) + 2
Else
ExitLoop
Endif
Wend
$p = 0
Return($sInfo)
EndFunc

;===============================================================================
; EXIF Parser
;===============================================================================
Func ParseExif($hFile, $exif_offset)
Local $nTiffHdrOffset, $pHdr, $nIFDOffset, $pCnt, $nIFDCount, $pTag, $nCnt, $id, $nEIFDCount
Local $ByteOrder = 0, $sInfo = ""
Local $nEIFDOffset, $aTag[1][2]
Local $sSpecialTags = "0112,8822,9208,9207,9209,9101,0128,A217,A403,A402,A406,A408,A409,A40A"

_AddPair($aTag, 0x0100, "ExifWidth")
_AddPair($aTag, 0x0101, "ExifHeight")
_AddPair($aTag, 0x011A, "XResolution")
_AddPair($aTag, 0x011B, "YResolution")
_AddPair($aTag, 0x0102, "Colordepth")
_AddPair($aTag, 0x0132, "DateTime")
_AddPair($aTag, 0x9003, "DateTimeOriginal")
_AddPair($aTag, 0x9004, "DateTimeDigitized")
_AddPair($aTag, 0x9102, "CompressedBitsPerPixel")
_AddPair($aTag, 0x9000, "ExifVersion")
_AddPair($aTag, 0x9204, "ExposureBiasValue")
_AddPair($aTag, 0x829A, "ExposureTime")
_AddPair($aTag, 0x829D, "FNumber")
_AddPair($aTag, 0x920A, "FocalLength")
_AddPair($aTag, 0x8827, "ISO")
_AddPair($aTag, 0x010F, "Make")
_AddPair($aTag, 0x9202, "ApertureValue")
_AddPair($aTag, 0x9205, "MaxApertureValue")
_AddPair($aTag, 0x0110, "Model")
_AddPair($aTag, 0x0131, "Software")
_AddPair($aTag, 0x010E, "ImageDescription")
_AddPair($aTag, 0x013B, "Artist")
_AddPair($aTag, 0x8298, "Copyright")
_AddPair($aTag, 0xA420, "ImageUniqueID")
_AddPair($aTag, 0x9286, "UserComments")
_AddPair($aTag, 0x9201, "ShutterSpeedValue")
_AddPair($aTag, 0x9202, "ApertureValue")
_AddPair($aTag, 0x9203, "BrightnessValue")
_AddPair($aTag, 0x9206, "SubjectDistance")
_AddPair($aTag, 0xA404, "DigitalZoomRatio")

$nTiffHdrOffset = $exif_offset + 10 ; Start of TIFF header

$pHdr = _FileReadToStruct("short;short;dword", $hFile, $nTiffHdrOffset)
If DllStructGetData($pHdr, 1) = 0x4D4D then $ByteOrder = 1
$nIFDOffset = _IntR(DllStructGetData($pHdr, 3), $ByteOrder)
$pCnt = _FileReadToStruct("ushort", $hFile, $nTiffHdrOffset + $nIFDOffset) ; Tags count
$nIFDCount = _IntR(DllStructGetData($pCnt, 1), $ByteOrder)

$pTag = DllStructCreate("ushort;ushort;ulong;ulong")
For $nCnt = 0 To $nIFDCount - 1
$pTag = _FileReadToStruct($pTag, $hFile, $nTiffHdrOffset + $nIFDOffset + 2 + $nCnt * 12)
$id = DllStructGetData($pTag, 1)
$id = _IntR($id, $ByteOrder)
For $i = 1 To $aTag[0][0]
If $aTag[$i][0] = $id Then
_Add($sInfo, $aTag[$i][1], _ReadTag($hFile, $pTag, $nTiffHdrOffset, $ByteOrder))
Exitloop
Endif
Next
If StringInStr($sSpecialTags, Hex($id, 4)) Then _AddSpecial($sInfo, $id, _ReadTag($hFile, $pTag, $nTiffHdrOffset, $ByteOrder))
If $id = 0x8769 Then ; Exif IFD Offset
$nEIFDOffset = _ReadTag($hFile, $pTag, $nTiffHdrOffset, $ByteOrder)
$pCnt = _FileReadToStruct($pCnt, $hFile, $nTiffHdrOffset + $nEIFDOffset)
$nEIFDCount = _IntR(DllStructGetData($pCnt, 1), $ByteOrder)
Endif
Next

If not ($nEIFDOffset > 0) Then Return($sInfo)

For $nCnt = 0 To $nEIFDCount - 1
$pTag = _FileReadToStruct($pTag, $hFile, $nTiffHdrOffset + $nEIFDOffset + 2 + $nCnt * 12)
$id = DllStructGetData($pTag, 1)
$id = _IntR($id, $ByteOrder)
For $i = 1 To $aTag[0][0]
If $aTag[$i][0] = $id Then
_Add($sInfo, $aTag[$i][1], _ReadTag($hFile, $pTag, $nTiffHdrOffset, $ByteOrder))
Exitloop
Endif
Next
If StringInStr($sSpecialTags, Hex($id, 4)) Then _AddSpecial($sInfo, $id, _ReadTag($hFile, $pTag, $nTiffHdrOffset, $ByteOrder))
Next
$pHdr = 0
$pCnt = 0
$pTag = 0

Return($sInfo)
EndFunc

;===============================================================================
; Return multi-choice values for some tags
;===============================================================================
Func _AddSpecial(ByRef $sInfo, $ID, $nValue)
Local $nIndex = $nValue, $sLabel, $aData, $sFired, $sMode, $sRed, $nModeState
Select
Case $id = 0xA402
$sLabel = "ExposureMode"
$aData = StringSplit("Auto,Manual,Auto bracket,Undefined", ",")
If $nValue > 2 Then $nIndex = 3
Case $id = 0xA403
$sLabel = "WhiteBalance"
$aData = StringSplit("Auto,Manual,Undefined", ",")
If $nValue > 1 Then $nIndex = 2
Case $id = 0xA406
$sLabel = "SceneCaptureType"
$aData = StringSplit("Standard,Landscape,Portrait,Night scene,Undefined", ",")
If $nValue > 3 Then $nIndex = 4
Case $id = 0xA408
$sLabel = "Contrast"
$aData = StringSplit("Normal,Soft,Hard,Undefined", ",")
If $nValue > 2 Then $nIndex = 3
Case $id = 0xA409
$sLabel = "Saturation"
$aData = StringSplit("Normal,Low,High,Undefined", ",")
If $nValue > 2 Then $nIndex = 3
Case $id = 0xA40A
$sLabel = "Sharpness"
$aData = StringSplit("Normal,Soft,Hard,Undefined", ",")
If $nValue > 2 Then $nIndex = 3
Case $id = 0xA217
$sLabel = "SensingMethod"
$aData = StringSplit("Undefined,Undefined,OneChipColorArea,TwoChipColorArea,ThreeChipColorArea,ColorSequentialArea,Undefined,Trilinear,ColorSequentialLinear", ",")
If $nValue > 8 Then $nIndex = 0
Case $id = 0x9101
$sLabel = "ComponentsConfiguration"
$aData = StringSplit("YCbCr,RGB", ",")
$nIndex = 0
If StringLeft($nValue, 1) = 0x34 Then $nIndex = 1
Case $id = 0x0128
$sLabel = "ResolutionUnit"
$aData = StringSplit("Undefined,Undefined,Inch,Sentimeter", ",")
If $nValue < 2 or $nValue > 3 Then $nIndex = 0
Case $id = 0x0112
$sLabel = "Orientation"
$aData = StringSplit("Undefined,Normal,Mirrored,180°,180° and mirrored,90° left and mirrored,90° right,90° right and mirrored,90° left", ",")
If $nValue > 8 Then $nIndex = 0
Case $id = 0x8822
$sLabel = "ExposureProgram"
$aData = StringSplit("Unknown,Manual Control,Normal,Aperture Priority,Shutter Priority,Creative (slow program),Action (high-speed),Portrait mode,Landscape mode", ",")
If $nValue > 8 Then $nIndex = 0
Case $id = 0x9207
$sLabel = "MeteringMode"
$aData = StringSplit("Unknown,Average,Center Weighted Average,Spot,MultiSpot,MultiSegment,Partial,Other", ",")
If $nValue > 7 Then $nIndex = 7
Case $id = 0x9208
$sLabel = "LightSource"
$aData = StringSplit("Unknown,Daylight,Fluorescent,Tungsten,Flash,Standard light A,Standard light B,Standard light C,D55,D65,D75,Other", ",")
Select
Case $nValue < 4
$nIndex = $nValue
Case $nValue = 10
$nIndex = 4
Case $nValue > 16 and $nValue < 23
$nIndex = 5 + $nValue - 17
Case $nValue = 255
$nIndex = 11
Case Else
$nIndex = 0
EndSelect
Case $id = 0x9209
$sFired = "Not fired, "
If _IsBitSet($nValue, 0) Then $sFired = "Fired, "
$sMode = ""
$nModeState = _IsBitSet($nValue, 4) * 2 + _IsBitSet($nValue, 3)
If $nModeState = 1 Then
$sMode = "Forced ON, "
ElseIf $nModeState = 2 Then
$sMode = "Forced OFF, "
ElseIf $nModeState = 3 Then
$sMode = "Auto, "
Endif
$sRed = ""
If _IsBitSet($nValue, 6) Then $sRed = "Red-eye reduction, "
$sInfo = $sInfo & StringTrimRight("Flash=" & $sFired & $sMode & $sRed, 2) & @LF
Return
EndSelect
$sInfo = $sInfo & $sLabel & "=" & $aData[$nIndex+1] & @LF
EndFunc

;===============================================================================
; Get param by name from function result
;===============================================================================
Func _ImageGetParam($sData, $sParam)
Local $nParamPos = StringInStr(@LF & $sData,@LF & $sParam & "=")
If $nParamPos Then
$sData = StringTrimLeft($sData, $nParamPos + StringLen($sParam))
Return StringLeft($sData, StringInStr($sData, @LF) - 1)
Endif
Return ""
EndFunc

;===============================================================================
; Checks if bit in the number is set
;===============================================================================
Func _IsBitSet($nNum, $nBit)
Return BitAND(BitShift($nNum, $nBit), 1)
EndFunc

;===============================================================================
; Add pair of values ID - Label to array
;===============================================================================
Func _AddPair(ByRef $aTag, $nID, $sLabel)
Local $nBound = UBound($aTag)
ReDim $aTag[$nBound+1][2]
$aTag[$nBound][0] = $nID
$aTag[$nBound][1] = $sLabel
$aTag[0][0] = $nBound
EndFunc

;===============================================================================
; Wrapper to add string
;===============================================================================
Func _Add(ByRef $sInfo, $sLabel, $nValue)
$sInfo = $sInfo & $sLabel & "=" & $nValue & @LF
EndFunc

;===============================================================================
; Convert Intel numbers into Motorola in case $nOrder = 1
;===============================================================================
Func _IntR($nInt, $nOrder = 1)
If not $nOrder Then Return $nInt
Local $nRet = 0, $nIntSize = 3, $curbyte
If BitShift($nInt, 16) = 0 Then $nIntSize = 1
For $i = 0 To $nIntSize
$curbyte = BitAND(BitShift($nInt, 8 * ($nIntSize-$i)), 0xFF)
$nRet = $nRet + BitShift($curbyte, -8 * $i)
Next
Return($nRet)
EndFunc

;===============================================================================
; Read data to struct given by string or pointer
;===============================================================================
Func _FileReadToStruct($vStruct, $hFile, $nOffset)
If not DllStructGetSize($vStruct) Then $vStruct = DllStructCreate($vStruct)
Local $nLen = DllStructGetSize($vStruct)
Local $ret = DllCall("kernel32.dll","int","SetFilePointer", _
"int",$hFile, _
"int",$nOffset, _
"int",0, _
"int",0) ; FILE_BEGIN
Local $pRead = DllStructCreate("dword")
$ret = DllCall("kernel32.dll","int","ReadFile", _
"int",$hFile, _
"ptr",DllStructGetPtr($vStruct), _
"int", $nLen, _
"ptr",DllStructGetPtr($pRead), _
"ptr",0)
Local $nRead = DllStructGetData($pRead, 1)
$pRead = 0
SetExtended($nRead)
If not ($nRead = $nLen) Then SetError(2)
Return $vStruct
EndFunc

;===============================================================================
; Read string data, avoid situation when string is not null-terminated
;===============================================================================
Func _DllStructArrayAsString($p, $index, $size, $start = 1)
Local $sTemp = "", $char
For $i = $start to $size
$char = DllStructGetData($p, $index, $i)
If $char = 0 then Return $sTemp
$sTemp &= Chr($char)
Next
Return $sTemp
EndFunc[/codeautoit]

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 15:20
par walkson
Oui, en effet, le code ne renvoie pas tout et je n'ai aucune idée pour corriger cela.
sur le lien https://www.autoitscript.com/forum/topi ... ment=89418 où se trouve l'UDF, il y a aussi image_get_info_30.zip que j'ai essayé mais le "UserComments" apparait en binaire et quand j'essaye de le convertir il apparait "UNICODE" ce qui n'est pas vraiment mon commentaire...
Ne sachant pas exactement ce que vous voulez faire, il y a la possibilité de se rabattre sur "Copyright" ou "Software" qui ne posent pas de problèmes , sinon reste la solution d'Orax

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 16:30
par GMH
Moi, j'obtiens de l'hexadécimal :
UserComment=0x005300740020005000610075006C005F004E005F0031003800360030005F003000300032000D000A

Si je le convertis avec un convertisseur en ligne, je n'obtiens pas la valeur que j'ai entrée dans le tag UserComments, j'obtiens le nom du fichier-photo !
Je vois aussi que la lettre "s" finale du tag UserComments a disparu !
Que de mystères !

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 17:13
par walkson
Sinon, il y a cette solution qui récupère les propriétés du fichier et donc les commentaires, mots clef, titre etc...
L'ordre donné n'est pas bon ex: les commentaires doivent être 24 et non 14 etc..
ça fait un peu bricolage mais bon...

Code : Tout sélectionner

#include <array.au3>
$path = @DesktopDir & "\IMG\aa.jpg"
$array = _GetExtProperty($path,-1)
_ArrayDisplay($array)
;Ou Msgbox(0,"",$array[24])
;===============================================================================
; Function Name:	GetExtProperty($sPath,$iProp)
; Description:      Returns an extended property of a given file.
; Parameter(s):     $sPath - The path to the file you are attempting to retrieve an extended property from.
;                   $iProp - The numerical value for the property you want returned. If $iProp is is set
;							  to -1 then all properties will be returned in a 1 dimensional array in their corresponding order.
;							The properties are as follows:
;							Name = 0
;							Size = 1
;							Type = 2
;							DateModified = 3
;							DateCreated = 4
;							DateAccessed = 5
;							Attributes = 6
;							Status = 7
;							Owner = 8
;							Author = 9
;							Title = 10
;							Subject = 11
;							Category = 12
;							Pages = 13
;							Comments = 14
;							Copyright = 15
;							Artist = 16
;							AlbumTitle = 17
;							Year = 18
;							TrackNumber = 19
;							Genre = 20
;							Duration = 21
;							BitRate = 22
;							Protected = 23
;							CameraModel = 24
;							DatePictureTaken = 25
;							Dimensions = 26
;							Width = 27
;							Height = 28
;							Company = 30
;							Description = 31
;							FileVersion = 32
;							ProductName = 33
;							ProductVersion = 34
; Requirement(s):   File specified in $spath must exist.
; Return Value(s):  On Success - The extended file property, or if $iProp = -1 then an array with all properties
;                   On Failure - 0, @Error - 1 (If file does not exist)
; Author(s):        Simucal (Simucal@gmail.com)
; Note(s):
;
;===============================================================================
Func _GetExtProperty($sPath, $iProp)
	Local $iExist, $sFile, $sDir, $oShellApp, $oDir, $oFile, $aProperty, $sProperty
	$iExist = FileExists($sPath)
	If $iExist = 0 Then
		SetError(1)
		Return 0
	Else
		$sFile = StringTrimLeft($sPath, StringInStr($sPath, "\", 0, -1))
		$sDir = StringTrimRight($sPath, (StringLen($sPath) - StringInStr($sPath, "\", 0, -1)))
		$oShellApp = ObjCreate ("shell.application")
		$oDir = $oShellApp.NameSpace ($sDir)
		$oFile = $oDir.Parsename ($sFile)
		If $iProp = -1 Then
			Local $aProperty[35]
			For $i = 0 To 34
				$aProperty[$i] = $oDir.GetDetailsOf ($oFile, $i)
			Next
			Return $aProperty
		Else
			$sProperty = $oDir.GetDetailsOf ($oFile, $iProp)
			If $sProperty = "" Then
				Return 0
			Else
				Return $sProperty
			EndIf
		EndIf
	EndIf
EndFunc   ;==>_GetExtProperty

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 17:27
par orax
GMH a écrit :Je vois aussi que la lettre "s" finale du tag UserComments a disparu !
Normalement, il n'y a pas de "s". C'est UserComment dans la norme. http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf

[codeautoit]#include <StringConstants.au3>
$UserComment=Binary("0x005300740020005000610075006C005F004E005F0031003800360030005F003000300032000D000A")
$r=BinaryToString($UserComment,$SB_UTF16BE)
ConsoleWrite($r & @CRLF)[/codeautoit]

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 19:28
par GMH
@walkson
Le code #14 est court et efficace. Récupérer la valeur dans un tableau est simplissime. Je l'adopte.

@orax
Je pensais que le binaire était constitué de 0 et de 1. La valeur contenant des lettres, je pensais qu'il s'agissait d'hexadécimal.

Merci à tous les deux pour vos interventions qui m'ont fait avancer.

Re: [R] Ecrire dans EXIF et Lire EXIF

Posté : lun. 04 juil. 2016 20:31
par orax
Tout à fait, c'est un nombre en hexadécimal. D'après moi, c'est la représentation, en hexadécimal, de données binaires.
Il est plus simple et plus court d'utiliser de l'hexadécimal que du binaire avec juste des 0 et des 1. De plus, l'hexadécimal est adapté pour représenter des données binaires. Par exemple :
0xF = 1111
0xFFFF = 1111 1111 1111 1111 (alors qu'en décimal ça ferait 65 535, ce qui n'est pas un chiffre rond).