Page 1 of 1

Picture data (EXIF Tag)

Posted: Tue Jun 14, 2011 12:36 pm
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

Re: Picture data (EXIF Tag)

Posted: Tue Jun 14, 2011 2:54 pm
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)

Re: Picture data (EXIF Tag)

Posted: Tue Jun 14, 2011 6:57 pm
by bwolfsohn
It's not xbase or express, but you might want to take a look at jhead

Re: Picture data (EXIF Tag)

Posted: Sat Mar 23, 2013 5:32 am
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