Exif

Discuss any general programming issues here
Post Reply
ilbarbax
Posts: 152
Joined: Thu Apr 01, 2010 6:41 pm

Exif

Post by ilbarbax »

Try to read the exif data from a picture but after several attempt still nothing.
The infamous tags are quite obscure to me. I tried to manage them to seek the position in the file but nothing. I tried to convert them in exadeciml/decimal/anything unsuccesfully.

Can you please pointing me to the right way? or even better share some working piece of code (it is not because I'm lazy it is just because I'm stuck since a week and I surrended)

Thanks in advance
Flinx
Posts: 342
Joined: Sun Feb 14, 2021 9:54 am
Location: Germany

Re: Exif

Post by Flinx »

I've never tried this before, but after a quick look at a description , I immediately found the APP1 marker, the following two-byte size specification of the EXIF data and the character string "Exif" in a JPEG file using a hex editor.
It can't be a big problem to read that. How did you try it? Did you mark the search operations with #ENCODING_RAW?
ilbarbax
Posts: 152
Joined: Thu Apr 01, 2010 6:41 pm

Re: Exif

Post by ilbarbax »

Yes i did also that.
But using tag as seek reference for searching trough the file I always obtain a -1 result. I believe that the tag needs to be converted in some way to have a result.
I also looked at the file trough an ex editor finding some explicit references like maker but they are always in a different position. This confirms the fact that the tag is a marker but I can't get it put from the file
Flinx
Posts: 342
Joined: Sun Feb 14, 2021 9:54 am
Location: Germany

Re: Exif

Post by Flinx »

Understand. Wait some minutes, I will try to make an example.
Flinx
Posts: 342
Joined: Sun Feb 14, 2021 9:54 am
Location: Germany

Re: Exif

Post by Flinx »

Here is a semi-finished JPEG parser, based on this documentation. When it has found the EXIF data, it only reports its size. You would have to decode the EXIF structure yourself next, but I hope this helps for now.

Code: Select all

