Geotagging at SFO Museum: Client-side EXIF, Web Components, Tilepacks, AppRunner and Live Demos

This is a blog post by aaron cope that was published on June 16, 2021 . It was tagged golang, geotagging, aws, reverse-geocoding, tilezen, maps and aws.

Negative: San Francisco Airport, meeting with National Security Resources Board. Negative. Transfer, SFO Museum Collection. 2011.032.0179.

Here is an update on a number of improvements we’ve implemented since the last blog post about the geotagging project. Specifically:

  • Client-side EXIF encoding of geotagging coordinates in downloadable images.
  • Support for drag-and-drop and file-browser-based image selection.
  • Bundled and locally served Nextzen map tiles.
  • Support for running the geotagging application with bundled databases inside of a Docker container, and deployed as an AWS AppRunner instance.
  • A live demonstration application.

Client-side EXIF

Negative: San Francisco Airport, Flying Tiger Line Curtiss C-46 Commando. Negative. Transfer, SFO Museum Collection. 2011.032.0327.

It is now possible to configure the web application to encode geotagging information for an image in to a new image that you can download to your computer. All of this happens in the browser so there is no need for a server-side component to encode geotagging information. This builds on the work we’ve been doing to develop a WebAssembly-based EXIF update tool.

At the moment only the geotagging center point is recorded as EXIF GPSLatitude and GPSLongitude properties. Field of view information is not included yet while I figure out how and where the best place to encode that data within the constraints of the EXIF format.

Web Components

Photograph: Transcontinental & Western Air (TWA), Douglas DC-1. Photograph. Gift of Carla B. Bos in memory of Abraham Bos, SFO Museum Collection. 2000.069.016.

We have integrated GitHub’s file-attachment WebComponent with the application. This provides user-interface elements that allow a person to drag-and-drop, or select from their computer, an image they want to geotag.

WebComponents are a new-ish browser technology, described as:

…a suite of different technologies allowing you to create reusable custom elements — with their functionality encapsulated away from the rest of your code — and utilize them in your web apps.

I like this because I hear echoes of something I said in the very first blog post about geotagging images:

…we would be better served as a sector to focus on shared tools that automate what can happen to data and making it both easy to ingest and export in the process. The cultural heritage sector needs as many of these small, focused, tools as it can produce. It needs them in the long-term to finally reach the goal of a common infrastructure that can be employed sector-wide.

It is possible to imagine a world where there are too many WebComponents, of variable quality and in some cases questionable motives. That’s a risk we should be conscious of but there is also the potential for well-designed, well-engineered and genuinely useful pieces of functionality, like the file-attachment component demonstrates, that we can share and build upon.

At the moment, only individual images are handled by the geotagging application. The file-attachment element supports loading multiple images but the geotagging application does not yet.


Photograph: KLM (Royal Dutch Airlines), TWA (Trans World Airlines), San Francisco International Airport (SFO), Julian Veovich. Photograph. Gift of Julian Veovich, SFO Museum Collection. 2013.126.023.

In the last blog post I talked about using the Protomaps mapping libraries and databases for serving map tiles without the need for a separate database or hosting infrastructure. I am pleased to announced that we’ve enabled similar functionality for Nextzen map tiles. Nextzen map tiles are rendered using the Tangram.js library which has been around longer than Protomaps and has better support for things like labels. Each is great in their own right and ensuring that both are supported in the geotagging application is even better.

A local database of Nextzen tiles can be created using the tools in the Tilezen go-tilepacks package. For example this is how we created a database of map tiles for SFO:

$> cd go-tilepacks
$> make tools

$> ./bin/build \
	-dsn /usr/local/data/sfo-tiles.db \
	-zooms 0-16
	-bounds '37.604481,-122.405228,37.645194,-122.355044' \
	-url-template '{z}/{x}/{y}.mvt?api_key={NEXTZEN_APIKEY}'	

