In a previous post, Geocoded Lightroom Web Gallery Plugin – Part 1, I discussed the concept of a geocoded Lightroom plugin for producing Web galleries, outlined what I wanted it to do, and showed the look-and-feel of a prototype design. In Part 2, I’ll discuss the view “under the hood”, detailing how to use GPS EXIF information in a Lightroom Web Gallery plugin. This information is intended for plug-in developers and those intrepid souls who want to understand what lies beneath the surface of a Lightroom gallery engine. It isn’t my intention to make this series of posts a definitive guide to Lightroom gallery engine design or anatomy. Instead, I’d recommend starting with the Lightroom SDK 2.0 Programmers Guide and Lightroom 2 SDK available from Adobe. The Adobe guide is a good starting point, but you can learn even more by dissecting an actual gallery engine, including those that are included in the SDK.
If an image that has been geocoded (i.e., has GPS EXIF information) is imported into Lightroom, a Web gallery engine or plugin can access the geocoding data during the creation of a Web gallery. But you need to know a little bit about the anatomy of a Lightroom gallery engine to understand how that is achieved. A typical Lightroom Web gallery engine contains the following files and folders (or a subset of them):
- footer.html
- galleryinfo.lrweb
- grid.html
- header.html
- large.html (or detail.html)
- manifest.lrweb
- resources folder
Modifying the galleryinfo.lrweb File
A simple text or HTML editor can be used to examine and/or modify these files. I use BBEdit from Bare Bones Software. The galleryinfo.lrweb file is the heart of the engine. It delineates the data that will populate the gallery, defines the CSS (Cascading Style Sheet), and structures the user interface panel. First, we need to make the GPS EXIF data available to the gallery engine. We’ll add the per-image GPS information by adding this code to galleryinfo.lrweb Image Info pane settings:
["perImageSetting.gpsLocation"] = { enabled = true, value = "{{com.adobe.GPS}}", },
And the following code to the galleryinfo.lrweb per-image properties settings:
properties = { perImage = { { id = "gpsLocation", title = "GPS Coordinates", }, }, },
Displaying GPS Coordinates
Lightroom passes the GPS location in degrees-minutes-seconds (DMS) format (for example, 35°49’1″ N 75°33’53″ W). To display the GPS coordinates in Lightroom DMS format with the thumbnail (grid.html) or large image (large.html or detail.html) in the Web gallery, we need to insert a reference to the GPS data at the desired location in the page layout, styling the text to taste. For example:
<% if image.metadata.gpsLocation == "" then %><% else %> GPS Location - $image.metadata.gpsLocation <% end %>
The conditional statement enables the text display only if there is GPS data associated with the image, i.e., the image is geocoded.
Converting GPS Coordinates from DMS to DD for Google Maps
A link to Google Maps requires a format conversion. Google Maps requires decimal degrees (DD), rounded to no more than six decimal places. Lightroom formats the GPS location in degrees-minutes-seconds (DMS) format. So a conversion from DMS to DD is necessary for each image that will have a map link. The heavy lifting can be done with Lua code that we place in the large.html (or detail.html) file or grid.html file that is executed at the time of Lightroom gallery export/upload. The following code can be inserted at the top of the large.html (or detail.html) file, or in the <lr:GridPhotoCell> loop of the grid.html file. This code creates a link to Google Maps centered on the GPS location associated with the image.
<% --[[ Begin Google Maps ]] if model.nonCSS.googleMaps then if image.metadata.gpsLocation == "" then else --[[ Round to idp decimal places ]] function round(num, idp) local mult = 10^(idp or 0) return math.floor(num * mult + 0.5) / mult end --[[ Convert DMS to DD ]] function latlongDMStoDD(brng) local precision = 6 local dms = {} for w in string.gfind(brng, "%d+") do table.insert(dms, w) end local deg = dms[1]/1 + dms[2]/60 + dms[3]/3600 deg = round(deg, precision) local dir = string.match(brng, "%u") if dir == "S" then deg = -deg elseif dir == "W" then deg = -deg else end return deg end --[[ Get GPS location data ]] gpsData = image.metadata.gpsLocation --[[ Find latitude and longitude strings ]] local dms_pattern = "%d+%W+%d+%W+%d+%W+%u" local latlongDMS = {} for w in string.gfind(gpsData, dms_pattern) do table.insert(latlongDMS, w) end --[[ Create latitude,longitude decimal degree string ]] local latlongDD = latlongDMStoDD(latlongDMS[1]) .. "," .. latlongDMStoDD(latlongDMS[2]) --[[ Create Google Maps URL ]] googleURL = "http://maps.google.com/maps?f=q&q=" .. latlongDD googleURL = googleURL .. "&ll=" .. latlongDD googleURL = googleURL .. "&t=h" googleURL = googleURL .. "&iwloc=near" googleURL = googleURL .. "&z=10" end else end --[[ End Google Maps ]] %>
Link to Google Maps
At the end of the above code, the googleURL link variable is created. The parameters in this case create a hybrid map (&t=h) with zoom level 10 (&z=10), centered on the GPS location associated with the image. These parameters are described in detail in the Google Maps wiki. The googleURL link variable that can be inserted in the large.html (or detail.html) or grid.html at the desired location in the page layout, styling the link to taste. For example:
<% if image.metadata.gpsLocation == "" then %><% else %> GPS Location <% end %>
The conditional statement enables the link display only if there is GPS data associated with the image, i.e., the image is geocoded.
Creating a Static Map
Optionally, we can create a static map rather than linking to a Google Maps page. From the Google Maps Static Maps API:
The Google Static Maps API returns an image (either GIF, PNG or JPEG) in response to a HTTP request via a URL. For each request, you can specify the location of the map, the size of the image, the zoom level, the type of map, and the placement of optional markers at locations on the map. You can additionally label your markers using alphanumeric characters, so that you can refer to them in a “key.”
You embed a Static Maps API image within a webpage inside an img tag’s src attribute. When the webpage is displayed, the browser requests the image from the the Static Maps API and it renders within the image location. Note that static maps may only be displayed within browser content; use of static maps outside of the browser is not allowed.
The static map can be inserted in a page layout as an image, but requires a minor modification to the Lua code above. Replace this:
googleURL = "http://maps.google.com/maps?f=q&q=" .. latlongDD googleURL = googleURL .. "&ll=" .. latlongDD googleURL = googleURL .. "&t=h" googleURL = googleURL .. "&iwloc=near" googleURL = googleURL .. "&z=10"
with this:
googleURL = "http://maps.google.com/maps/api/staticmap?center=" .. latlongDD googleURL = googleURL .. "&markers=color:blue|label:A|" .. latlongDD googleURL = googleURL .. "&maptype=hybrid" googleURL = googleURL .. "&zoom=10" googleURL = googleURL .. "&size=640x640" googleURL = googleURL .. "&sensor=false"
The parameters are different from those used to create a link to the Google Maps site. In this case the parameters create a PNG image (default), hybrid map (&maptype=hybrid), with zoom level 10 (&zoom=10), sized at 640×640 pixels (&size=640×640), with a blue marker labeled “A” (&markers=color:blue|label:A|) centered on the GPS coordinates associated with the image. The largest image available is 640×640 pixels. We can insert the static map image into a Web page by using a regular <img> tag. For example:
<% if mode == 'publish' then %> <% if image.metadata.gpsLocation == "" then %><% else %> <img src="$googleURL" alt="map" /> <% end %> <% end %>
This example embeds the 640×640 pixel PNG static map where this code appears on the webpage. The conditional statements enable the static map display when the gallery is exported/uploaded, and only if there is GPS data associated with the image, i.e., the image is geocoded.
Geocoded Web Engines
Matt Campagna, The Turning Gate, has used this code in his TTG Highslide Gallery and TTG Highslide Gallery Pro web engines. I highly recommend these two feature-rich products.
My galleries were generated using a Web engine of my own design that I will discuss in Part 3 of this series.
Adobe and Photoshop are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries.