Basic Read of EXIF data

You can post your code snippets here for others to use and learn from
Post Reply
User avatar
Redlion
Posts: 127
Joined: Sun Jul 10, 2011 5:05 am
Location: Perth, Western Australia

Basic Read of EXIF data

Post by Redlion »

Hello All,

Here is a proof of concept code for reading EXIF information from Jpeg images. It is a bit long winded as not all image tags follow the EXIF standard so I wanted to be able to show the raw data as well as the decoded tag info.

There is still a lot to do, I would like to be able to edit a tag so I can develop my Image database ( I would like to be able to search images for locations (GPS) or info I have embedded into the image so that I could display all the images from Xmas 2024 or all pictures with animals etc.)
I would like to be able to read the info from images taken on my mobile phone but I have a few other thing to get right first. ( if anyone has already done that please let me know. )

The Preference file is just a text file with the name of the directory where your images are stored. ( easy to create )

I know that the math can be improved and that it could be optimised, as I said its a proof of concept. It works on SAM 460 and my PC albeit with some format issues.

Feel free to use it in your project but a bit of credit would be nice.

So here it is, have fun and help me improve it.

Code: Select all

/*** Information about this app *******************************************************************/
@APPTITLE "EXIF Reader"
@APPVERSION "$VER: 1.0.0  (02.01.25)"
@APPCOPYRIGHT "(C) 2025 by Leo den Hollander"
@APPAUTHOR "Leo den Hollander"
@APPDESCRIPTION "EXIF Reader"

;*** EXIF Tag references *************************************************************************************
; https://exiftool.org/TagNames/EXIF.html
; https://www.media.mit.edu/pia/Research/deepview/exif.html
; https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf 

; *** Enable DPI-awareness so that our GUI looks sharp even on high DPI monitors *****************************
@OPTIONS {DPIAware = True}

; ***  Setup ESC to exit program *****************************************************************************
EscapeQuit(True)

; *** This script requires the RapaGUI plugin ****************************************************************
@REQUIRE "RapaGUI", {Link = True}

; ***  Define Global Variables *******************************************************************************
Global Next_OffSet
Global IDFOffSet
Global TName$
Global THex$
Global TDec$

; ***  Setup ESC EXIF tag Table ******************************************************************************
Dim TagData[32]

