getting metadata out of an image file

I have a script that downloads images direct from my compact flash card to my laptop whilst also renaming them and fileing them in Filemaker.

I wish to achieve 2 more things.

1 Get metatdata (IPTC data and EXIF) out of images without going through Photoshop. Image events does not handle this.

2 write metatdata to the file using applescript.

Does anybody no whether this is possible.

Model: 11 macs, all my babies
AppleScript: 2.1.1
Browser: Safari 417.9.2
Operating System: Mac OS X (10.4)

If you are happy to use iMagine Photo (free) and Automator, I have written an automator action for iMagine Photo that writes exif information to a text file, delimited by either tabs or commas. The Automator action was written using AppleScript so if it does not quite do what you need I can provide you with the relevant AppleScript code from the action.

The automator action comes with iMagine Photo so all you have to do is copy iMagine Photo to your applications folder and the internal actions will be found by Automator.

You can download iMagine Photo from here:

http://www.yvs.eu.com/downloading.html

Kevin

  1. There is a free command line tool for EXIF read and some write access - I successfully used it in some of my applescripts:

http://www.sentex.net/~mwandel/jhead/

  1. a few weeks ago someone posted a large AppleScript for reading EXIF Tags in the Studio/Xcode Forum (http://bbs.applescript.net/viewforum.php?id=3). As far as I remember it was ‘pure’ Applescript. Maybe it’s worth a look …

Thanks Kevin and Dominik.

I would be interested in the your applescript Kevin. perhaps you can post it. I have not used Imagine Photo yet, I use a mixture of Photoshop, Image events and Filemaker but will give it a whirl.

That command line stuff is well beyond me Dominik but thanks

I think you will be pleased with Imagine Photo; I have used it, and it is an extremely useful utility.

weedinner,

Here is the script as you requested. It is quite complicated so if you need any help let me know.

Craig, thanks for your vote of confidence. I have had very little feedback over the years and have almost no idea over the extent of use of iMagine Photo. I know of a couple of people who are using it to process thousands of images a day but that is about it.

Kevin



-- properties initialized by the script.
property unicodeType : 1
property floatType : 2
property intType : 3
property float3Type : 4
property propDimensionsWidth : 5
property propDimensionsHeight : 6
property propDepth : 7
property propImageCount : 8
property propGraphicType : 9
property propResolutionHorizontal : 10
property propResolutionVertical : 11
property propFileName : 12
property propPath : 13
property propColorSpace : 14
property exifList : missing value
property propertyList : missing value
property titleList : {}
property initLists : false
property colorSpaceEnum : {}
property colorSpaceTextItems : {"rgb", "cmyk", "lab", "gray", "five channels", "six channels", "eight channels", "five colors", "six colors", "seven colors", "eight colors"}

-- delimiters
property theDelimiter : tab -- you can set this here.
property theDelimitersAsText : {"comma", "tab"}
property theDelimiters : {",", tab}

-- output file handling.
property gOverwrite : false -- you can set this here. (false means append)

property isRecursive : true

on run
	InitTheLists()
	set theTitleList to my CreateFullTitleList()
	set newTitleList to choose from list theTitleList with prompt "Choose the data you want:" default items titleList with multiple selections allowed
	if newTitleList is not equal to false then
		set titleList to newTitleList
	end if
	set theFolder to choose folder with prompt "Choose folder of image files: "
	set excelFile to choose file name with prompt "Save results as: " default name "MyImageData.xls"
	try
		set the fileRef to open for access excelFile with write permission
	on error theErr
		display dialog theErr
	end try
	if gOverwrite is equal to true then
		set eof fileRef to 0
	end if
	if (get eof of fileRef) is equal to 0 then
		-- write the titles for each of the columns.
		set AppleScript's text item delimiters to theDelimiter
		write (titleList as text) to the fileRef
		write return to the fileRef starting at (get eof of fileRef) + 1
	end if
	ProcessFilesInFolder(theFolder, fileRef)
	close access the fileRef
end run

on ProcessFilesInFolder(theFolder, fileRef)
	set folderList to list folder theFolder without invisibles
	set subFolderList to {}
	set theFile to theFolder
	repeat with j from 1 to the count of folderList
		if the first character of (item j in folderList) is not "." then
			try
				set theFile to ((theFolder as string) & (item j in folderList)) as alias
				-- display dialog "The path: " & (POSIX path of theFile)
				-- set theFile to ((theFolder as string) & (item j in folderList)) as alias
				-- log theFolder
				if folder of (info for theFile) is true then
					copy theFile to the end of subFolderList
				else
					ProcessFile(theFile, fileRef)
				end if
			on error
				log theFile
			end try
		end if
	end repeat
	if isRecursive is equal to true then
		repeat with i from 1 to the count of subFolderList
			set theSubFolder to item i of subFolderList
			ProcessFilesInFolder(theSubFolder, fileRef)
		end repeat
	end if
end ProcessFilesInFolder

on InitExifList()
	using terms from application "iMagine Photo"
		set exifList to {{exif type:info, exifData:unicodeType, titleText:"Headline"}, {exif type:exif make, exifData:unicodeType, titleText:"Maker"}, {exif type:exif model, exifData:unicodeType, titleText:"Model"}, {exif type:software, exifData:unicodeType, titleText:"Software"}, {exif type:exif creation date, exifData:unicodeType, titleText:"File Creation Date"}, {exif type:orientation, exifData:unicodeType, titleText:"Orientation"}, {exif type:exposure time in seconds, exifData:floatType, titleText:"Exposure Time (sec)"}, {exif type:aperture fNum, exifData:floatType, titleText:"Aperture fNum"}, {exif type:exposure program, exifData:unicodeType, titleText:"Exposure Program"}, {exif type:ISO film speed, exifData:intType, titleText:"ISO Film Speed"}, {exif type:capture date, exifData:unicodeType, titleText:"Capture Date"}, {exif type:captureDateSubSecondTime, exifData:floatType, titleText:"Capture date sub second time"}, {exif type:exposure bias EV, exifData:floatType, titleText:"Exposure Bias"}, {exif type:metering mode, exifData:unicodeType, titleText:"Metering Mode"}, {exif type:light source, exifData:unicodeType, titleText:"Light Source"}, {exif type:flash, exifData:unicodeType, titleText:"Flash"}, {exif type:focal length mm, exifData:floatType, titleText:"Focal Length"}, {exif type:capture width in pixels, exifData:intType, titleText:"Capture Width (pixels)"}, {exif type:capture height in pixels, exifData:intType, titleText:"Capture Height (pixels)"}, {exif type:copyright, exifData:unicodeType, titleText:"Copyright"}, {exif type:artist, exifData:unicodeType, titleText:"Artist"}, {exif type:gps latitude ref, exifData:unicodeType, titleText:"Latitude Reference (N/S)"}, {exif type:gps longitude ref, exifData:unicodeType, titleText:"Longitude Reference (E/W)"}, {exif type:gps latitude, exifData:float3Type, titleText:"Latitude"}, {exif type:gps longitude, exifData:float3Type, titleText:"Longitude"}, {exif type:gps altitude, exifData:floatType, titleText:"Altitude (m)"}, {exif type:gps altitude ref, exifData:intType, titleText:"Altitude Ref"}, {exif type:comment, exifData:unicodeType, titleText:"Comment"}, {exif type:user comment, exifData:unicodeType, titleText:"User Comment"}}
	end using terms from
end InitExifList

on InitPropertyList()
	set propertyList to {{propertyData:propFileName, titleText:"File Name"}, {propertyData:propDimensionsWidth, titleText:"Width (pixels)"}, {propertyData:propDimensionsHeight, titleText:"Height (pixels)"}, {propertyData:propDepth, titleText:"Bit Depth"}, {propertyData:propImageCount, titleText:"Number of Images"}, {propertyData:propGraphicType, titleText:"Graphic Type"}, {propertyData:propResolutionHorizontal, titleText:"Horizontal Resolution (dpi)"}, {propertyData:propResolutionVertical, titleText:"Vertical Resolution (dpi)"}, {propertyData:propPath, titleText:"File path"}, {propertyData:propColorSpace, titleText:"Color Space"}}
	using terms from application "iMagine Photo"
		set colorSpaceEnum to {rgb, cmyk, lab, xyz, gray, fiveChannel, sixChannel, sevenChannel, eightChannel, fiveColor, sixColor, sevenColor, eightColor}
	end using terms from
end InitPropertyList

on InitTheLists()
	if initLists is equal to true then
		return
	end if
	InitPropertyList()
	InitExifList()
	set initLists to true
end InitTheLists

on AddExifDataToFile(thisImporter, fileRef)
	set isExif to 1
	set isProperty to 2
	tell application "iMagine Photo"
		set myFileLoc to file location of thisImporter
		-- log ("The file = " & POSIX path of myFileLoc)
		set theExifData to the exif data of thisImporter
		set propertyData to the properties of thisImporter
		-- log (file name of propertyData)
		set addTab to false
		set theTextToWrite to ""
		repeat with j from 1 to the number of items in titleList
			set theTitle to (item j of the titleList)
			set dataType to 0
			if addTab is false then
				set addTab to true
			else
				set theTextToWrite to theTextToWrite & theDelimiter
			end if
			repeat with i from 1 to the count of exifList
				if theTitle is equal to the titleText of (item i of exifList) then
					set dataType to isExif
					set theResult to (item i of exifList)
					exit repeat
				end if
			end repeat
			if dataType is equal to 0 then
				repeat with i from 1 to the count of propertyList
					if theTitle is equal to the titleText of (item i of propertyList) then
						-- log (theTitle)
						set dataType to isProperty
						set theResult to (item i of propertyList)
						exit repeat
					end if
				end repeat
			end if
			if dataType is equal to isExif then
				-- log (exif type of theResult as string)
				repeat with i from 1 to the count of theExifData
					set exifItem to (item i of the theExifData)
					if the exif type of theResult is equal to the exif type of exifItem then
						if the exifData of theResult is equal to unicodeType then
							set theTextToWrite to theTextToWrite & (exif unicode of exifItem) as string
						else if the exifData of theResult is equal to floatType then
							set theTextToWrite to theTextToWrite & (exif float of exifItem as string)
						else if the exifData of theResult is equal to intType then
							set theTextToWrite to theTextToWrite & (exif int of exifItem as string)
						else if the exifData of theResult is equal to float3Type then
							-- log (exifItem as string)
							set theNumbers to exif float of exifItem
							set theNum to (item 1 of theNumbers) + (item 2 of theNumbers) / 60.0 + (item 3 of theNumbers) / 3600.0
							set theTextToWrite to theTextToWrite & theNum as string
						end if
					end if
				end repeat
			else if dataType is equal to isProperty then
				-- log (propertyData of theResult)
				if propertyData of theResult is equal to propFileName then
					set theTextToWrite to theTextToWrite & ((file name of propertyData) as string)
				else if propertyData of theResult is equal to propDimensionsWidth then
					set natBounds to the natural bounds of propertyData
					set theTextToWrite to theTextToWrite & ((item 3 of the natBounds) as string)
				else if propertyData of theResult is equal to propDimensionsHeight then
					set natBounds to the natural bounds of propertyData
					set theTextToWrite to theTextToWrite & ((item 4 of the natBounds) as string)
				else if propertyData of theResult is equal to propDepth then
					set theTextToWrite to theTextToWrite & ((bit depth of propertyData) as string)
				else if propertyData of theResult is equal to propImageCount then
					set theTextToWrite to theTextToWrite & ((image count of propertyData) as string)
				else if propertyData of theResult is equal to propGraphicType then
					set theTextToWrite to theTextToWrite & ((graphic type of propertyData) as string)
				else if propertyData of theResult is equal to propResolutionHorizontal then
					set theTextToWrite to theTextToWrite & ((item 1 of resolution of propertyData) as string)
				else if propertyData of theResult is equal to propResolutionVertical then
					set theTextToWrite to theTextToWrite & ((item 2 of resolution of propertyData) as string)
				else if propertyData of theResult is equal to propColorSpace then
					set theTextToWrite to theTextToWrite & my GetColorSpaceText(color space of propertyData)
				else if propertyData of theResult is equal to propPath then
					set theFileLocation to file location of thisImporter
					set theTextToWrite to theTextToWrite & ((POSIX path of theFileLocation) as string)
				end if
			else
				display dialog "Undefined type"
			end if
		end repeat
	end tell
	try
		write theTextToWrite to the fileRef starting at (get eof of fileRef) + 1
		write return to the fileRef starting at (get eof of fileRef) + 1
	on error theErr
		display dialog theErr
	end try
end AddExifDataToFile

on GetColorSpaceText(colorSpaceEnumValue)
	-- dd("Color Space Enum: " & colorSpaceEnumValue as text)
	using terms from application "iMagine Photo"
		repeat with i from 1 to the number of items of colorSpaceEnum
			if colorSpaceEnumValue = (item i in colorSpaceEnum) then
				return item i in colorSpaceTextItems
			end if
		end repeat
	end using terms from
	return ""
end GetColorSpaceText

on ProcessFile(theFile, fileRef)
	tell application "iMagine Photo"
		try
			set thisImporter to import graphic theFile
			if the component error of thisImporter is equal to 0 then
				my AddExifDataToFile(thisImporter, fileRef)
				--	log ("Could not import: " & theFile as string)
			end if
		end try
		close thisImporter
		set thisImporter to missing value
	end tell
end ProcessFile

on CreateFullTitleList()
	set theTitleList to {}
	repeat with i from 1 to the count of propertyList
		copy (titleText of (item i of propertyList)) to the end of theTitleList
	end repeat
	repeat with i from 1 to the count of exifList
		copy (titleText of (item i of exifList)) to the end of theTitleList
	end repeat
	return theTitleList
end CreateFullTitleList

Thanks chaps

ktam… I will work throgh this in due course. Its very kind of you to make this available.

Regards to all