I have taken extensivly from others here so here is something back however poor.
I write software (up until now only on windows) for pro photogs. I have had my own exif reader for some years now on windows. I just started looking at porting one of my windows apps to the mac so I fired up the mac I purchased 3 or 4 years ago, bought Tiger and looked around at what was there. I was pretty impressed with where Tiger has taken the mac and not a little impressed with the suite of programming tools available for no extra charge. What a difference. Instead of needing to invest $3K to $5K for development tools they were all there free for the use when purchasing Tiger.
So here is a (not finished) image exif reader I did yesterday and today. It is not done as I suggest but does chase the exif ifd entries and their associated tags. I nearly gave up on this for a time but finally got to a point it actually works. I think it has an issue if there is no exif data and I’ll correct that shortly.
The real point of this is to show that applescript can read and use binary data files given a known structure and known values to look for. This reader works for both II and MM byte orders and should work for any tags defined in the main tags list.
This has also not undergone any relook to clean it up. I just got it working. Hope this helps somebody as so much from here has helped me in the last 3 weeks. My powerbook shows up on Tuesday next week - yoohoo. Finally things should perk up in speed. This 800mghz flat panel imac with 512kb of ram is pretty much a dog. I’m used to much faster.
Note that in the mytaglist the four elements are 1) the description of the tag 2) the standard MM order of the tag id 3) my special routine id - you can change this to whatever you like 4) the decimal equivalent of the standard MM order of the tag id - ie 010f in hex = 271 in decimal.
-- KSSCEXIFReader.applescript
-- KSSCEXIFReader
--  Created by gesmith on 3/23/06.
--  Copyright 2006 __MyCompanyName__. All rights reserved.
property myTagList : {¬
	{"Make", "010F", 100, 271}, ¬
	{"Model", "0110", 101, 272}, ¬
	{"Date-Time", "0132", 140, 306}, ¬
	{"Maker Note", "927C", 109, 37500}, ¬
	{"Sub IFD", "8769", 109, 34665}, ¬
	{"ISO", "8827", 13, 34855}, ¬
	{"Jpg Offset", "0201", 18, 513}, ¬
	{"Jpg Byte Count", "0202", 19, 514}, ¬
	{"Compression", "0103", 20, 259}, ¬
	{"Camera Serial Number", "000C", 24, 12}, ¬
	{"Custom Functions", "000F", 25, 15}, ¬
	{"IPTC/NAA", "83BB", 26, 33723}, ¬
	{"Inter Color Profile", "8773", 27, 34675}, ¬
	{"Firmware Version", "0007", 33, 7}, ¬
	{"Camera Owner", "0009", 34, 9}, ¬
	{"Orientation", "0112", 6, 274}, ¬
	{"XRes", "A20E", 14, 41486}, ¬
	{"YRes", "A20F", 15, 41487}, ¬
	{"Width", "0100", 36, 256}, ¬
	{"Height", "0101", 37, 257}, ¬
	{"Main Image Width", "A002", 38, 40962}, ¬
	{"Main Image Height", "A003", 39, 40963}, ¬
	{"Date-Time Digitized", "9003", 141, 36867}, ¬
	{"Aperture Value", "9202", 1, 37378}, ¬
	{"Shutter Speed Value", "9201", 10, 37377}, ¬
	{"Exposure Time", "829A", 3, 33434}, ¬
	{"FNumber", "829D", 4, 33437}, ¬
	{"Subject Distance", "9206", 5, 37382}, ¬
	{"Flash", "9209", 7, 37385}, ¬
	{"Focal Length", "920A", 12, 37386}, ¬
	{"Rows Per Strip", "0116", 28, 278}, ¬
	{"Strip Offset", "0111", 21, 273}, ¬
	{"Strip Byte Count", "0117", 22, 279}, ¬
	{"Photometric Interpretation", "0106", 23, 262}, ¬
	{"Planar Configuration", "011C", 32, 284}, ¬
	{"YRes", "011B", 41, 283}, ¬
	{"XRes", "011A", 42, 282}, ¬
	{"Bits Per Sample", "0102", 43, 258}, ¬
	{"Metering Mode", "9207", 11, 37383}, ¬
	{"Exposure Index", "A215", 0, 41493}, ¬
	{"Exposure Mode", "8822", 16, 34850}, ¬
	{"Exposure Comp", "9204", 17, 37380}, ¬
	{"Interoperability IFD/DCF", "A005", 27, 40965} ¬
		}