Function p_PrintHex(st$)
	Local Debugstr$=""
	For Local i=0 To StrLen(st$, #ENCODING_RAW)-1
		Debugstr$=Debugstr$ ..FormatStr("%.2X", ByteVal(MidStr(st$,i,1, #ENCODING_RAW),#BYTE)).." "
	Next
	DebugPrint(Debugstr$)
EndFunction

f$="_EXIF-Example.jpg"

Local err= ?OpenFile(1, f$, #MODE_READ)
If err<>#ERR_NONE
	DebugPrint("File not found")
EndIf

While Not Eof(1)
	header$=ReadBytes(1, 2)
	p_PrintHex(header$)
	Switch header$
	Case "\255\216" ;D8
		DebugPrint("Start of Image.")
		Continue
	Case "\255\192" ; C0
		FallThrough
	Case "\255\194" ; C2
		FallThrough
	Case "\255\196" ; C4
		FallThrough
	Case "\255\219" ; DB
		FallThrough
	Case "\255\254" ; FE
		FallThrough
	Case "\255\224" ; E0
		FallThrough
	Case "\255\226"
		FallThrough
	Case "\255\227"
		FallThrough
	Case "\255\228"
		FallThrough
	Case "\255\229"
		FallThrough
	Case "\255\230"
		FallThrough
	Case "\255\231"
		FallThrough
	Case "\255\232"
		FallThrough
	Case "\255\233" ; E9
		; variable size
		Local s=ReadShort(1)
		DebugPrint("size",s)
		Seek(1, s-2, #SEEK_CURRENT)

	Case "\255\225" ; E1 - EXIF
		Local s=ReadShort(1)
		DebugPrint("size of EXIF data:",s)
		Seek(1, s-2, #SEEK_CURRENT)

	Case "\255\208" ; D0
		FallThrough
	Case "\255\209"
		FallThrough
	Case "\255\210"
		FallThrough
	Case "\255\211"
		FallThrough
	Case "\255\212"
		FallThrough
	Case "\255\213"
		FallThrough
	Case "\255\214"
		FallThrough
	Case "\255\215" ; D7
		; no payload

	Case "\255\221" ; DD
		Seek(1, 4, #SEEK_CURRENT)
	Case "\255\217" ; D9
		DebugPrint("End of Image")
	Case "\255\218" ; DA
		DebugPrint("compressed image data follow")
		End()
	EndSwitch
Wend
ilbarbax
Posts: 152
Joined: Thu Apr 01, 2010 6:41 pm

Re: Exif

Post by ilbarbax »

@Flinks

thanks for the effort, but seems not solving my problem. Moreover it is quite slow going trough the whole file.
my test was focused to the extraction of some data such the equipment maker (The scanner/camera manufacturer) or the model (The scanner/camera model name or number.)

please refer to https://www.vcode.no/web/resource.nsf/ii2lnug/642.htm.

anyhow for the moment i will surrende I will keep my mind solving some other problem.

I want to thanks you once more
Flinx
Posts: 342
Joined: Sun Feb 14, 2021 9:54 am
Location: Germany

Re: Exif

Post by Flinx »

What did you expect? I have shown you how to find the EXIF data in the JPEG data blocks. Now you would have to write a similar parser for the EXIF data block found, which moves through the EXIF data structure and extracts the desired tags.
This needs still some work.
And, if it is slow, then maybe I did not catch all JPEG block markers and the parser is out of sync (intended was to skip all uninteresting blocks using the given block size). Of course this is only a quick hack to show you how it should be done, and I did test only with a single JPEG file from my phone.
Flinx
Posts: 342
Joined: Sun Feb 14, 2021 9:54 am
Location: Germany

Re: Exif

Post by Flinx »

To make it easier to understand what happens, I have now added error messages to the JPEG parser and a function call in which you would now have to insert the Exif parser. I don't have enough time for that at the moment. A useful description of the data structure is here. And of course you can find many Exif parsers in different languages on the net that could be ported.
By the way, if this is to be a real parser, then you would certainly not write a switch/case jungle as I have done here, but write the header identifiers and function calls in a table.

Code: Select all

Function p_PrintHex(st$)
	Local Debugstr$=""
	For Local i=0 To StrLen(st$, #ENCODING_RAW)-1
		Debugstr$=Debugstr$ ..FormatStr("%.2X", ByteVal(MidStr(st$,i,1, #ENCODING_RAW),#BYTE)).." "
	Next
	DebugPrint(Debugstr$)
EndFunction

Function p_ParseEXIF(Exif$)
	If CompareStr(LeftStr(Exif$, 6, #ENCODING_RAW),"Exif\0\0",True, #ENCODING_RAW)<>0
		DebugPrint("no EXIF")
		Return(False)
	EndIf

	;*** continue here ***
EndFunction

f$="_EXIF-Example.jpg"

Local err= ?OpenFile(1, f$, #MODE_READ)
If err<>#ERR_NONE
	DebugPrint("File not found")
EndIf

While Not Eof(1)
	header$=ReadBytes(1, 2)
	p_PrintHex(header$)
	Switch header$
	Case "\255\216" ;D8
		DebugPrint("Start of Image.")
		Continue
	Case "\255\192" ; C0
		FallThrough
	Case "\255\194" ; C2
		FallThrough
	Case "\255\196" ; C4
		FallThrough
	Case "\255\219" ; DB
		FallThrough
	Case "\255\254" ; FE
		FallThrough
	Case "\255\224" ; E0
		FallThrough
	Case "\255\226"
		FallThrough
	Case "\255\227"
		FallThrough
	Case "\255\228"
		FallThrough
	Case "\255\229"
		FallThrough
	Case "\255\230"
		FallThrough
	Case "\255\231"
		FallThrough
	Case "\255\232"
		FallThrough
	Case "\255\233" ; E9
		; variable size
		Local s=ReadShort(1)
		DebugPrint("size",s)
		Seek(1, s-2, #SEEK_CURRENT)

	Case "\255\225" ; E1 - EXIF
		Local s=ReadShort(1)
		DebugPrint("size of EXIF data:",s-2)
		Exif$=ReadBytes(1, s-2)
		p_ParseEXIF(Exif$)
		Break(2)

	Case "\255\208" ; D0
		FallThrough
	Case "\255\209"
		FallThrough
	Case "\255\210"
		FallThrough
	Case "\255\211"
		FallThrough
	Case "\255\212"
		FallThrough
	Case "\255\213"
		FallThrough
	Case "\255\214"
		FallThrough
	Case "\255\215" ; D7
		; no payload

	Case "\255\221" ; DD
		Seek(1, 4, #SEEK_CURRENT)

	Case "\255\217" ; D9
		DebugPrint("End of Image")

	Case "\255\218" ; DA
		DebugPrint("compressed image data follow")
		End()
	Default:
		If ByteAsc(header$)=0xFF
			DebugPrint("unknown jpeg header")
		Else
			DebugPrint("out of sync while reading jpeg")
			End()
		EndIf
	EndSwitch
Wend
Post Reply