3 Jul 2011

Exporting keywords in Lightroom

Posted by dap

I use keywords extensively. In any given photo, I’ll keyword names of people I know, the location, prominent subjects (like birds, trees, a museum), and types of photo (like landscape, nighttime, macro). Take this one:

Dolores Park at Night

I’ve tagged this one with: skyline (a subject), cityscape (a subject and type of photo), dolores-park, mission (the location), night (time of day), and time-lapse (type of photo).

Unlike like popular wisdom, I keyword all the photos I don’t reject, rather than just the ones I’ve selected to actually work on. I do this partly because I’m always a fastidious organizer, but also because I want to build a library of my own stock photography for blog posts and other projects. For that to be useful, it needs to be easy to search through.

When I export photos to my galleries, until recently I’ve deliberately excluded keywords by checking the “minimize embedded metadata” option when exporting. But this has several problems:

  • Leaving out keywords makes it harder for search engines to identify the photos.
  • Minimizing metadata also leaves out camera settings like shutter speed and focal length, which I’d prefer to keep since I like seeing that in other people’s photos.
  • Minimizing metadata also leaves out captions, so I need to manually enter those after exporting.

I could just stop checking this option, but I haven’t been careful about marking some keywords private (i.e. not for export). For example, I have keywords that include addressess of friends’ homes, which I’d rather not include on a picture of their house. But inside Lightroom, there’s no good way to change the “export” setting for multiple keywords, so fixing this would be a very manual process.

I looked around and found other people with the same problem, but it sounds like the only supported way to fix this without going through the 4-click process for each keyword is using the Lightroom SDK. Having never seen Lua or the SDK before, I was able to throw together a little plugin that did what I wanted in a morning. It has no UI, though, so it’s not flexible. It just does exactly what I needed for this case:

  • If a top-level keyword is not exported, all of its child keywords should not be exported. The plugin hides all keywords under a top-level one that’s not exported.
  • If a top-level keyword is exported, most of its child keywords should also be exported. There are some exceptions, so the plugin just logs a message when it finds an exception to this rule.

I haven’t bothered packaging this as a plugin because it’s so specific, but I’ve provided the code below in case anyone needs to do something similar in the future. Caveat: I’m not a Lightroom engineer, and this code may not do what you want, or it may eat your catalog. Always backup your catalog before making changes like this.

--
-- This script is provided for reference only.  Do *not* run this without
-- understanding how it works.  It was written by an amateur.
--
-- This script is intended to hide keywords whose top-level parent keyword is
-- not hidden (marked for export), and warn about keywords which are hidden
-- whose top-level parent is not hidden.  That is, this script iterates the
-- keywords in the active catalog.  For each one, if its top-level parent
-- keyword is marked for export but this keyword is not, the script prints a
-- warning.  If its top-level parent keyword is not marked for export but the
-- keyword itself is, this script unmarks the keyword for export.
--

local LrDialogs = import 'LrDialogs'
local LrLogger = import 'LrLogger'

local log = LrLogger( 'dapLogger' )
log:enable( "logfile" )
log:trace("BEGIN")

-- Track how many keywords we've hidden.
local nhidden = 0;

--
-- Hide the given keyword and its children (recursively).
--
local function fixKeyword(keyword)
	local attrs = keyword:getAttributes()

	if not attrs.includeOnExport then
		log:trace("skipping '" .. keyword:getName() .. "' (already not exported)")
	else
		log:trace("hide keyword '" .. keyword:getName() .. "'")
		keyword:setAttributes({ includeOnExport = false });
		nhidden = nhidden + 1
	end

	for key,child in pairs(keyword:getChildren()) do
		fixKeyword(child)
	end
end

--
-- Check that the given keyword and its children are not hidden (recursively).
--
local function checkKeyword(keyword)
	local attrs = keyword:getAttributes()

	if not attrs.includeOnExport then
		log:trace("surprised to find '" .. keyword:getName() .. "' not exported");
	end

	for key,child in pairs(keyword:getChildren()) do
		checkKeyword(child)
	end
end

--
-- Body of this operation: start an asynchronous task that modifies the catalog
-- as described above.
--
import "LrTasks".startAsyncTask(function ()
	local catalog = import "LrApplication".activeCatalog()
	local allkeywords = catalog:getKeywords()

	catalog:withWriteAccessDo('Hide specific keywords', function ()
		for key,keyword in pairs(allkeywords) do
			local attrs = keyword:getAttributes()
			if not attrs.includeOnExport then
				fixKeyword(keyword)
			else
				checkKeyword(keyword)
			end
		end
	end)

	LrDialogs.message('Hid ' .. nhidden .. ' keywords.', '', 'info')
	log:trace("END")
end)

Tags:

Comments are closed.