property returnTags : {JFIF:false, APP0LengthWithThumb:0, EXIFOffset:0, Motorola:false, theIFDOffsets:{}, DigitizedDateTime:"", CameraMaker:"", CameraModel:"", DateTime:""}
--65498 = ffd9
--65497 = ffd8
property sExt : ""
property theFileToUse : ""
property inFile : missing value
property wFile : missing value
property bMotorola : false
property bIntel : true
property addEntry : {}
property baddEntry : false
property curIFDCount : 0
property myFoundCount : 0
on clicked theObject
	(*Add your script here.*)
	set myFoundCount to 0
	set theFile to (choose file) as string
	DoTheReader(theFile)
	display dialog myFoundCount
end clicked
on DoTheReader(theFile)
	set JFIF of returnTags to false
	set CameraModel of returnTags to ""
	set CameraMaker of returnTags to ""
	set DateTime of returnTags to ""
	set APP0LengthWithThumb of returnTags to 0
	set EXIFOffset of returnTags to 0
	set Motorola of returnTags to false
	set theIFDOffsets of returnTags to {} --initial list of offset and entries
	set DigitizedDateTime of returnTags to ""
	set filePathElements to get_file_path_elements(theFile)
	set sExt to item 4 of filePathElements
	
	if (sExt ≠ "JPG") and (sExt ≠ "THM") and (sExt ≠ "TIF") and (sExt ≠ "RAF") ¬
		and (sExt ≠ "DCR") and (sExt ≠ "CR2") and (sExt ≠ "NEF") and (sExt ≠ "CRW") then
		display dialog "This file type either is not recognized or does not contain exif information"
		return
	end if
	
	set theFileToUse to theFile
	
	if sExt = "CRW" then
		set theFileToUse to (item 1 of filePathElements) & (item 3 of filePathElements) & ".THM"
	end if
	
	try
		set inFile to open for access file theFileToUse
	on error msg
		display dialog "Could Not Open: " & theFile
		return
	end try
	
	set myJFIFsearch to read inFile for 1024 as string --read first 1024 to see if it is a JFIF
	
	if sExt = "JPG" then
		if "JFIF" is in myJFIFsearch then
			set JFIF of returnTags to true
		end if
		set APP0LengthWithThumb of returnTags to read inFile from 5 to 6 as small integer
	end if
	
	set theExifOffset to offset of "II" in myJFIFsearch
	if theExifOffset = 0 then set theExifOffset to offset of "MM" in myJFIFsearch
	if theExifOffset = 0 then
		display dialog "No exif markers found"
		return
	end if
	
	set bMotorola to false
	set bIntel to true
	set sWork to text from character theExifOffset to character (theExifOffset + 1) of myJFIFsearch
	set EXIFOffset of returnTags to theExifOffset
	--motorola of returntags = false means the data is in intel order
	if sWork = "MM" then
		set Motorola of returnTags to true --set to not intel order which is ho first
		set bMotorola to true
		set bIntel to false
	end if
	
	set myJFIFsearch to "" --give the string memory back
	
	if bIntel then
		set lowAddress to fixIntel(theExifOffset + 4, 4)
	else
		set lowAddress to read inFile from theExifOffset + 4 to theExifOffset + 7 as integer --address of first 
	end if
	
	set lowAddress to lowAddress + theExifOffset
	--*
	--* get inital set of IFD entry offset and number of tag entries in each
	--* this list is added to later if we find other ifd pointers in the tags
	--* such as a maker note for example
	--*
	repeat while lowAddress ≠ 0
		if bIntel then
			set numEntries to fixIntel(lowAddress, 2)
		else
			set numEntries to read inFile from lowAddress to lowAddress + 1 as small integer
		end if
		set thisOne to {lowAddress + 2, numEntries}
		set end of theIFDOffsets of returnTags to thisOne
		set lowAddress to lowAddress + (numEntries * 12) + 2
		if bIntel then
			set lowAddress to fixIntel(lowAddress, 4)
		else
			set lowAddress to read inFile from lowAddress to lowAddress + 3 as integer --get address offset of next ifd
		end if
		if lowAddress ≠ 0 then
			set lowAddress to lowAddress + theExifOffset --must add original offset for real file offset
		end if --display dialog lowAddress
	end repeat
	if (count of theIFDOffsets of returnTags) < 1 then
		close access inFile
		if bIntel then
			close access wFile
		end if
		return returnTags
	end if
	set bQuit to false
	set curIFDCount to count of theIFDOffsets of returnTags
	set x to 0
	repeat until bQuit --with x from 1 to count of theIFDOffsets of returnTags
		set x to x + 1
		if x ≤ curIFDCount then
			WalkTheTags(item x of theIFDOffsets of returnTags)
		else
			set bQuit to true
		end if
	end repeat
	close access inFile
