Sign in to follow this  
Followers 0
Lazycat

Udf For Reading Exif Info

6 posts in this topic

#1 ·  Posted (edited)

Here is my attempt to make UDF for retrieving EXIF info from JPEG's in "right way". Not sure it will work with edited images, and currently it don't work with EXIF's have straight byte order (for ex. all Casio cameras). But it work fine with all images I have from other cameras (7 different models). If you know how you are welcome to add other parameters (Shutter Speed, Aperture etc.) :ph34r:

Example:

$file = FileOpenDialog("Please select file", "", "JPEG files (*.jpg;*.jpeg)");
if @error then Exit
$aExif = _GetEXIFData($file)
if @error then Exit

$aLabel = StringSplit("Date/Time: |Vendor: |Model: |Descr: |Copyright: |Orientation: |Width: |Height: _
|Original Date: |Digitized Date: |Comments: ", "|")

Dim $out = ""

for $i = 0 to UBound($aExif)-1
    $out = $out & $aLabel[$i+1] & $aExif[$i] & @CR
next

MsgBox (0, "EXIF Data", $out)

UDF:

;===============================================================================
;
; Description:    Reads EXIF info
; Parameter(s):  File name
; Requirement(s):   None
; Return Value(s):  On Success - array with EXIF data:
;                      0 - Date & Time
;                      1 - Camera Vendor
;                      2 - Camera Model
;                      3 - Image Description
;                      4 - Copyright
;                      5 - Orientation
;                      6 - Width
;                      7 - Height
;                      8 - Original Date & Time
;                      9 - Digitized Date & Time
;                     10 - User Comments
;                  On Failure empty string and sets @ERROR:
;                      1 - File is not JPEG file
;                      2 - EXIF info not found
; Author(s):        YDY (Kot) <mpc@nm.ru>
; Version:        1.1.00
; Date:          09.08.2004
; Note(s):        None
;
;===============================================================================

Func _GetEXIFData($file)
Local $pos = 3

If not (_FileReadAtOffsetHEX ($file, 1, 2) = "FFD8") Then
    SetError(1); Not JPEG
    Return("")
Endif

$fs = FileGetSize($file)

While $pos < $fs
    $data = _FileReadAtOffsetHEX ($file, $pos, 4)
    If StringLeft($data, 2) = "FF" then; Valid segment start
        $segtype = StringMid($data, 3, 2)
        if $segtype = "E1" then Return(ParseExif($pos))
        $pos = $pos + Dec(StringRight($data, 4)) + 2
    Else
        Exitloop
    Endif
Wend
SetError(2); Segment not found
Return("")
Endfunc

Func ParseExif($exif_offset)
Local $ByteOrder = 0
Local $ic, $idf_offset, $exif[11]
Local $orient = StringSplit("Normal|Mirrored|180░|180░ and mirrored|90░ left and mirrored|_
90░ right|90░ right and mirrored|90░ left", "|")

If _FileReadAtOffsetHEX ($file, $exif_offset+10, 2) = "4D4D" then $ByteOrder = 1

$size = _FileReadAtOffsetHEX ($file, $exif_offset+2, 2)
$exif_offset = $exif_offset + 11 + 9; 9 JFIF header size + 11 - IDF header size, 

For $ic = 0 To 11
    $tag_full = _FileReadAtOffsetHEX($file, $exif_offset + $ic * 12, 12)
    $id = StringLeft($tag_full, 4)
    If $ByteOrder Then $id = StringRight($id, 2) & StringLeft($id, 2)
    Select
        Case $id = "6987"; Exif IDF offset
           $idf_offset = _GetNumValue(StringRight($tag_full, 8), $ByteOrder)
        Case $id = "3201"; DateTime 3201
           $exif[0] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "0F01"; Vendor
           $exif[1] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "1001"; Model
           $exif[2] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "0E01"; ImageDescription
           $exif[3] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "9882"; Copyright
           $exif[4] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "1201"; Orientation
           $value = _GetNumValue(StringRight($tag_full, 8), $ByteOrder)
           If $ByteOrder Then $value = BitShift($value, 16)
           If ($value > 0) and ($value < 9) Then
               $exif[5] = $orient[$value]
           Else
               $exif[5] = "Undefined"
           Endif
    EndSelect
Next

If not ($idf_offset > 0) Then Return($exif)

For $ic = 0 To 23
    $tag_full = _FileReadAtOffsetHEX ($file, $idf_offset + 15 + $ic * 12, 12)
    $id = StringLeft($tag_full, 4)
    If $ByteOrder Then $id = StringRight($id, 2) & StringLeft($id, 2)
    Select
        Case $id = "02A0"; Width
           $exif[6] = _GetNumValue(StringRight($tag_full, 8), $ByteOrder)
        Case $id = "03A0"; Height
           $exif[7] = _GetNumValue(StringRight($tag_full, 8), $ByteOrder)
        Case $id = "0390"; DateTimeOriginal
           $exif[8] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "0490"; DateTimeDigitized
           $exif[9] = _ReadValue($file, $tag_full, $ByteOrder)
        Case $id = "8692"; UserComments
           $exif[10] = _ReadValue($file, $tag_full, $ByteOrder)
    EndSelect
Next
Return($exif)
EndFunc

Func _ReadValue($file, $tag, $ByteOrder)
    Local $count = _GetNumValue(StringMid($tag, 9, 8), $ByteOrder)
    Local $offset = _GetNumValue(StringMid($tag, 17, 8), $ByteOrder)
    Local $tStr = _FileReadAtOffsetHEX ($file, $offset+13, $count)
    Local $oStr = ""
    While StringLen($tStr) > 0
       $oStr = $oStr & Chr(Dec(StringLeft($tStr, 2)))
       $tStr = StringTrimLeft($tStr, 2)
    WEnd
    Return($oStr)
EndFunc

Func _GetNumValue ($input, $ByteOrder)
    Local $tStr = ""
    If $ByteOrder then
        $tStr = $input
    Else
        While StringLen($input) > 0
           $tStr = $tStr & StringRight($input, 2)
           $input = StringTrimRight($input, 2)
        WEnd
    Endif
    Return (Dec($tStr))
EndFunc

Func _FileReadAtOffsetHEX ($file, $offset, $bytes)
    Local $tfile = FileOpen($file, 0)
    Local $tstr = ""
    FileRead($tfile, $offset-1)
    For $i = $offset To $offset + $bytes - 1
        $tstr =  $tstr & Hex(Asc(FileRead($tfile, 1)), 2)
    Next
    FileClose($tfile)
    Return ($tstr)
Endfunc
Edited by Kot

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Code updated, now UDF works fine with EXIF's have Motorola byte order (for ex. Casio). Also EXIF segment searching is more robust. But it still return wrong info from edited images - I have no idea where the prob lays :(

I'll also try to add more EXIF parameters support :ph34r:

Edited by Kot

Share this post


Link to post
Share on other sites

I have found a bug in the ParseExif function. muttley

You use the $file variable but is not defined in the list of parameter of ParseExif function.

To fix it, retype function declaration :

Func ParseExif($file, $exif_offset)

and to call it in the _GetEXIFData function :

if $segtype = "E1" then Return(ParseExif($file,$pos))

Share this post


Link to post
Share on other sites

dmoniac, this is the really ancient script muttley You can try it's successor _ImageGetInfo (link to site in my sig). Seems, object-based solution was available somewere too.

Ok.

Thanks

Share this post


Link to post
Share on other sites

dmoniac, this is the really ancient script :mellow: You can try it's successor _ImageGetInfo (link to site in my sig). Seems, object-based solution was available somewere too.

Hi, Lazy, I was looking your "new" script, but it does not edit or write to the EXIF file. Do you have some clues on that?

Thanks

Jose

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0