; *** Setup Graphics for Picture Display *********************************************************************
CreateBrush(2, 400, 300, #BLACK)

; *** Setup GUI **********************************************************************************************
moai.CreateApp([[<?xml version="1.0" encoding="iso-8859-1"?>
<application id="app">
  <window id="mainwin" title=" EXIF Veiwer " margin="0" width="1280" height="768" notify="closerequest">
	<vgroup color="#99D2CB">
	  <vgroup>
		<vspace height="5"/>
		<hgroup>
		  <hspace Width="5"/>
		  <vgroup frame="1">
			<text>Image Files</text>
			<listview Id="files" Notify="Active; DoubleClick">
			  <column Title=" File Name " width="100"/>
			  <column Title=" File Type " width="50"/>
			  <column Title= "File Size " width="70"/>
			</listview>
		  </vgroup>
		  <vspace height="5"/>
		  <vgroup frame="1">
			<text>Registered Tags</text>
			<vgroup weight="80">
			  <listview Id="tags">
				<column Title=" Tag No " width="50"/>
				<column Title=" Tag Name "/>
				<column Title=" Tag Data "/>
			  </listview>
			</vgroup>
			<text>Unregistered Tags ... </text>
			<vgroup weight="20">
			  <listview Id="noinfo">
				<column Title=" Tag Id " width="50"/>
				<column Title=" Tag No "/>
			  </listview>
			</vgroup>
		  </vgroup>
		  <vgroup Frame="1">
			<text>Image</text>
			<hgroup>
			  <hollywood display="1" width="400" Height="300"/>
			</hgroup>
			<vspace height="5"/>
			<text>File Load Tag Data Summary ... </text>
			<texteditor Id="filetype" height="400"></texteditor>
			<vspace height="5"/>
			<hgroup>
			  <button ID="clear"> Clear </button>
			  <hspace Width="5"/>
			  <button ID="preferences"> Preferences </button>
			</hgroup>
		  </vgroup>          
		</hgroup>   
		<vspace height="5"/>        
		</vgroup>    
	  </vgroup> 
  </window>

  <window Id="prefs" Title=" EXIF Veiwer Preferences" Margin="0" Width="700" Height="300" Closegadget="false" 
			  Sizegadget="false" Minimizegadget="false" Maximizegadget="false" Open="false">
	<vgroup color="#99D2CB" frame="1">
	  <hspace width="10"/>
	  <vgroup frame="1">
	   <vspace height="10"/> 
	   <text align="center"> Please select the Default Directory for Startup.</text>
	   <vspace height="10"/> 
		<hgroup> 
		  <hspace width="10"/>
		  <text Weight="10">Default Directory</text>
		  <poppath Id="examine"></poppath>
		  <hspace width="10"/>
		</hgroup> 
		<vspace height="10"/>      
	  </vgroup>   
	  <hgroup frame="1">
		<hspace width="10"/>
		<button ID="save"> Save Directory </button>
		<hspace Width="80"/>
		<button ID="restore"> Restore Directory </button>
		<hspace Width="80"/>
		<button ID="cancel"> Cancel Preferences </button>
		<hspace width="10"/>
		</hgroup> 
		<vspace height="5"/>
	</vgroup> 
  </window> 

</application>
]])

; *** Load Program Preferences *******************************************************************************
Function F_Load_Preferences()
	OpenFile(2, "Exif-Prefs.txt", #MODE_READ)
		Global ProgDir$ = ReadLine(2)
	CloseFile(2)
EndFunction

; *** Load Picture Files *************************************************************************************
Function F_Load_Pictures()
	dd = OpenDirectory(Nil, ProgDir$)
	e = NextDirectoryEntry(dd)
	While e <> Nil
		If e.type = #DOSTYPE_FILE
			If LowerStr(RightStr(e.name, 3)) = "jpg" Or LowerStr(RightStr(e.name, 3)) = "tif"
				moai.DoMethod("files", "Insert", "Bottom", e.name, RightStr(e.name, 3), e.size )
			EndIf
		EndIf
		e = NextDirectoryEntry(dd)
	Wend
	CloseDirectory(dd)
EndFunction

; *** Clear all Lists **********************************************************************************
Function F_Clear_All()
	moai.DoMethod("filetype", "Clear")
	moai.DoMethod("tags", "Clear")
	moai.DoMethod("noinfo", "Clear")
	DisplayBrush(2, 0, 0)
EndFunction

; *** Get Tag Name ***************************************************************************
Function Check_Tag()
  Switch TagNo
	Case 270
	  TagName = " Description: "
	  F_Get_2()
	Case 271
	  TagName =  " Make: "
	  F_Get_2()
	Case 272
	  TagName = " Model: "
	  F_Get_2()
	Case 273
	  TagName = " Strip Offsets: "
	  F_Get_2()
	Case 274
	  TagName =  " Orientation: "
	  TagData[0] = " Unknown" 
	  TagData[1] = " Horizontal (normal)" 
	  TagData[2] = " Mirror horizontal" 
	  TagData[3] = " Rotate 180" 
	  TagData[4] = " Mirror vertical" 
	  TagData[5] = " Mirror horizontal and rotate 270 CW" 
	  TagData[6] = " Rotate 90 CW"
	  TagData[7] = " Mirror horizontal and rotate 90 CW" 
	  TagData[8] = " Rotate 270 CW"
	  A$ = TagData[Dat]
	Case 277
	  TagName = " Sample Per Pixel: "
	  F_Get_2()
	Case 278
	  TagName = " Rows per Strip: "
	  F_Get_2()
	Case 282
	  TagName = " Res X: "
	  F_Get_5()
	Case 283
	  TagName = " Res Y: "
	  F_Get_5()
	Case 296
	  TagName = " Res-Units: "
	  TagData[0] = " Unknown" 
	  TagData[1] = " None" 
	  TagData[2] = " inches" 
	  TagData[3] = " cm"
	  A$ = TagData[Dat]
	Case 305
	  TagName = " CreatorTool: "
	  F_Get_2()
	Case 306
	  TagName = " ModifyDate: "
	  F_Get_2()
	Case 531
	  TagName = " YCbCrPositioning: "
	  TagData[0] = " Unknown"
	  TagData[1] = " Centered"
	  TagData[2] = " Co-sited"
	  A$ = TagData[Dat]
	Case 33434
	  TagName = " Exposure Time: "
	  Seek(1, dat + 12)
	  A = 0
	  D = 0
	  B1 = ReadByte(1, #ENCODING_UTF8)
	  B2 = ReadByte(1, #ENCODING_UTF8)
	  B3 = ReadByte(1, #ENCODING_UTF8)
	  B4 = ReadByte(1, #ENCODING_UTF8)
	  C1 = ReadByte(1, #ENCODING_UTF8)
	  C2 = ReadByte(1, #ENCODING_UTF8)
	  C3 = ReadByte(1, #ENCODING_UTF8)
	  C4 = ReadByte(1, #ENCODING_UTF8)
	  If ByteChr(P12) .. ByteChr(P13) = "MM"
		A = (B1*1024) + (B2*512) + (B3*256) + B4
		D = (C1*1024) + (C2*512) + (C3*256) + C4
		D$ = Val(D/A)
	  Else 
		A = (B4*1024) + (B3*512) + (B2*256) + B1
		D = (C4*1024) + (C3*512) + (C2*256) + C1
		D$ = Val(D/A)
	  EndIf
	  A$ =  "1/" .. D$
	Case 33437
	  TagName = " F Number: "
	  Seek(1, dat + 12)
	  A = 0
	  D = 0
	  B1 = ReadByte(1, #ENCODING_UTF8)
	  B2 = ReadByte(1, #ENCODING_UTF8)
	  B3 = ReadByte(1, #ENCODING_UTF8)
	  B4 = ReadByte(1, #ENCODING_UTF8)
	  C1 = ReadByte(1, #ENCODING_UTF8)
	  C2 = ReadByte(1, #ENCODING_UTF8)
	  C3 = ReadByte(1, #ENCODING_UTF8)
	  C4 = ReadByte(1, #ENCODING_UTF8)
	  A = (B4*1024) + (B3*512) + (B2*256) + B1
	  D = (C4*1024) + (C3*512) + (C2*256) + C1
	  D$ = Val(A/D)
	  A$ =  "1/" .. D$
	Case 34665
	  TagName = " EXIF Sub IFD Offset: "
	  F_Get_4()
	  IDFOffSet = Dat
	Case 34850
	  TagName = " Exposure Program: "
	  TagData[0] = " Not Defined" 
	  TagData[1] = " Manual" 
	  TagData[2] = " Program AE" 
	  TagData[3] = " Aperture-priority AE" 
	  TagData[4] = " Shutter speed priority AE" 
	  TagData[5] = " Creative (Slow speed)" 
	  TagData[6] = " Action (High speed)" 
	  TagData[7] = " Portrait" 
	  TagData[8] = " Landscape" 
	  TagData[9] = " Bulb"
	  A$ = TagData[Dat]
	Case 34855
	  TagName = " ISO Speed Rating: "
	  F_Get_3()
	Case 34864
	  TagName = " Sensitivity Type:"
	  TagData[0] = " Unknown"
	  TagData[1] = " Standard Output Sensitivity"
	  TagData[2] = " Recommended Exposure Index" 
	  TagData[3] = " ISO Speed" 
	  TagData[4] = " Standard Output Sensitivity and Recommended Exposure Index" 
	  TagData[5] = " Standard Output Sensitivity and ISO Speed" 
	  TagData[6] = " Recommended Exposure Index and ISO Speed"
	  TagData[7] = " Standard Output Sensitivity, Recommended Exposure Index and ISO Speed"
	  A$ = TagData[Dat]
	Case 36864
	  TagName = " Exif Version: "
	  F_Get_2()
	Case 36867
	  TagName = " Date Time Original: "
	  F_Get_2()
	Case 36868
	  TagName = " Date Time Digitized: "
	  F_Get_2()
	Case 37121
	  TagName = " Component Config: "
	  TagData[0] = "-"
	  TagData[1] = "Y" 
	  TagData[2] = "Cb" 
	  TagData[3] = "Cr"
	  TagData[4] = "R"
	  TagData[5] = "G" 
	  TagData[6] = "B"
	  A$ = TagData[T8] .. TagData[T9] .. TagData[T10] 
	Case 37122
	  TagName = " Compressed Bit Per Pixel: "
	  F_Get_5()
	  A$ =  A$ .. "/1"
	Case 37377
	  TagName = " Shutter Speed Value: "
	  Seek(1, dat + 12) 
	  A = 0
	  D = 0
	  B1 = ReadByte(1, #ENCODING_UTF8)
	  B2 = ReadByte(1, #ENCODING_UTF8)
	  B3 = ReadByte(1, #ENCODING_UTF8)
	  B4 = ReadByte(1, #ENCODING_UTF8)
	  C1 = ReadByte(1, #ENCODING_UTF8)
	  C2 = ReadByte(1, #ENCODING_UTF8)
	  C3 = ReadByte(1, #ENCODING_UTF8)
	  C4 = ReadByte(1, #ENCODING_UTF8)
	  A = (B4*1024) + (B3*512) + (B2*256) + B1
	  D = (C4*1024) + (C3*512) + (C2*256) + C1
	  D$ = Val(D/A)
	  A$ =  "1/" .. D$
	Case 37378
	  TagName = " Aperture Value: "
	  F_Get_10()
	Case 37379
	  TagName = " Brightness Value: "
	  F_Get_10()
	  A = TrimStr(A, "0", 1)
	  A = TrimStr(A, "0", 0)
	  If Val(A) <> 0
		A$ = "EV" .. A/10
	  Else
		A$ = "EV" .. "0.0"
	  EndIf
	Case 37380
	  TagName = " Exposure Bias Value: "
	  F_Get_10()
	  A = TrimStr(A, "0", 1)
	  A = TrimStr(A, "0", 0)
	  If Val(A) <> 0
		A$ = "EV" .. A/10
	  Else
		A$ = "EV" .. "0.0"
	  EndIf
	Case 37381
	  TagName = " Max Aperture Value: "
	  Seek(1, dat + 12)
	  A = 0
	  D = 0
	  B1 = ReadByte(1, #ENCODING_UTF8)
	  B2 = ReadByte(1, #ENCODING_UTF8)
	  B3 = ReadByte(1, #ENCODING_UTF8)
	  B4 = ReadByte(1, #ENCODING_UTF8)
	  C1 = ReadByte(1, #ENCODING_UTF8)
	  C2 = ReadByte(1, #ENCODING_UTF8)
	  C3 = ReadByte(1, #ENCODING_UTF8)
	  C4 = ReadByte(1, #ENCODING_UTF8)
	  A = (B4*1024) + (B3*512) + (B2*256) + B1
	  D = (C4*1024) + (C3*512) + (C2*256) + C1
	  D$ = Val(A/D)
	  A$ =  "1/" .. D$
	Case 37382
	  TagName = " Subject Distance: "
	  F_Get_3()
	Case 37383
	  TagName = " Metering Mode: "
	  TagData[0] = " Unknown" 
	  TagData[1] = " Average" 
	  TagData[2] = " Center-weighted average" 
	  TagData[3] = " Spot" 
	  TagData[4] = " Multi-spot" 
	  TagData[5] = " Multi-segment" 
	  TagData[6] = " Partial" 
	  TagData[7] = " 255 = Other"
	  If Dat > 7 Then Dat = 7
	  A$ = TagData[Dat]
	Case 37384
	  TagName =  " Light Source: "
	  TagData[0] = " Unknown" 
	  TagData[1] = " Daylight" 
	  TagData[2] = " Fluorescent" 
	  TagData[3] = " Tungsten" 
	  TagData[4] = " Flash"
	  TagData[5] = " Fine Weather: "
	  TagData[6] = " Cloudy" 
	  TagData[7] = " Shade" 
	  TagData[8] = " Daylight Fluorescent" 
	  TagData[9] = " Day White Fluorescent" 
	  TagData[10] = " Cool White Fluorescent"
	  TagData[11] = " White Fluorescent: "
	  TagData[12] = " Warm White Fluorescent" 
	  TagData[13] = " Standard Light A" 
	  TagData[14] = " Standard Light B" 
	  TagData[15] = " Standard Light C" 
	  TagData[16] = " Fluorescent"
	  If Dat > 167 Then Dat = 0
	  A$ = TagData[Dat]
	Case 37385
	  TagName = " Flash: "
	  TagData[0] = " No Flash" 
	  TagData[1] = " Fired" 
	  TagData[5] = " Fired, No Return" 
	  TagData[7] = " Fired, Return" 
	  TagData[8] = " On, Did not Fire"
	  TagData[9] = " On, Fired "
	  TagData[13] = " On, Return not detected" 
	  TagData[15] = " On, return Detected" 
	  TagData[16] = " Off, Did not Fire" 
	  TagData[17] = " Off, Did Not Fire" 
	  TagData[18] = " Auto, Did not Fire"
	  TagData[19] = " Auto, Fired "
	  A$ = TagData[Dat] 
	Case 37386
	   TagName = " Focal Length: "
	   F_Get_5()
	   A$ = A$ .."mm"
	Case 37396
	  TagName = " Subject Area: "
	  Seek(1, dat + 12)
	  A = 0
	  D = 0
	  B1 = ReadByte(1, #ENCODING_UTF8)
	  B2 = ReadByte(1, #ENCODING_UTF8)
	  B3 = ReadByte(1, #ENCODING_UTF8)
	  B4 = ReadByte(1, #ENCODING_UTF8)
	  C1 = ReadByte(1, #ENCODING_UTF8)
	  C2 = ReadByte(1, #ENCODING_UTF8)
	  C3 = ReadByte(1, #ENCODING_UTF8)
	  C4 = ReadByte(1, #ENCODING_UTF8)
	   A$ = (B2 * 256) + B1..","..(B4 * 256) + B3..","..(C2 * 256) + C1..","..(C4 * 256) + C3
	Case 40960
	  TagName = " Flash Pix Version: "
	  F_Get_7()
	Case 40961
	  TagName = " Colour Space: "
	  TagData[0] = " Unknown "
	  TagData[1] = " sRGB "
	  A$ = TagData[Dat]
	Case 40962
	  TagName = " Exif Image Width: "
	  A$ = Dat
	Case 40963
	  TagName = " Exif Image Height: "
	  A$ = Dat
	Case 40964
	  TagName = " Related Sound File: "
	  F_Get_2()
	Case 40965
	  TagName = " Exif Interoperablity Offset: "
	  F_Get_4()
	Case 41486
	  TagName = " Focal Plane X Resolution: "
	Case 41487
	  TagName = " Focal Plane Y Resolution: "
	Case 41488
	  TagName = " Focal plane Resolution Unit: "
	  TagData[0] = " None" 
	  TagData[1] = " inches" 
	  TagData[2] = " cm" 
	  TagData[3] = " mm" 
	  TagData[4] = " um"
	  A$ = TagData[Dat]
	Case 41495
	  TagName = " Sensing Method: "
	  TagData[0] = " Not defined" 
	  TagData[1] = " One-chip color area" 
	  TagData[2] = " Two-chip color area" 
	  TagData[3] = " Three-chip color area" 
	  TagData[4] = " Color sequential area" 
	  TagData[5] = " Trilinear"
	  TagData[6] = " Color sequential linear"
	  A$ = TagData[Dat]
	Case 41728
	  TagName = " File Source: "
	  TagData[0] = " Unknown" 
	  TagData[1] = " Film Scanner" 
	  TagData[2] = " Reflection Film Camera"
	  TagData[3] = " Digital Camera" 
	  If ByteChr(P12) .. ByteChr(P13) = "MM"
		Dat = Val((T9 * 256) + T8) 
	  EndIf
	  A$ = TagData[Dat]
	Case 41729
	  TagName = " Scene Type: "
	  TagData[0] = " Unknown" 
	  TagData[1] = " Directly Photographed"
	  If ByteChr(P12) .. ByteChr(P13) = "MM"
		Dat = Val((T9 * 256) + T8) 
	  EndIf
	  A$ = TagData[Dat]
	Case 41985
	  TagName = " Custom Rendered:"
	  TagData[0] =  " Unknown"
	  TagData[1] =  " Custom Process"
	  TagData[2] =  " Custom "
	  A$ = TagData[Dat]
	Case 41986
	  TagName = " Exposuer Mode:"
	  TagData[0] = " Auto"
	  TagData[1] = " Manual"
	  TagData[2] = " Auto Bracket"
	  A$ = TagData[Dat]
	Case 41987
	  TagName = " White balance:"
	  TagData[0] = " Auto"
	  TagData[1] = " Manual"
	  A$ = TagData[Dat]
	Case 41988
	  TagName = " Digital Zoom Ratio:"
	  Seek(1, dat + 12) 
	  A = 0
	  D = 0
	  B1 = ReadByte(1, #ENCODING_UTF8)
	  B2 = ReadByte(1, #ENCODING_UTF8)
	  B3 = ReadByte(1, #ENCODING_UTF8)
	  B4 = ReadByte(1, #ENCODING_UTF8)
	  C1 = ReadByte(1, #ENCODING_UTF8)
	  C2 = ReadByte(1, #ENCODING_UTF8)
	  C3 = ReadByte(1, #ENCODING_UTF8)
	  C4 = ReadByte(1, #ENCODING_UTF8)
	  A = (B4*1024) + (B3*512) + (B2*256) + B1
	  D = (C4*1024) + (C3*512) + (C2*256) + C1
	  D$ = Val(D)
	  A$ =  "0/" .. D$
	Case 41989
	  TagName = " Focal Length (35 mm Format):"
	  F_Get_3()
	  A$ = A$ .. "mm"
	Case 41990
	  TagName = " Scene Capture Type:"
	  TagData[0] = " Standard"
	  TagData[1] = " Landscape"
	  TagData[2] = " Portrait"
	  TagData[3] = " Night"
	  TagData[4] = " Other"
	  A$ = TagData[Dat]
	Case 41991
	  TagName = " Gain Control:"
	  TagData[0] = " None:"
	  TagData[1] = " Low gain up"
	  TagData[2] = " High gain up"
	  TagData[3] = " Low gain down"
	  TagData[4] = " High gain down"
	  A$ = TagData[Dat]
	Case 41992
	  TagName = " Contrast:"
	  TagData[0] = " Normal"
	  TagData[1] = " Low"
	  TagData[2] = " High"
	  A$ = TagData[Dat]
	Case 41993
	  TagName = " Saturation:"
	  TagData[0] = " Normal"
	  TagData[1] = " Low"
	  TagData[2] = " High"
	  A$ = TagData[Dat]
	Case 41994
	  TagName = " Sharpness:"
	  TagData[0] = " Normal"
	  TagData[1] = " Soft"
	  TagData[2] = " Hard"
	  A$ = TagData[Dat]
	Case 41995
	  TagName = " Device Setting Description:"
	Case 41996
	  TagName = " Subject Distance Range:"
	  TagData[0] = " Unknown"
	  TagData[1] = " Macro"
	  TagData[2] = " Close"
	  TagData[3] = " Distant"
	  A$ = TagData[Dat]
	Case 42016
	  TagName = " Image Unique ID:"
	Case 42032
	  TagName = " Owner Name:"
	Case 42033
	  TagName = " Body Serial Number:"
	Case 42034
	  TagName = " Lens Info:"
	Case 42035
	  TagName = " Lens Make:"
	Case 42036
	  TagName = " Lens Model:"
	Case 42037
	  TagName = " Lens Serial Number:"
	Case 42038
	  TagName = " Image Title:"
	Case 42039
	  TagName = " Photgrapher :"
	Case 42040
	  TagName = " Image Editor:"
	Case 50341
	  TagName = " PrintIM OffSet: "
	  F_Get_7()
	Default
	  moai.DoMethod("noinfo", "Insert", "Bottom", HexStr(TagNo), TagNo)
  EndSwitch
  
  If TagName <> ""
	moai.DoMethod("filetype", "Insert", Chr(13) .. "\27bTag " .. HexStr(TagNo) .. " (" .. TagNo .. ") :- " .. TagName$ ..
				"Type: " .. Type .. " Number: " .. Numb .. " Data: " .. Dat, "Bottom") 
	moai.DoMethod("tags", "Insert", "Bottom", TagNo, TagName, A$)
  EndIf
  TagName$ = ""
  A$ = ""       

EndFunction  

; *** Read Tag 2 *****************************************************************************
Function F_Get_2()
	If Numb > 5
	If Numb > 1024 Then Numb = 1024
		Seek(1, dat + 12)
		A$ = ""
		For t = 1 To numb
			B = ReadByte(1, #ENCODING_UTF8)
			B$ = ByteChr(B)
			A$ = A$ .. B$ 
		Next
	Else
		A$ = ByteChr(T8) .. ByteChr(T9) .. ByteChr(T10) .. ByteChr(T11)
	EndIf 
	D$ = A$ 
EndFunction 

; *** Read Tag 3 **********************************************************************************
Function F_Get_3()
	A$ = Dat        
EndFunction 

; *** Read Tag 4 **********************************************************************************
Function F_Get_4()
	A$ = Dat
EndFunction

; *** Read Tag 5 **********************************************************************************
Function F_Get_5()
  Seek(1, dat + 12)
  A = 0
  D = 0
  For Local t = 1 To (numb * 4)
	B = ReadByte(1, #ENCODING_UTF8)
	A = A + B
  Next
  A$ = Val(A)
  For Local t = 1 To (numb * 4)
	C = ReadByte(1, #ENCODING_UTF8)
	D = D + C
  Next
  C$ = Val(D)
  D$ = C$ .. "/" .. A$
EndFunction 

; *** Read Tag 7 **********************************************************************************
Function F_Get_7()
  Seek(1, dat + 12)
  A$ = ""
  AA = 0
  For Local t = 1 To numb
	 B = ReadByte(1, #ENCODING_UTF8)
	 AA = AA + Val(B)
  Next
  A$ = AA
EndFunction

; *** Read Tag Type 10 **********************************************************************************
Function F_Get_10()
	Seek(1, dat + 12)
	A = 0
	For t = 1 To 4
	   B = ReadByte(1, #ENCODING_UTF8)
	   B$ = ByteChr(B)
	   A = A .. B
	Next
	A$ = A
EndFunction

; *** Read EXIF Header Tags **********************************************************************************
Function F_Read_Exif(SelectedFile$)
	Counter = 0
	A = 0
	A$ = ""
	IDFOffSet = 0
	OpenFile(1, SelectedFile$)
		P0 = ReadByte(1) 
		P1 = ReadByte(1) 
		If P0 = 255 And P1 = 216
		  moai.DoMethod("filetype", "insert", "\27bSOI Marker found. " .. HexStr(P0) .. " " .. 
						  HexStr(P1) .. Chr(13), "Bottom") 
		  P2 = ReadByte(1) 
		  P3 = ReadByte(1) 
		  If P2 = 255 And P3 = 225
			moai.DoMethod("filetype", "insert", "\27bAPP1 Marker found. " .. 
						  HexStr(P2) .. " " .. HexStr(P3) .. Chr(13), "Bottom")
			P4 = ReadByte(1) 
			P5 = ReadByte(1) 
			moai.DoMethod("filetype", "insert", " APP1 Marker size :  " .. HexStr(P4) .. " " .. 
					  HexStr(P5) .. Chr(13), "Bottom")
			moai.DoMethod("filetype", "insert", "\27bExif Header Found. " .. Chr(13), "Bottom")
			P6 = ReadByte(1) 
			P7 = ReadByte(1) 
			P8 = ReadByte(1) 
			P9 = ReadByte(1) 
			moai.DoMethod("filetype", "Insert", " " .. ByteChr(P6) .. ByteChr(P7) .. ByteChr(P8) .. 
					  ByteChr(P9) .. " : ", "Bottom")
			moai.DoMethod("filetype", "Insert", " " .. HexStr(P6) .. HexStr(P7) .. HexStr(P8) .. 
					  HexStr(P9) .. Chr(13), "Bottom")
			P10 = ReadByte(1) 
			P11 = ReadByte(1)  
			moai.DoMethod("filetype", "insert", "\27bTIFF Header found. " .. Chr(13), "Bottom")
			counter = 12
			P12 = ReadByte(1) 
			P13 = ReadByte(1) 
			moai.DoMethod("filetype", "insert", " Align format : " .. Chr(P12) .. 
					  Chr(P13) .. " - ", "Bottom")
			If ByteChr(p12)..ByteChr(P13) = "MM"
			  moai.DoMethod("filetype", "Insert", " Motorola Format" .. Chr(13), "Bottom")
			  P14 = ReadByte(1) 
			  P15 = ReadByte(1) 
			  moai.DoMethod("filetype", "insert", " TAG Marker : " ..  P14 .. P15 .. " : " .. 
						  HexStr(P14) .. " " .. HexStr(P15) .. Chr(13), "Bottom")
			  P16 = ReadByte(1) 
			  P17 = ReadByte(1) 
			  Off_H = ReadByte(1) 
			  Off_L = ReadByte(1)
			  moai.DoMethod("filetype", "insert", " Offset to IFD0 : " ..  Off_H .. Off_L .. " : " .. 
						  HexStr(Off_H) .. " " .. HexStr(Off_l) .. Chr(13), "Bottom")
			ElseIf ByteChr(p12) .. ByteChr(P13) = "II"
			  moai.DoMethod("filetype", "Insert", " Intel Format ".. Chr(13), "Bottom")
			  P14 = ReadByte(1) 
			  P15 = ReadByte(1) 
			  moai.DoMethod("filetype", "insert", " TAG Marker : " ..  P15 .. P14 .. " : " .. 
						  HexStr(P15) .. " " .. HexStr(P14) .. Chr(13), "Bottom")
			  Off_L = ReadByte(1) 
			  Off_H = ReadByte(1)               
			  P18 = ReadByte(1) 
			  P19 = ReadByte(1) 
			  moai.DoMethod("filetype", "insert", " Offset to IFD0 : " ..  Off_H .. Off_L .. " : " .. 
						  HexStr(Off_H) .. " " .. HexStr(Off_L) .. Chr(13), "Bottom")
			EndIf
		
			Next_OffSet = Val((Off_H * 256) + Off_L)
			Counter = Counter + Next_OffSet
			Seek(1, Counter)
			moai.DoMethod("filetype", "Insert", Chr(13) .. "\27bIFD Tags:" .. Chr(13), "Bottom")
			If ByteChr(P12) .. ByteChr(P13) = "MM" 
			  NT_H = ReadByte(1) 
			  NT_L = ReadByte(1)           
			ElseIf ByteChr(P12) .. ByteChr(P13) = "II"
			  NT_L = ReadByte(1) 
			  NT_H = ReadByte(1) 
			EndIf
			No_Tags = Val((NT_H * 256) + NT_L)
			moai.DoMethod("filetype", "Insert","\27bNo. of Tags in IFD0 : " .. No_Tags .. 
					   " : \27n" .. HexStr(NT_H) .. HexStr(NT_L) .. Chr(13), "Bottom")
			Counter = Counter + 2

			For NT = 1 To No_Tags
			  T0 = ReadByte(1) 
			  T1 = ReadByte(1) 
			  T2 = ReadByte(1) 
			  T3 = ReadByte(1) 
			  T4 = ReadByte(1) 
			  T5 = ReadByte(1) 
			  T6 = ReadByte(1) 
			  T7 = ReadByte(1)
			  T8 = ReadByte(1) 
			  T9 = ReadByte(1) 
			  T10 = ReadByte(1) 
			  T11 = ReadByte(1)
			  If ByteChr(P12) .. ByteChr(P13) = "MM"
				TagNo = (T0 * 256) + T1 
				Type = Val((T2 * 256) + T3)
				Numb = Val((T6 * 256) + T7)
				Dat = Val((T8 * 256) + T9) + Val((T10 * 256) + T11)
			   ; Dat = Val((T10 * 256) + T11)
			  ElseIf ByteChr(P12) .. ByteChr(P13) = "II"
				TagNo = T0 + (T1 * 256)
				Type = Val(T2 + (T3 * 256))
				Numb = Val(T4 + (T5 * 256))
				Dat = Val(T8 + (T9 * 256))
			  EndIf
			  Check_Tag()
			  Counter = Counter + 12
			  Seek(1, Counter)
			Next
  
			If IDFOffSet > 0
			  F_Read_IFD0()
			EndIf            
			
		  Else
			moai.DoMethod("filetype", "insert", "\27b NO APP1 Marker found. " .. Chr(13), "Bottom")
		  EndIf
		Else
		  moai.DoMethod("filetype", "insert", "\27b NO SOI Marker found. " .. Chr(13), "Bottom")
		EndIf
EndFunction

; *** Read the Tags in IFD0 **********************************************************************
Function F_Read_IFD0()    
	If ByteChr(P12) .. ByteChr(P13) = "MM"
		Seek(1, IDFOffSet + 12)
		NT_H = ReadByte(1) 
		NT_L = ReadByte(1)
		No_Tags =  Val(NT_L + (NT_H * 256)) 
	ElseIf ByteChr(P12) .. ByteChr(P13) = "II"
		Seek(1, IDFOffSet + 12)
		NT_L = ReadByte(1) 
		NT_H = ReadByte(1) 
		No_Tags = Val(NT_L + (NT_H * 256))
	EndIf
	moai.DoMethod("filetype", "Insert",  Chr(13) ..  Chr(13) .. "\27bNo. of Tags in Sub IFD0 : " .. No_Tags .. 
					  " : \27n" .. HexStr(NT_H) .. HexStr(NT_L) .. Chr(13), "Bottom")
	Seek(1, IDFOffSet + 14)
	Counter = IDFOffSet + 14 
	For NT = 1 To No_Tags
	  T0 = ReadByte(1) 
	  T1 = ReadByte(1) 
	  T2 = ReadByte(1) 
	  T3 = ReadByte(1) 
	  T4 = ReadByte(1) 
	  T5 = ReadByte(1) 
	  T6 = ReadByte(1) 
	  T7 = ReadByte(1)
	  T8 = ReadByte(1) 
	  T9 = ReadByte(1) 
	  T10 = ReadByte(1) 
	  T11 = ReadByte(1)

	  If ByteChr(P12) .. ByteChr(P13) = "MM"
		TagNo = (T0 * 256) + T1 
		Type = Val((T2 * 256) + T3)
		Numb = Val((T6 * 256) + T7)
		Dat = Val((T8 * 256) + T9) + Val((T10 * 256) + T11)        
	  ElseIf ByteChr(P12) .. ByteChr(P13) = "II"
		TagNo = T0 + (T1 * 256)
		Type = Val(T2 + (T3 * 256))
		Numb = Val(T4 + (T5 * 256))
		Dat = Val(T8 + (T9 * 256))
	  EndIf
	  
	  Check_Tag()

	  Counter = Counter + 12
	  Seek(1, Counter)
	Next
EndFunction

; *** Read the Tags in PrintIM **********************************************************************
Function F_Read_PrintIM()    
	If ByteChr(P12) .. ByteChr(P13) = "MM"
		Seek(1, PCounter + PrintIMOffSet + 12)
		NT_H = ReadByte(1) 
		NT_L = ReadByte(1)
		No_Tags =  Val(NT_L + (NT_H * 256)) 
	ElseIf ByteChr(P12) .. ByteChr(P13) = "II"
		Seek(1, PCounter + PrintIMOffSet + 12)
		NT_L = ReadByte(1) 
		NT_H = ReadByte(1) 
		No_Tags = Val(NT_L + (NT_H * 256))
	EndIf
	moai.DoMethod("filetype", "Insert", "\27bNo. of Tags in PrintIM IFD : " .. No_Tags .. 
					  " : \27n" .. HexStr(NT_H) .. HexStr(NT_L) .. Chr(13), "Bottom")
	Seek(1, PintIMOffSet + 14)
	PCounter = PrintIMOffSet + 14 

	For NT = 1 To No_Tags
	  T0 = ReadByte(1) 
	  T1 = ReadByte(1) 
	  T2 = ReadByte(1) 
	  T3 = ReadByte(1) 
	  T4 = ReadByte(1) 
	  T5 = ReadByte(1) 
	  T6 = ReadByte(1) 
	  T7 = ReadByte(1)
	  T8 = ReadByte(1) 
	  T9 = ReadByte(1) 
	  T10 = ReadByte(1) 
	  T11 = ReadByte(1)

	  If ByteChr(P12) .. ByteChr(P13) = "MM"
		TagNo = (T0 * 256) + T1 
		Type = Val((T2 * 256) + T3)
		Numb = Val((T6 * 256) + T7)
		Dat = Val((T10 * 1024) + (T11 * 512)) + Val((T8 * 256) + T9) 
	  ElseIf ByteChr(P12) .. ByteChr(P13) = "II"
		TagNo = T0 + (T1 * 256)
		Type = Val(T2 + (T3 * 256))
		Numb = Val(T4 + (T5 * 256))
		Dat = Val(T8 + (T9 * 256)) 
	  EndIf
			
	  F_Get_Tag_Name()

	  moai.DoMethod("filetype", "insert", "\27b NO APP1 Marker found. " .. Chr(13), "Bottom")
	  moai.DoMethod("filetype", "insert", "\27b NO SOI Marker found. " .. Chr(13), "Bottom")
	Next
EndFunction

/***********************************************************************************************************/
/*** RAPAGUI Events ****************************************************************************************/
/***********************************************************************************************************/
Function Rapa_Events(msg)
  
	Switch msg.action
		Case "RapaGUI"
	 
		Switch msg.attribute
			Case "Pressed"
			
				Switch msg.id
					Case "clear"
						F_Clear_All()

					Case "preferences"
					  moai.Set("prefs", "Open", True)
					  moai.Set("examine", "Path", ProgDir$)

					Case "save"
					  ProgDir$ = moai.Get("examine", "Path")
					  OpenFile(2, "Exif-Prefs.txt", #MODE_WRITE)
						WriteLine(2, ProgDir$) 
					  CloseFile(2)
					  moai.DoMethod("Files", "Clear")
					  F_Load_Pictures()
					  moai.Set("prefs", "Open", False)

					Case "restore"
					  moai.Set("examine", "Path", "")
					  moai.Set("examine", "Path", ProgDir$)

					Case "cancel"
					  moai.Set("prefs", "Open", False)
				
				EndSwitch
			Case "Active":
				Switch msg.id
					Case "files"
						Pos = moai.Get("files", "Active")
						Col1$, Col2$, Clo3$ = moai.DoMethod("files", "GetEntry", Pos)                       
				EndSwitch

			Case "DoubleClick":
				Switch msg.id
					Case "files"
						Pos = moai.Get("files", "Active")
						SelectedFile$, Col2$, Col3$  = moai.DoMethod("files", "GetEntry", Pos)
						SelectedFile$ = ProgDir$ .. SelectedFile$
						F_Clear_All()
						F_Read_Exif(SelectedFile$)
						CloseFile(1)
						LoadBrush(1, SelectedFile$)
						DisplayBrush(1, 0, 0, {Width=400, Height=300})

				EndSwitch
				  
			Case "CloseRequest"
				Switch msg.id
					Case "mainwin"
						moai.Set("mainwin", "Open", False)
						End                     
			
				EndSwitch

		EndSwitch
	EndSwitch     
EndFunction

; *** Listen to these events *********************************************************************************
InstallEventHandler({RapaGUI = Rapa_Events})

; *** Program Setup ******************************************************************************************
F_Load_Preferences()
F_Load_Pictures()

; *** Main Loop **********************************************************************************************
Repeat
  WaitEvent
Forever
Cheers
Leo
----------------------------------------------------------------------------------------
Redlion
Sam460 Lite
A4000 A3000 A2000 A1200 A1000 A600 A500 CD32
ilbarbax
Posts: 173
Joined: Thu Apr 01, 2010 6:41 pm

Re: Basic Read of EXIF data

Post by ilbarbax »

Interesting I missed this thread.
In the meantime there have been further evolution'
User avatar
Redlion
Posts: 127
Joined: Sun Jul 10, 2011 5:05 am
Location: Perth, Western Australia

Re: Basic Read of EXIF data

Post by Redlion »

Here is an update, a long time coming but I got there.

I have added GPS EXIF data, it seems to work with my Samsung phone.

Give it a try and let me know if it fails.

Code: Select all

;*** Information about this app *****************************************************************************
@APPTITLE "EXIF Reader"
@APPVERSION "$VER: 3.0.0  (09.08.26)"
@APPCOPYRIGHT "(C) 2026 by Leo den Hollander"
@APPAUTHOR "Leo den Hollander"
@APPDESCRIPTION "EXIF Reader"

;*** EXIF Tag references ************************************************************************************
; https://exiftool.org/TagNames/EXIF.html
; https://www.media.mit.edu/pia/Research/deepview/exif.html
; https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf
 
;*** Enable DPI-awareness so that our GUI looks sharp even on high DPI monitors *****************************
@OPTIONS {DPIAware = True}

;***  Setup ESC to exit program *****************************************************************************
EscapeQuit(True)

;*** This script requires the RapaGUI plugin ****************************************************************
@REQUIRE "RapaGUI", {Link = True}

;*** Create Image display Brush *****************************************************************************
CreateBrush(2, 400, 300, #BLACK)

; ***  Setup EXIF tag Table *********************************************************************************
Dim TagData[32]
Global xvalue$

;*** RapaGUI USER INTERFACE *********************************************************************************
moai.CreateApp([[
<?xml version="1.0" encoding="iso-8859-1"?>
<application id="app">
  <window id="mainwindow" title="JPEG EXIF + GPS Viewer" width="1280" height="1024" margin="0" 
          notify="closerequest">
    <hgroup color="#888888">
      <hspace width="4"/>
      <vgroup weight="20">
        <vgroup frame="true">
          <text fontsize="14" fontstyle="Bold">Image Files</text>
          <listview Id="files" Notify="Active; DoubleClick">
            <column Title=" File Name " width="100"/>
            <column Title=" File Type " width="50"/>
            <column Title= "File Size " width="70"/>
          </listview>
          <text id="defaultdir"> </text>            
        </vgroup> 
        <vgroup frame="true">            
          <vspace height="5"/>
          <hollywood display="1" width="400" Height="300"/>
          <vgroup>
            <text id="filetext"> No image selected </text>
          </vgroup>
        </vgroup>       
        <vspace height="3"/>
      </vgroup>
      <hspace width="4"/>
      <vgroup weight="50">
        <vgroup frame="true">
          <text fontsize="14" fontstyle="Bold"> Image EXIF Tag Details </text>
          <listview Id="tags">
            <column Title=" HEX Tag" width="70"/>
            <column Title=" DEC Tag" width="70"/>
            <column Title=" Tag Name " width="200"/>
            <column Title=" Tag Data " width="250"/>
          </listview>
        </vgroup>
        <vgroup frame="true">
          <hgroup>
            <text id="IFD0tags"> No. of IFD0 Tags = </text>
            <text id="IFD1tags"> No. of IFD1 Tags = </text>
            <text id="GPStags"> No. of GPS Tags = </text>
          </hgroup>
        </vgroup>
        <vspace height="4"/>
      </vgroup>
      <hspace width="3"/>
      <vgroup weight="15">
        <vgroup frame="true">
          <text fontsize="14" fontstyle="Bold"> Unknown Tags </text>
          <texteditor id="unknown" readonly="true" styled="false"> </texteditor>
        </vgroup>
        <vgroup frame="true">
          <vgroup>
            <button id="getdir" tooltip="Re Load Default Directory." fontstyle="Bold" fontsize="12"
                    > Get Default Dir </button>
            <button id="clearbutton" tooltip="Clear the EXIF information." fontstyle="Bold" fontsize="12"
                    > Clear </button>
            <button id="default" tooltip="Set Default Dir" fontstyle="Bold" fontsize="12"
                    > Set Default Dir  </button>
            <button id="quitbutton" tooltip="Quit the application." fontstyle="Bold" fontsize="12"
                    > Quit </button>
          </vgroup>
        </vgroup>
        <vspace height="4"/>
      </vgroup>
      <hspace width="4"/>
    </hgroup>
  </window>
  <window id="defaults" Title=" EXIF Veiwer Default Directory" Margin="0" Width="700" Height="300" 
          Closegadget="false" 
    Sizegadget="false" Minimizegadget="false" Maximizegadget="false" Open="false">
    <hgroup color="#888888">
      <hspace width="4"/>
      <vgroup>
        <vgroup frame="1">
          <vspace height="10"/> 
          <text align="center"> Please select the Default Directory for Startup.</text>
          <vspace height="10"/> 
          <hgroup> 
            <hspace width="10"/>
            <text Weight="10">Default Directory</text>
            <poppath Id="examine"></poppath>
            <hspace width="10"/>
          </hgroup> 
          <vspace height="10"/>      
        </vgroup>   
        <hgroup frame="1">
          <hspace width="10"/>
          <button id="save" tooltip="Save the Default Directory to disk." fontstyle="Bold" fontsize="12"
                  > Save Directory </button>
          <hspace width="80"/>
          <button id="restore" tooltip="Restore Default Directory." fontstyle="Bold" fontsize="12"
                  > Restore Directory </button>
          <hspace width="80"/>
          <button id="cancel" tooltip="Close Default Directry " fontstyle="Bold" fontsize="12"
                  > Cancel </button>
          <hspace width="10"/>
        </hgroup> 
        <vspace height="5"/>
      </vgroup>
      <hspace width="4"/>
    </hgroup> 
  </window> 
</application>
]])

;*** READ UINT 16 Bit ***************************************************************************************
Function F_ReadU16(pos)
  Local B1 = ByteAsc(JPEGData$, pos)
  Local B2 = ByteAsc(JPEGData$, pos + 1)
  If LittleEndian = True
    Return(B1 + B2 * 256)
  Else
    Return(B1 * 256 + B2)
  EndIf
EndFunction

;*** READ UINT 32 Bit ***************************************************************************************
Function F_ReadU32(pos)
  Local B1 = ByteAsc(JPEGData$, pos)
  Local B2 = ByteAsc(JPEGData$, pos + 1)
  Local B3 = ByteAsc(JPEGData$, pos + 2)
  Local B4 = ByteAsc(JPEGData$, pos + 3)
  If LittleEndian = True
    Return(B1 + B2 * 256 + B3 * 65536 + B4 * 16777216)
  Else
    Return(B1 * 16777216 + B2 * 65536 + B3 * 256 + B4)
  EndIf
EndFunction
;*** READ ASCII *********************************************************************************************
Function F_ReadASCII(pos, count)
  Local result$ = ""
  For Local i = 0 To count - 1
    Local c = ByteAsc(JPEGData$, pos + i)
    If c = 0
      Break
    Elseif c = 10
      Break
    EndIf
    result$ = result$ .. Chr(c)
  Next
  Return(result$)
EndFunction

;*** READ RATIONAL ******************************************************************************************
Function F_ReadRational(pos)
  Local numerator = F_ReadU32(pos)
  Local denominator = F_ReadU32(pos + 4)
  If denominator = 0
    Return("0")
  EndIf
  Return(FormatStr("%.4f", numerator / denominator))
EndFunction

;*** READ SIGNED RATIONAL ***********************************************************************************
Function F_ReadSignedRational(pos)
  Local numerator = F_ReadS32(pos)
  Local denominator = F_ReadS32(pos + 4)
  If denominator = 0
    Return("0")
  EndIf
  Return(FormatStr("%.4f", numerator / denominator))
EndFunction
;*** READ SIGNED UINT32 *************************************************************************************
Function F_ReadS32(pos)
  Local n = F_ReadU32(pos)
  If n >= 2147483648
    n = n - 4294967296
  EndIf
  Return(n)
EndFunction

;*** GET VALUE POSITION *************************************************************************************
Function F_GetValuePosition(entry, type, count)
  Local size = F_TypeSize(type)
  Local total = size * count
  If total <= 4
    Return(entry + 8)
  EndIf
  Return(TIFFBase + F_ReadU32(entry + 8))
EndFunction

;*** TIFF TYPE SIZE *****************************************************************************************
Function F_TypeSize(type)
  Switch type
  Case 1
    Return(1)
  Case 2
    Return(1)
  Case 3
    Return(2)
  Case 4
    Return(4)
  Case 5
    Return(8)
  Case 7
    Return(1)
  Case 9
    Return(4)
  Case 10
    Return(8)
  EndSwitch
  Return(1)
EndFunction

;*** READ TIFF VALUE ****************************************************************************************
Function F_ReadValue(entry, type, count)
  Local pos = F_GetValuePosition(entry, type, count)
  Switch type
    Case 1
      If count = 1
        Return(StrStr(ByteAsc(JPEGData$, pos)))
      EndIf
      Local result$ = ""
      For Local i = 0 To count - 1
        If i > 0
          result$ = result$ .. ", "
        EndIf
        result$ = result$ .. StrStr(ByteAsc(JPEGData$, pos + i))
      Next
      Return(result$)

    Case 2
      Return(F_ReadASCII(pos, count))

    Case 3
      If count = 1
        Return(StrStr(F_ReadU16(pos)))
      EndIf
      result$ = ""
      For i = 0 To count - 1
        If i > 0
          result$ = result$ .. ", "
        EndIf
        result$ = result$ .. StrStr(F_ReadU16(pos + i * 2))
      Next
      Return(result$)

    Case 4
      If count = 1
        Return(StrStr(F_ReadU32(pos)))
      EndIf
      result$ = ""
      For i = 0 To count - 1
        If i > 0
          result$ = result$ .. ", "
        EndIf
        result$ = result$ .. StrStr(F_ReadU32(pos + i * 4))
      Next
      Return(result$)

    Case 5
      If count = 1
        Return(F_ReadRational(pos))
      EndIf
      result$ = ""
      For i = 0 To count - 1
        If i > 0
          result$ = result$ .. ", "
      EndIf
      result$ = result$ .. F_ReadRational(pos + i * 8)
      Next
      Return(result$)

      Case 7
      If count = 1
        result$ = ByteAsc(JPEGData$,pos)
        Return(result$)
      Else
        result$ = F_ReadASCII(pos, count)
        Return(result$)
      EndIf

    Case 9
      If count = 1
        Return(StrStr(F_ReadS32(pos)))
      EndIf
      result$ = ""
      For i = 0 To count - 1
        If i > 0
          result$ = result$ .. ", "
        EndIf
      result$ = result$ .. StrStr(F_ReadS32(pos + i * 4))
      Next
      Return(result$)

    Case 10
      If count = 1
        Return(F_ReadSignedRational(pos))
      EndIf
      result$ = ""
      For i = 0 To count - 1
        If i > 0
          result$ = result$ .. ", "
        EndIf
      result$ = result$ .. F_ReadSignedRational(pos + i * 8)
      Next
    Return(result$)

  EndSwitch
  Return("")
EndFunction

;*** PARSE EXIF IFD *****************************************************************************************
Function F_ParseExifIFD(ifdpos)
  moai.DoMethod("tags", "Insert", "Bottom", "", "", "", "")
  moai.DoMethod("tags", "Insert", "Bottom", "=====", "====", "EXIF INFORMATION", "========")
  Local count = F_ReadU16(ifdpos)
  For Local i = 0 To count - 1
    Local entry = ifdpos + 2 + i * 12
    Local tag = F_ReadU16(entry)
    Local type = F_ReadU16(entry + 2)
    Local num = F_ReadU32(entry + 4)
    value$ = F_ReadValue(entry, type, num)
    F_TagName(tag, value$)
    moai.DoMethod("tags", "Insert", "Bottom", HexStr(tag), tag, dat$, value$)
  Next
  moai.Set("IFD1tags", "Text", " No. of IFD1 Tags = " .. Count-1)
EndFunction

; *** Load Program Preferences *******************************************************************************
Function F_Load_Preferences()
  OpenFile(2, "Exif-Prefs.txt", #MODE_READ)
    Global ProgDir$ = ReadLine(2)
  CloseFile(2)
EndFunction

; *** Load Picture Files *************************************************************************************
Function F_Load_Pictures()
  dd = OpenDirectory(Nil, ProgDir$)
  e = NextDirectoryEntry(dd)
  While e <> Nil
    If e.type = #DOSTYPE_FILE
      If LowerStr(RightStr(e.name, 3)) = "jpg" Or LowerStr(RightStr(e.name, 3)) = "tif"
        moai.DoMethod("files", "Insert", "Bottom", e.name, RightStr(e.name, 3), e.size )
      EndIf
    EndIf
    e = NextDirectoryEntry(dd)
  Wend
  CloseDirectory(dd)
EndFunction

; *** Clear all Lists ***************************************************************************************
Function F_Clear_All()
  OutputText$ = ""
  moai.Set("filetext", "Text", "")
  moai.DoMethod("tags", "Clear")
  moai.DoMethod("unknown", "Clear")
  DisplayBrush(2, #CENTER, #CENTER)
EndFunction

; *** Display Image ***************************************************************************************
Function F_Display_Image()
  Local NBW = 400
  Local NBH = 300
  ImageWidth = GetAttribute(#BRUSH, 1, #ATTRWIDTH)
  ImageHeight = GetAttribute(#BRUSH, 1, #ATTRHEIGHT)
  FilePart$ = FilePart(SelectedFile$)
  moai.Set("filetext", "Text", FilePart$)
  If ImageWidth > 400 Or ImageHeight > 300
    Local BW = ImageWidth /400
    Local BH = ImageHeight / 300
    If BW > BH
      NBW = ImageWidth / BW
      NBH = ImageHeight / BW
    ElseIf BW < BH
      NBW = ImageWidth / BH
      NBH = ImageHeight / BH
    EndIf
  EndIf
  ScaleBrush(1, NBW, NBH, Smooth)
  DisplayBrush(1, #CENTER, #CENTER)
EndFunction

;*** LOAD JPEG Image File ***********************************************************************************
Function F_LoadJPEG(SelectedFile$)  
  Local result = OpenFile(1, SelectedFile$, #MODE_READ)
  If result <> 0
    moai.Set("tags", "Text", "ERROR - Could Not open file")
    Return(False)
  EndIf
  JPEGData$ = ReadBytes(1)
  CloseFile(1)
  If StrLen(JPEGData$, #ENCODING_RAW) = 0
    moai.Set("tags", "Text", "ERROR - JPEG is empty")
    Return(False)
  EndIf
  F_FindEXIF()
  Return(True)
EndFunction

;*** FIND EXIF APP1 *****************************************************************************************
Function F_FindEXIF()
  Local File_Length = StrLen(JPEGData$, #ENCODING_RAW)
  If File_Length < 12
    moai.DoMethod("tags", "Insert", "Bottom", "=====", "Error", "JPEG is too small", "=========")
  Return(False)
  EndIf
  If ByteAsc(JPEGData$, 0) <> $FF Or ByteAsc(JPEGData$, 1) <> $D8
    moai.DoMethod("tags", "Insert", "Bottom", "=====", "Error", "File is Not a JPEG" ,"=========")
    Return(False)
  EndIf
  Local pos = 2
  While pos < File_Length - 4
    While pos < File_Length And ByteAsc(JPEGData$, pos) = $FF
      pos = pos + 1
    Wend
    If pos >= File_Length
      Break
    EndIf
    Local marker = ByteAsc(JPEGData$, pos)
    pos = pos + 1
    If marker = $DA
      Break
    EndIf
    If marker = $D9
      Break
    EndIf
    If marker >= $D0 And marker <= $D7
      Continue
    EndIf
    If marker = $01
      Continue
    EndIf
    If pos + 1 >= File_Length
      Break
    EndIf
    Local segmentlength = ByteAsc(JPEGData$, pos) * 256
    segmentlength = segmentlength + ByteAsc(JPEGData$, pos + 1)
    If segmentlength < 2
      Break
    EndIf
    Local segmentstart = pos + 2
    ; APP1 marker.
    ;----------------------------------------------------------------------------------------------
    If marker = $E1
      If segmentlength >= 8
      ; "Exif" = 45 78 69 66 followed by two zero bytes -------------------------------------------
      If ByteAsc(JPEGData$, segmentStart) = $45
        If ByteAsc(JPEGData$, segmentStart + 1) = $78
        If ByteAsc(JPEGData$, segmentStart + 2) = $69
          If ByteAsc(JPEGData$, segmentStart + 3) = $66
          If ByteAsc(JPEGData$,segmentStart + 4) = 0
            If ByteAsc(JPEGData$,segmentStart + 5) = 0
            TIFFBase = segmentStart + 6
            ; TIFF byte order ---------------------------------------------------------------------
            If ByteAsc(JPEGData$, TIFFBase) = $49 And ByteAsc(JPEGData$, TIFFBase + 1) = $49
              LittleEndian = True
            ElseIf ByteAsc(JPEGData$, TIFFBase) = $4D And ByteAsc(JPEGData$,TIFFBase + 1) = $4D
              LittleEndian = False
            Else
              moai.DoMethod("tags", "Insert", "Bottom", "===== ", "ERROR", "Invalid TIFF byte order",
                            "=========")
              Return(False)
            EndIf
            ; TIFF magic number -------------------------------------------------------------------
            If F_ReadU16(TIFFBase + 2) <> 42
              moai.DoMethod("tags", "Insert", "Bottom", "===== ", "ERROR", "Invalid TIFF header",
                            "=========")
              Return(False)
            EndIf
            ; Offset to IFD0 ----------------------------------------------------------------------
            Local firstIFD = F_ReadU32(TIFFBase + 4)
            If firstIFD = 0
              moai.DoMethod("tags", "Insert", "Bottom", "===== ", "ERROR", "No IFD0 found",
                            "=========")
              Return(False)
            EndIf
            ; Parse IFD0 --------------------------------------------------------------------------
            F_ParseIFD0(TIFFBase + firstIFD)
            ; Parse EXIF IFD ----------------------------------------------------------------------
            If ExifIFDOffset <> 0
              F_ParseExifIFD(ExifIFDOffset)
            EndIf
            ; Parse GPS IFD ------------------------------------------------------------------------
            If GPSIFDOffset <> 0
              F_ParseGPSIFD(GPSIFDOffset)
            Else
              moai.DoMethod("tags", "Insert", "Bottom", "", "", "", "")
              moai.DoMethod("tags", "Insert", "Bottom", "===== ", "====", "GPS INFORMATION",
                            "==========")
              moai.DoMethod("tags", "Insert", "Bottom", " ", " ", "No GPS information found", " ")
            EndIf
            Return(True)
            EndIf
          EndIf
          EndIf 
        EndIf
        EndIf
      EndIf
      EndIf
    EndIf
    ; Advance to next JPEG segment ----------------------------------------------------------------
    pos = segmentstart + segmentlength - 2
  Wend
  moai.DoMethod("tags", "Insert", "Bottom", " RESULT", "====", "No EXIF APP1 segment found",
                "=========")
  Return(False)
EndFunction

;*** PARSE IFD0 *********************************************************************************************
Function F_ParseIFD0(ifdpos)
  ExifIFDOffset = 0
  GPSIFDOffset = 0
  moai.DoMethod("tags", "Insert", "Bottom", "=====", "====", "IMAGE INFORMATION", "=========")
  Local count = F_ReadU16(ifdpos)
  For Local i = 0 To count - 1
    Local entry = ifdpos + 2 + i * 12
    Local tag = F_ReadU16(entry)
    Localtype = F_ReadU16(entry + 2)
    Local num = F_ReadU32(entry + 4)
    If tag = $8769
      ExifIFDOffset = TIFFBase + F_ReadU32(entry + 8)
    ElseIf tag = $8825
      GPSIFDOffset = TIFFBase + F_ReadU32(entry + 8)
    Else
      Local value$ = F_ReadValue(entry, type, num)
      F_TagName(tag, value$)
      moai.DoMethod("tags", "Insert", "Bottom", HexStr(tag), tag, dat$, value$)
      xvalue$ = ""
    EndIf
  Next
  moai.Set("IFD0tags", "Text", " No. of IFD0 Tags = " .. Count-1)
EndFunction

;*** PARSE GPS IFD ******************************************************************************************
Function F_ParseGPSIFD(ifdpos)
  Local latitudeRef$ = ""
  Local longitudeRef$ = ""
  Local count = F_ReadU16(ifdpos)
  ; Find latitude and longitude references.
  ;-------------------------------------------------------------
  For Local i = 0 To count - 1
    Local entry = ifdpos + 2 + i * 12
    Local tag = F_ReadU16(entry)
    Local type = F_ReadU16(entry + 2)
    Local num = F_ReadU32(entry + 4)
    If tag = $0001
      Local LatitudeRef$ = F_ReadValue(entry, type, num)
    ElseIf tag = $0003
      Local LongitudeRef$ = F_ReadValue(entry, type, num)
    EndIf
  Next
  moai.DoMethod("tags", "Insert", "Bottom", "", "", "", "")
  moai.DoMethod("tags", "Insert", "Bottom", "=====", "====", "GPS INFORMATION", "=========")
  ; Read GPS tags.
  ;-------------------------------------------------------------
  For i = 0 To count - 1
    entry = ifdpos + 2 + i * 12
    tag = F_ReadU16(entry)
    type = F_ReadU16(entry + 2)
    num = F_ReadU32(entry + 4)
    If tag = $0002
      Local pos = TIFFBase + F_ReadU32(entry + 8)
      Local value$ = F_ReadGPSCoordinate(pos)
      moai.DoMethod("tags", "Insert", "Bottom", HexStr(tag), tag, "GPSLatitude", value$)
      value$ = F_ReadGPSDecimal(pos, latitudeRef$)
      moai.DoMethod("tags", "Insert", "Bottom", "", "", "Latitude Decimal", value$ .. " " .. latitudeRef$)
    ElseIf tag = $0004
      pos = TIFFBase + F_ReadU32(entry + 8)
      value$ = F_ReadGPSCoordinate(pos)
      moai.DoMethod("tags", "Insert", "Bottom", HexStr(tag), tag, "GPSLongitude", value$)
      value$ = F_ReadGPSDecimal(pos, longitudeRef$)
      moai.DoMethod("tags", "Insert", "Bottom", "", "", "Longitude Decimal", value$ .. " " .. longitudeRef$)
    ElseIf tag = $0007
      pos = TIFFBase + F_ReadU32(entry + 8)
      value$ = F_ReadRational(pos)
      value$ = value$ .. ":"
      value$ = value$ .. F_ReadRational(pos + 8)
      value$ = value$ .. ":"
      value$ = value$ .. F_ReadRational(pos + 16)
      moai.DoMethod("tags", "Insert", "Bottom", HexStr(tag), tag, "GPSTimeStamp", value$)
    Else
      value$ = F_ReadValue(entry, type, num)
      gvalue = value$
      F_GPSTagName(tag, gvalue$)
      moai.DoMethod("tags", "Insert", "Bottom", HexStr(tag), tag, dat$, value$)
      gvalue$ = ""
    EndIf
  Next
  moai.Set("GPStags", "Text", " No. of GPS Tags = " .. Count)
EndFunction

;*** GPS COORDINATE *****************************************************************************************
Function F_ReadGPSCoordinate(pos)
  Local degrees = F_ReadRational(pos)
  Local minutes = F_ReadRational(pos + 8)
  Local seconds = F_ReadRational(pos + 16)
  Local result$ = StrStr(degrees)
  result$ = result$ .. " deg "
  result$ = result$ .. StrStr(minutes)
  result$ = result$ .. " min "
  result$ = result$ .. StrStr(seconds)
  result$ = result$ .. " sec"
  Return(result$)
EndFunction

;*** GPS DECIMAL COORDINATE *********************************************************************************
Function F_ReadGPSDecimal(pos, ref$)
  Local degrees = F_ReadU32(pos) / F_ReadU32(pos + 4)
  Local minutes = F_ReadU32(pos + 8) / F_ReadU32(pos + 12)
  Local seconds = F_ReadU32(pos + 16) / F_ReadU32(pos + 20)
  Local decimal = degrees + minutes / 60 + seconds / 3600
  If ref$ = "S" Or ref$ = "W"
    decimal = 0 - decimal
  EndIf
  Return(FormatStr("%.8f", decimal))
EndFunction

;*** EXIF TAG NAME ******************************************************************************************
Function F_TagName(tag, xvalue$)
  Switch tag
    Case $0100
      dat$ = "Image Pixel Width"
  
    Case $0101
      dat$ = "Image Pixel Length"
    
    Case $0102
      dat$ = "Image Pixel Length"
  
    Case $0103
      dat$ = "Image Compresion"
  
    Case $0106
      dat$ = "Image Pixel Length"
  
    Case $010E
      dat$ = "Image Description"
  
    Case $010F
      dat$ = "Make"
  
    Case $0110
      dat$ = "Model"
  
    Case $0112
      TagData = {"Unknown", "Horizontal (normal)", "Mirror horizontal", "Rotate 180",
                 "Mirror vertical", "Mirror horizontal and rotate 270 CW", "Rotate 90 CW",
                 "Mirror horizontal and rotate 90 CW", "Rotate 270 CW"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Orientation"
  
    Case $011A
      Value$ = Val(xvalue$) .. " dpi"
      dat$ = "X Resolution"
  
    Case $011B
      Value$ = Val(xvalue$) .. " dpi"
      dat$ = "Y Resolution"
  
    Case $0128
      TagData = {"Unknown", "None", "inches", "cm"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Resolution Unit"
  
    Case $0131
      dat$ = "Software"
  
    Case $0132
      dat$ = "Date/Time"
  
    Case $013B
      dat$ = "Artist"
  
    Case $0213
      TagData = {"Unknown", " Centered", "Co-sited"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "YCbCrPositioning"
  
    Case $8298
      dat$ = "Copyright"
  
    Case $8769
      dat$ = "Exif IFD Pointer"
  
    Case $8825
      dat$ = "GPS Info IFD Pointer"
  
    Case $829A
      Ex = 1 / Val(value$)
      value$ = "1/" .. Int(Ex) .. " sec"
      dat$ = "Exposure Time"
  
    Case $829D
      value$ = "f 1/" .. TrimStr(xvalue$, "0", True)
      dat$ = "F Number"
    
    Case $8769
      dat$ = " EXIF Sub IDF0 Offset"
  
    Case $8822
      TagData = {"Not Defined", "Manual", "Program AE","Aperture-priority AE", "Shutter speed priority AE", 
                 "Creative (Slow speed)", "Action (High speed)", "Portrait", "Landscape", "Bulb"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Exposure Program"
    
    Case $8825
      dat$ = "GSP Tag IFD"
  
    Case $8827
      value$ = "ISO " .. value$
      dat$ = "ISO"
  
    Case $8830
      TagData = {"Unknown", "Standard Output Sensitivity", "Recommended Exposure Index", "ISO Speed",
                 "Standard Output Sensitivity and Recommended Exposure Index", 
                 "Standard Output Sensitivity and ISO Speed", "Recommended Exposure Index and ISO Speed",
                 "Standard Output Sensitivity, Recommended Exposure Index and ISO Speed"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "SensitivityType"
  
    Case $8831
      dat$ = "Standard Output Sensitivity"
  
    Case $9000
      dat$ = "Exif Version"
  
    Case $9003
      dat$ = "Date Time Original"
  
    Case $9004
      dat$ = "Date Time Digitized"
    
    Case $9010
      dat$ = "Date Time (GMT)"
  
    Case $9011
      dat$ = "Original Time (GMT)"
  
    Case $9101
      TagData = {"-", "Y", "Cb", "Cr", "R", "G", "B"}
        A$ = TagData[T8] .. TagData[T9] .. TagData[T10]
      dat$ = "Components Configuration"
  
    Case $9102
      dat$ = "Compressed Bits Per Pixel"
  
    Case $9201
      dat$ = "Shutter Speed Value"
  
    Case $9202
      value$ = "f 1/" .. TrimStr(xvalue$, "0", True)
      dat$ = "Aperture Value"
  
    Case $9203
      value$ = "EV " .. Val(value$)
      dat$ = "Brightness Value"
  
    Case $9204
      value$ = "EV " .. Val(value$)
      dat$ = "Exposure Bias Value"
  
    Case $9205
      value$ = "f 1/" .. TrimStr(xvalue$, "0", True)
      dat$ = "Max Aperture Value"
  
    Case $9206
      dat$ = "Subject Distance"
  
    Case $9207
      TagData = {"Unknown", "Average", "Center-weighted A Flaverage", "Spot", "Multi-spot", "Multi-segment", 
                 "Partial", "Other"}
      If Val(xvalue$) > 7 Then xvalue$ = "7"
      value$ = TagData[Val(xvalue$)]
      dat$ = "Metering Mode"
  
    Case $9208
      TagData = {"Unknown", "Daylight", "Fluorescent", "Tungsten", "Flash", "Fine Weather", "Cloudy",
                 "Shade", "Daylight Fluorescent", "Day White Fluorescent", "Cool White Fluorescent",
                 "White Fluorescent", "Warm White Fluorescent", "Standard Light A", "Standard Light B", 
                 "Standard Light C", "Fluorescent"}
      If Val(xvalue$) > 16 Then xvalue$ = "0"
      value$ = TagData[Val(xvalue$)]
      dat$ = "Light Source"
  
    Case $9209
      TagData = {"No Flash", "Fired", "", "", "", "Fired, No Return", "", "Fired, Return", "On, Did not Fire",
             "On, Fired", "", "", "", "On, Return not detected", "", "On, return Detected", 
                     "Off, Did not Fire", "Off, Did Not Fire", "Auto, Did not Fire", "Auto, Fired "}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Flash"
  
    Case $920A
      dat$ = "Focal Length"
  
    Case $9214
      dat$ = "Subject Area"
  
    Case $927C
      dat$ = "Maker Note"
  
    Case $9286
      dat$ = "User Comment"
  
    Case $9290
      dat$ = "Sub Sec Time"
  
    Case $9291
      dat$ = "Sub Sec Time Original"
  
    Case $9292
      dat$ = "Sub Sec Time Digitized"
  
    Case $A000
      dat$ = "Flash Pix Version"
  
    Case $A001
      TagData = {"Unknown", "sRGB "}
      value$ = TagData[Val(xvalue$)]
      dat$ = "ColorSpace"
  
    Case $A002
      dat$ = "Pixel X Dimension"
  
    Case $A003
      dat$ = "Pixe lY Dimension"
  
    Case $A004
      dat$ = "Related Sound File"
  
    Case $A005
      dat$ = "Interoperability IFD"
  
    Case $A20E
      dat$ = "Focal Plane X Resolution"
  
    Case $A20F
      dat$ = "Focal Plane Y Resolution"
  
    Case $A210
      TagData = {"None", "inches", "cm", "mm", "um"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Focal Plane Resolution Unit"
  
    Case $A215
      dat$ = "Exposure Index"
    
    Case $A217
      TagData = {"Not defined", "One-chip color area", "Two-chip color area", "Three-chip color area", 
                 "Color sequential area", "Trilinear", "Color sequential linear"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Sensing Method"
    
    Case $A300
      TagData = {"Unknown", "Film Scanner", "Reflection Film Camera", "Digital Camera"}
      value$ = TagData[Val(xvalue$)]    
      dat$ = "File Source"
  
    Case $A301
      TagData = {"Unknown", "Directly Photographed"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Scene Type"
  
    Case $A401
       TagData = {"Unknown", "Custom Process", "Custom"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Custom Rendered"
  
    Case $A402
      TagData = {"Auto", "Manual", "Auto Bracket"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Exposure Mode"
  
    Case $A403
       TagData = {"Auto", "Manual"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "White Balance"
  
    Case $A404
      dat$ = "Digital Zoom Ratio"
  
    Case $A405
      value$ = value$.. "mm"
      dat$ = "Focal Length (35mm)"
  
    Case $A406
      TagData = {"Standard", "Landscape", "Portrait", "Night", "Other"}
      value$ = TagData[Val(xvalue$)]    
      dat$ = "Scene Capture Type"
  
    Case $A407
      TagData = {"None", "Low gain up", "High gain up", "Low gain down", "High gain down"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Gain Control"
  
    Case $A408
      TagData = {"Normal", "Low", "High"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Contrast"
  
    Case $A409
      TagData = {"Normal", "Low", "High"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Saturation"
  
    Case $A40A
      TagData = {"Normal", "Soft", "Hard"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Sharpness"
  
    Case $A40C
      TagData = {"Unknown", "Macro", "Close", "Distant"}
      value$ = TagData[Val(xvalue$)]
      dat$ = "Subject Distance Range"
  
    Case $A420
      dat$ = "Image Unique ID"
    
    Case $C4A5
      dat$ = "PrintIM OffSet"
  EndSwitch
EndFunction

;**** GPS TAG NAME ******************************************************************************************
Function F_GPSTagName(tag, gvalue)
  Switch tag
    Case $0000
      dat$ = "GPS Version ID"
  
    Case $0001
      dat$ = "GPS Latitude Ref"
  
    Case $0002
      dat$ = "GPS Latitude"
  
    Case $0003
      dat$ = "GPS Longitude Ref"
  
    Case $0004
      dat$ = "GPS Longitude"
  
    Case $0005
      dat$ = "GPS Altitude Ref"
  
    Case $0006
      dat$ = "GPS Altitude"
  
    Case $0007
      dat$ = "GPS TimeStamp"
  
    Case $0008
      dat$ = "GPS Satellites"
  
    Case $0009
      dat$ = "GPS Status"
  
    Case $000A
      dat$ = "GPS MeasureMode"
  
    Case $000B
      dat$ = "GPSDOP"
  
    Case $000C
      dat$ = "GPS SpeedRef"
  
    Case $000D
      dat$ = "GPS Speed"
  
    Case $000E
      dat$ = "GPS Track Ref"
  
    Case $000F
      dat$ = "GPS Track"
  
    Case $0010
      dat$ = "GPS Img Direction Ref"
  
    Case $0011
      dat$ = "GPS Img Direction"
  
    Case $0012
      dat$ = "GPS Map Datum"
  
    Case $001D
      dat$ = "GPSDateStamp"
  
    Case $001E
      dat$ = "GPS Differential"
  EndSwitch
EndFunction

;*** RapaGUI EVENT HANDLER **********************************************************************************
Function F_EventHandler(msg)
  Switch msg.action
    Case "RapaGUI"
      Switch msg.attribute
        Case "Pressed"
          Switch msg.id
            Case "getdir"
              moai.DoMethod("files", "Clear")
              F_Clear_All()
              moai.Set("defaultdir", "Text", ProgDir$)
              F_Load_Pictures()

            Case "clearbutton"
              F_Clear_All()
      
            Case "default"
               moai.Set("defaults", "Open", True)
               moai.Set("examine", "Path", ProgDir$)
              
            Case "save"
              ProgDir$ = moai.Get("examine", "Path")
              OpenFile(2, "Exif-Prefs.txt", #MODE_WRITE)
                WriteLine(2, ProgDir$) 
              CloseFile(2)
              moai.DoMethod("Files", "Clear")
              moai.Set("defaults", "Open", False)

            Case "restore"
              moai.Set("examine", "Path", "")
              moai.Set("examine", "Path", ProgDir$)

            Case "cancel"
              moai.Set("defaults", "Open", False)
      
            Case "quitbutton"
              moai.Set("mainwindow", "open", False)
              End

          EndSwitch
        
        Case "DoubleClick":
          Switch msg.id
            Case "files"
              Pos = moai.Get("files", "Active")
              SelectedFile$, Col2$, Col3$  = moai.DoMethod("files", "GetEntry", Pos)
              SelectedFile$ = ProgDir$ .. SelectedFile$
              F_Clear_All()
              LoadBrush(1, SelectedFile$)
              F_Display_Image
              F_LoadJPEG(SelectedFile$)
      
          EndSwitch

        Case "CloseRequest"
          If msg.id = "mainwindow"
            moai.Set("mainwindow", "open", False)
          End
          EndIf
      EndSwitch
   EndSwitch
EndFunction

;*** INSTALL EVENT HANDLER ************************************************************************
InstallEventHandler({RapaGUI = F_EventHandler})

;***  MAIN EVENT LOOP *****************************************************************************
F_Load_Preferences()
moai.Set("defaultdir", "Text", ProgDir$)
F_Load_Pictures()

Repeat
  WaitEvent
Forever
Have fun with it.
Leo
----------------------------------------------------------------------------------------
Redlion
Sam460 Lite
A4000 A3000 A2000 A1200 A1000 A600 A500 CD32
Post Reply