Picture data (EXIF Tag)

This forum is for ideas and or code to be contributed for general use.
Post Reply
Message
Author
bborror
Posts: 3
Joined: Mon Dec 27, 2010 3:41 pm

Picture data (EXIF Tag)

#1 Post by bborror »

Stymied. have an app that I need to read the date a .jpeg picture taken so I can use that date in my app. Can't find any xBase, express functions that can help. Any suggestions?
Barry

User avatar
Auge_Ohr
Posts: 1405
Joined: Wed Feb 24, 2010 3:44 pm

Re: Picture data (EXIF Tag)

#2 Post by Auge_Ohr »

bborror wrote:I need to read the date a .jpeg picture
while there a diffenrent Format i´m not shure if this Code fit.
it is allways better to get Structure of Exif Header from Manufacturer of the Camera

Code: Select all

#include 'Directry.ch'			// Directory Array Definitions
#include 'FileIO.ch'			// Low-Level File Access Definitions

#define SOI_MARKER				chr(255) + chr(216)		// FFD8 -- Start Of Image Marker
#define EOI_MARKER				chr(255) + chr(217)		// FFD9 -- End Of Image Marker
#define JFIF_MARKER				chr(255) + chr(224)		// FFE0 -- JFIF ==> JPEG File Interchange Format Marker
#define EXIF_MARKER				chr(255) + chr(225)		// FFE1 -- EXIF ==> Extended (TIFF) Interchange Format Marker
#define JFIF_SIGNATURE			"JFIF" + chr(0)
#define EXIF_SIGNATURE			"Exif" + chr(0) + chr(0)

Procedure Main(cDir)
LOCAL cPath  := iif(cDir == NIL, CurDrive() + ":\" + CurDir(CurDrive()), cDir) + "\"
LOCAL aFiles := Directory(cPath + "*.*")
	Set Alternate To "Picture.lst" ; Set Alternate On
	aFiles := ASort(aFiles, , , {|aFile1, aFile2| aFile1[F_NAME] < aFile2[F_NAME]})
	AEval(aFiles, {|aFile| ListJPEGData(aFile[F_NAME], cPath)})
	Set Alternate To ; Set Alternate Off
return

Procedure ListJPEGData(cFileName, cPath)
LOCAL nLength  := 0		// 2 bytes: Length of Marker Header
LOCAL nMajVers := 0		// 1 bytes: (01)
LOCAL nMinVers := 0		// 1 bytes: (02)
LOCAL nUnits   := 0		// 1 byte: 0 = Aspect Ratio, 1 = DPI (Inches), 2 = DPC (cm)
LOCAL nXSize   := 0		// 2 bytes
LOCAL nYSize   := 0		// 2 bytes
LOCAL nFileLen := 0		// Length of JPEG File
LOCAL nHandle  := 0
LOCAL lValid   := .f.
LOCAL cText    := Space(2)
	QOut('File: "' + cFileName + '"')
	if (nHandle  := FOpen(cPath + cFileName, FO_READ + FO_SHARED)) > 0
		nTextLen := FSeek(nHandle, 0, FS_END) ; FSeek(nHandle, 0, FS_SET)
		if (lValid := FRead(nHandle, @cText, 2) == 2 .and. cText == SOI_MARKER)
			FSeek(nHandle, -2, FS_END)
			if (lValid := FRead(nHandle, @cText, 2) == 2 .and. cText == EOI_MARKER)
				if (nLength := FindJPEGMarker(nHandle, JFIF_MARKER)) > 0
					cText := Space(nLength)
					if FRead(nHandle, @cText, nLength) == nLength
						nOffSet := len(JFIF_SIGNATURE)
						if left(cText, nOffSet) == JFIF_SIGNATURE
							nMajVers := asc(cText[++nOffSet])
							nMinVers := asc(cText[++nOffSet])
							nUnits   := asc(cText[++nOffSet])
							nXSize   := asc(cText[++nOffSet]) * 256 + asc(cText[++nOffSet])
							nYSize   := asc(cText[++nOffSet]) * 256 + asc(cText[++nOffSet])
							QQOut(" -- X/Y " + iif(nUnits == 1 .or. nUnits == 2, "Resolution", "Aspect-Ratio") + ": " + alltrim(str(nXSize)) + "/" + alltrim(str(nYSize)) + iif(nUnits == 1, " DPI", iif(nUnits == 2, " DPC", "")))
						else
							QQOut(' -- Not a valid JFIF file...')
						endif
					else
						QQOut(" -- Invalid/Corrupted JFIF Header...")
					endif
				elseif (nLength := FindJPEGMarker(nHandle, EXIF_MARKER)) > 0
					cText := Space(nLength)
					if FRead(nHandle, @cText, nLength) == nLength
						nOffSet := len(EXIF_SIGNATURE)
						if left(cText, nOffSet) == EXIF_SIGNATURE
							QQOut(" -- Can't (yet) deceipher EXIF Application Markers...")
						else
							QQOut(' -- Not a valid EXIF file...')
						endif
					else
						QQOut(" -- Invalid/Corrupted EXIF Header...")
					endif
				else
					QQOut(" -- Could not find valid (JFIF/EXIF) Application Marker...")
				endif
			endif
		endif
		FClose(nHandle)
	endif
	if .not. lValid
		QQOut(" -- Not a valid JPEG file...")
	endif
return

Function FindJPEGMarker(nHandle, cMarker)
LOCAL nLength := 0
LOCAL cHeader := Space(2)
LOCAL cBuffer := Space(2)
	FSeek(nHandle, 2, FS_SET)
	while FRead(nHandle, @cHeader, 2) == 2 .and. cHeader # EOI_MARKER
		if FRead(nHandle, @cBuffer, 2) == 2
			nLength := asc(cBuffer[1]) * 256 + asc(cBuffer[2]) - 2
			if cHeader == cMarker
				exit
			else
				cHeader := Space(2)
				cBuffer := Space(nLength)
				if FRead(nHandle, @cBuffer, nLength) # nLength
					nLength := 0 ; exit
				endif
				nLength := 0
			endif
		else
			nLength := 0 ; exit
		endif
	enddo
return (nLength)
greetings by OHR
Jimmy

bwolfsohn
Posts: 648
Joined: Thu Jan 28, 2010 7:07 am
Location: Alachua, Florida USA
Contact:

Re: Picture data (EXIF Tag)

#3 Post by bwolfsohn »

It's not xbase or express, but you might want to take a look at jhead
Brian Wolfsohn
Retired and traveling around the country to music festivals in my RV.
OOPS.. Corona Virus, so NOT traveling right now...
http://www.breadmanrises.com
FB travel group: The Breadman Rises

c-tec
Posts: 379
Joined: Tue Apr 20, 2010 1:36 am
Location: SALZBURG/AUSTRIA
Contact:

Re: Picture data (EXIF Tag)

#4 Post by c-tec »

Hello,
I use exiftool.exe, commandline tool you can call with runshell to create a text file with the information. You can also write tags
regards
Rudolf
Rudolf Reinthaler
digital pen & paper systems
http://www.formcommander.net

Post Reply