And then to use these tiles in our geotagging application we include the following flags when we start the application:

$> cd go-www-geotag

$> bin/server \
	-enable-tilezen-tilepacks true \
	-tilezen-tilepack-path /usr/local/data/sfo-tiles.db \	
	-nextzen-tile-url /tilezen/vector/v1/512/all/{z}/{x}/{y}.mvt
	...other geotagging application configuration flags

The map tiles themselves are harvested from the Nextzen website and stored in a SQLite (or MBTiles) database that is then used by the geotagging application itself to serve its own map tiles. That means there one less external service to depend on long-term for running a geotagging application. It’s not necessarily an approach that will scale to an application which has to support a large geographic extent but for small and bounded use cases it’s nearly perfect.


Negative: San Francisco International Airport (SFO), SFO Helicopter Airlines. Negative. Transfer, SFO Museum Collection. 2011.032.1289.

Recently, Amazon Web Services (AWS) announced their new AppRunner service. AppRunner is the distillation, and the simplification, of a number of existing AWS products and networking components for hosting web applications that are packaged as (Docker) containers.

Put another way, AppRunner is “fewer buttons to press” to deploy a web application for a lower monthly fee than before. AppRunner doesn’t have all the features that other AWS services do but it many cases that doesn’t matter.

A “container” is a standardized way of packaging and running web applications independent of the implementation details of a hosting provider (like AWS). In the Using the Placeholder Geocoder at SFO Museum blog post I wrote that:

Docker is both a service and an application for running virtual machines which are referred to as “containers”. A container is basically a freeze-dried virtual computer that contains only that which is absolutely necessary to run a pre-defined set of applications. Tools like Docker take care of “thawing” (and re-freeze-drying) containers and running the software they contain. It’s a pretty clever abstraction and managing the operation of containers, as a service, has been adopted by all the different ️cloud providers.

I like to think of this as layers, or separations, of concern:

  • My computer, the source code for the go-www-geotag application.
  • Your computer, the compiled go-www-geotag application running locally in a web browser.
  • Someone else’s computer, the go-www-geotag application running inside a virtual computing environment (aka a “container”).
  • Amazon’s computer, the go-www-geotag container running inside Amazon’s “cloud”.

We’ve made sure that the go-www-geotag application doesn’t depend on AWS, Docker or containerized computing environments to run. Containers are all the rage these days but that may not always be true or practical. The go-www-geotag application can take advantage of the benefits that each of these technologies provide but you can just as easily run the application on its own or behind a traditional web server like Apache or Nginx if you want, or more importantly, need to.

This image is quite large so it might be easier to read by looking at the full-sized original.

The go-www-geotag package is bundled with a Dockerfile for building a containerized version of the application. It has been updated to look for any Protomaps or MBTiles database files you put in a local data folder and copies them in to the final container. This means that you can deploy an entirely self-contained application, inclusive of map tiles and spatial databases, as a single “container” resource that you pass simply along to AWS, or another cloud provider, to host.

This is an approach we’ve been actively investigating, starting with the Reverse-Geocoding in Time at SFO Museum blog post. Conceptually the reverse-geocoding demonstration applications described in that blog post and the geotagging demonstration, described below, are the same. The big difference is that the latter is easier to configure and deploy than the former.

Live demos!

Negative: San Francisco International Airport (SFO), fire fighting demonstration. Negative. Transfer, SFO Museum Collection. 2011.032.0618.

There is a live demonstration application of everything described in this blog post:

While this particular instantiation of the geotagging application is scoped to the physical boundaries of SFO the code itself is not specific to the airport or SFO Museum. It can be used, in combination with custom databases of map tiles and geographic data, with any image on your computer. This code will continue to be the common infrastructure that we build a SFO Museum application, specific to our needs, on top of but it has been designed with general use in mind.

If you’d like to contribute there are a number of user-interface issues and user-experience issues that we would welcome comments and suggestions and help with.