end DoTheReader
--*
--* go through all the tags for this ifd
--*
on WalkTheTags(Offsetlist)
	repeat with thisTagEntry from 1 to item 2 of Offsetlist
		set mytagoffset to (thisTagEntry - 1) * 12 --get offset of the next tag
		set currentOffset to (mytagoffset + (item 1 of Offsetlist))
		if bIntel then
			set theTagID to fixIntel(currentOffset, 2)
		else
			set theTagID to read inFile from currentOffset to currentOffset + 1 as small integer
		end if
		--display dialog theTagID
		repeat with tagTblEntry from 1 to count of myTagList
			if item 4 of item tagTblEntry of myTagList = theTagID then
				--display dialog item 1 of item tagTblEntry of myTagList
				set myFoundCount to myFoundCount + 1
				WorkThisTag(tagTblEntry, currentOffset)
				exit repeat
			end if
		end repeat
	end repeat
end WalkTheTags
--*
--* have a recognized tag so get the data from it
--*
on WorkThisTag(tagIndex, tagOffset)
	set tagDesc to item 1 of item tagIndex of myTagList
	set tagRout to item 3 of item tagIndex of myTagList
	set tagID to item 4 of item tagIndex of myTagList
	set theDataAddress01 to 0
	set theDataAddress02 to 0
	set theDataValue to 0
	set theDataValueString to ""
	
	if bIntel then
		set tagDataType to fixIntel(tagOffset + 2, 2)
	else
		set tagDataType to read inFile from tagOffset + 2 for 2 as small integer
	end if
	
	if bIntel then
		set theDataLength to fixIntel(tagOffset + 4, 4)
	else
		set theDataLength to read inFile from tagOffset + 4 for 4 as integer
	end if
	
	if tagDataType = 1 then
		--unsigned byte
	else if tagDataType = 2 then
		--ascii string
		if bIntel then
			set theDataAddress01 to fixIntel(tagOffset + 8, 4)
		else
			set theDataAddress01 to read inFile from tagOffset + 8 for 4 as integer
		end if
		set theDataAddress01 to theDataAddress01 + (EXIFOffset of returnTags)
	else if (tagDataType = 3) or (tagDataType = 8) then
		--unsigned short
		
		if bIntel then
			set theDataValue to fixIntel(tagOffset + 8, 2)
		else
			set theDataValue to read inFile from tagOffset + 8 for 2 as small integer
		end if
		set theDataValueString to theDataValue as string
	else if (tagDataType = 4) or (tagDataType = 9) then
		--unsigned long (offset address)
		if bIntel then
			set theDataAddress01 to fixIntel(tagOffset + 8, 4)
		else
			set theDataAddress01 to read inFile from tagOffset + 8 for 4 as integer
		end if
		set theDataAddress01 to theDataAddress01 + (EXIFOffset of returnTags)
	else if (tagDataType = 5) or (tagDataType = 10) then
		--unsigned rational
		if bIntel then
			set theDataAddress02 to fixIntel(tagOffset + 8, 4)
		else
			set theDataAddress02 to read inFile from tagOffset + 8 for 4 as integer
		end if
		set theDataAddress02 to theDataAddress02 + (EXIFOffset of returnTags)
		if bIntel then
			set theDataAddress01 to fixIntel(tagOffset + 4, 4)
		else
			set theDataAddress01 to read inFile from tagOffset + 4 for 4 as integer
		end if
		set theDataAddress01 to theDataAddress01 + (EXIFOffset of returnTags)
	else if tagDataType = 6 then
		--signed byte
	else if tagDataType = 7 then
		--address and length 
		if bIntel then
			set theDataAddress01 to fixIntel(tagOffset + 8, 4)
			set theDataAddress02 to fixIntel(tagOffset + 4, 4)
		else
			set theDataAddress01 to read inFile from tagOffset + 8 for 4 as integer
			set theDataAddress02 to read inFile from tagOffset + 4 as integer
		end if
		set theDataAddress01 to theDataAddress01 + (EXIFOffset of returnTags)
	end if
	if tagRout = 140 then
		set mystring to read inFile from theDataAddress01 to theDataAddress01 + theDataLength - 2 as string
		set DateTime of returnTags to mystring
	else if tagRout = 100 then
		set mystring to read inFile from theDataAddress01 to theDataAddress01 + theDataLength - 2 as string
		set CameraMaker of returnTags to mystring
	else if tagRout = 101 then
		set mystring to read inFile from theDataAddress01 to theDataAddress01 + theDataLength - 2 as string
		set CameraModel of returnTags to mystring
	else if tagRout = 109 then
		--maker note ifd pointer
		--sub ifd
		if bIntel then
			set numEntries to fixIntel(theDataAddress01, 2)
		else
			set numEntries to read inFile from theDataAddress01 for 2 as small integer
		end if
		set addEntry to {theDataAddress01 + 2, numEntries}
		set end of theIFDOffsets of returnTags to addEntry
		set curIFDCount to curIFDCount + 1
	end if
