Adding and Removing Image Keywords in Aperture 3

Scripting keyword manipulations in Aperture 3 is tricky and unintuitive. Here’s what I’ve learned, along with scripts for adding keywords to and removing them from images.

The parents property of an Aperture keyword is a string containing the path from the keyword up to its topmost parent (as you would see them in the Aperture Keywords HUD or the button editor), separated by tabs. For example, the parents of a keyword Mountains whose parent is Landscape, where Landscape’s parent is the top-level keyword Scene, would be “Landscape\tScene”. Mountains would be the value of the keyword’s name property. The id property is the concatenation of the name, a tab, and parents, unless the keyword is at the top-level of the hierarchy, in which case the id is just the name (and parents is an empty string).

As far as I can tell, the name and parents properties of keywords are redundant since they can be derived from the id.

The Aperture AppleScript dictionary does not provide access to the application’s internal record of keywords, so there is apparently no way to find out all the keywords without getting the keyword of every image in the library and adding each keyword’s ID to a list, if it is not already in the list.

An odd behavior that might trip you up is that if you get the same keyword from each of two images, they are not equal even though their properties have the same values, something I don’t understand. In fact,
the first keyword of anImage != the first keyword of anImage
So, if you want to make a list of all the keywords of some images, compare the ids of the keywords, not the keywords themselves.

Another point of possible confusion: an image may have multiple keywords with the same name but different parents (and, therefore, different ids). However, the name will appear only once wherever the image’s keyword metadata is displayed.

An important note about “make new” in the first handler below: this will add the keyword to Aperture’s internal record of known keywords if it isn’t already there (along with any parents that don’t exist), which you can then see in the keyword HUD. You can make a keyword with the same id repeatedly without its being duplicated in Aperture’s keyword hierarchy.

I found it more convenient to pass keyword ids to these handlers, and have the first one determine the keyword’s name and parents from the id, rather than constructing the id from name and parents paremeters.


(*
Handlers for adding keywords to and removing them from
images in Aperture.

Mitchell L Model, mlm at acm dot org, 2011-09-24

Provides;
	addKeywordToImage(theKeywordID, theImage)
	removeKeywordFromImage(theKeywordID, theImage)
	
	addKeywordToImages(theKeywordID, theImages)
	removeKeywordFromImages(theKeywordID, theImages)
	
	addKeywordToSelectedImages(theKeywordID)
	removeKeywordFromSelectedImages(theKeywordID)
	
*)

to addKeywordToImage(theKeywordName, theKeywordParents, theImage)
	tell application "Aperture"
		set tabpos to the offset of tab in theKeywordID
		if tabpos = 0 then
			set {theName, theParents} to {theKeywordID, ""}
		else
			set {theName, theParents} to ¬
				{rich text 1 thru (tabpos - 1) of theKeywordID, ¬
					rich text (tabpos + 1) thru length of theKeywordID}
			-- I don't know why the compiler adds "rich" to "text"
		end if
		tell theImage to make new keyword with properties ¬
			{id:theKeywordID, name:theName, parents:theParents}
			-- it isn't actually necessary to include the id property
	end tell
end addKeywordToImage

to removeKeywordFromImage(theKeywordID, theImage)
	tell application "Aperture" to ¬
		tell the Image to ¬
			delete (every keyword of theImage whose id is theKeywordID)
end removeKeywordFromImage

to addKeywordToImages(theKeywordID, theImages)
	repeat with n from 1 to count of theImages
		my addKeywordToImage(theKeywordID, item n of theImages)
	end repeat
end addKeywordToImages

to removeKeywordFromImages(theKeywordID, theImages)
	repeat with n from 1 to count of theImages
		my removeKeywordFromImage(theKeywordID, item n of theImages)
	end repeat
end removeKeywordFromImages

to addKeywordToSelectedImages(theKeywordID)
	tell application "Aperture"
		my addKeywordToImages(theKeywordID, selection)
	end tell
end addKeywordToSelectedImages

to removeKeywordFromSelectedImages(theKeywordID)
	tell application "Aperture"
		my removeKeywordFromImages(theKeywordID, selection)
	end tell
end removeKeywordFromSelectedImages

Model: MacBook Pro
AppleScript: 2.0
Browser: Camino
Operating System: Mac OS X (10.6)