end WorkThisTag
--*
--* II (intel) values are stored backwards from MM so must turn them around
--*
on fixIntel(myOffset, num)
	set byt0 to read inFile from myOffset for 1
	set byt1 to read inFile from myOffset + 1 for 1
	set val0 to (ASCII number byt0)
	set val1 to (ASCII number byt1)
	if num = 4 then
		set byt2 to read inFile from myOffset + 2 for 1
		set byt3 to read inFile from myOffset + 3 for 1
		set val2 to (ASCII number byt2)
		set val3 to (ASCII number byt3)
		return ((val3 * 16777216) + (val2 * 65536) + (val1 * 256) + val0) as integer
	else
		return ((val1 * 256) + val0) as integer
	end if
	return 0
end fixIntel
--*
--* common routines that have nothing to do with the exif data
--*
on get_file_path_elements(fName)
	set thePathName to fName as string
	if thePathName ends with ":" then
		--no file name present, it's all path
		return {thePathName, "", "", "", (fName as string)} --path,fullfilename(with extension),filenamenoextension,extension
	end if
	if thePathName ends with "/" then
		--no file name present, it's all path
		return {thePathName, "", "", "", (fName as string)} --path,fullfilename(with extension),filenamenoextension,extension
	end if
	set thePathName to strReverse(thePathName)
	set thePath to ""
	set theFullFileName to ""
	set theFileNameNoExtension to ""
	set theExtension to ""
	repeat with x from 1 to (length of thePathName)
		if item x of thePathName = ":" then
			set thePath to strReverse(text from character x to end of thePathName)
			set theFileName to (text from character 1 to character (x - 1) of thePathName)
			exit repeat
		else if item x of thePathName = "/" then --work --for either
			set thePath to strReverse(text from character x to end of thePathName)
			set theFileName to (text from character 1 to character (x - 1) of thePathName)
			exit repeat
		end if
	end repeat
	if theFileName ≠ "" then set theFullFileName to strReverse(theFileName)
	if length of theFileName < 2 then
		return {thePath, theFullFileName, theFullFileName, "", (fName as string)} --no extension to return
	end if
	set baseExt to ""
	repeat with idx from 1 to (length of theFileName)
		if (text item idx of theFileName = ".") then
			set baseExt to strReverse(text from character 1 to character (idx - 1) of theFileName)
			set theFileNameNoExtension to strReverse(text from character (idx + 1) to end of theFileName)
			return {thePath, theFullFileName, theFileNameNoExtension, baseExt, (fName as string)}
		end if
	end repeat
	return {thePath, theFullFileName, theFullFileName, "", (fName as string)}
	--set dirStr to "dirname " & fName
	--return do shell script dirStr
end get_file_path_elements
on strReverse(iText)
	if length of iText < 2 then
		return iText
	end if
	set reversedText to ""
	repeat with x from (length of iText) to 1 by -1
		set reversedText to reversedText & item x of iText
	end repeat
	return reversedText
	--return reverse of (iText's text items)
end strReverse
on get_f_as_alias(f) --this shoud work for strings (in both HFS & POSIX paths), file specs, aliases 
	try
		return (f as alias)
	on error
		try
			return (f as POSIX file) as alias
		on error
			return false
		end try
	end try
end get_f_as_alias
--if bIntel then
--	set wFileName to ((path to temporary items folder as string) & "wFile.bin")
--	set wFile to open for access file wFileName with write permission
--end if