Updating EXIF metadata in JavaScript (and WebAssembly)

This is a blog post by aaron cope that was published on April 14, 2021 . It was tagged golang, exif, javascript, wasm and zoomable.

Over the last year SFO Museum has been hard at work on the tools it uses to build and display “zoomable images”. These tools allow a static, fixed-size image to be converted in to a tiled and “zoomable” version that can be used to pan around and highlight specific details. One of the handy features with zoomable images is the ability to save the visible area of a “zoomed” image to a new file, by clicking the camera icon in the top right-hand corner of the viewport.

Screenshot of the zoomable image camera button creating a new image with a crop of my favourite collection object "Tabletop airplane with walrus".

One question that’s been raised about the camera/save button in zoomable images is whether or not the new image contains, or preserves, existing EXIF metadata information stored in the original file. The answer yesterday was: No. The answer today is: Not yet, but only because we haven’t enabled it and we will do that soon.

Today we are releasing the go-exif-update package. It is a thin wrapper around Dustin Oprea’s go-exif and go-jpeg-image-structure packages designed to make assigning or updating EXIF properties in JPEG files a little bit easier. Importantly our package includes tools for compiling the code in to a WebAssembly (wasm) binary for updating EXIF data in JavaScript applications.

In the Tools for Complex and Ambiguous Dates at SFO Museum blog post I wrote that:

WebAssembly (wasm) is a standard that defines the rules for exporting code written in one programming language so that it can be safely consumed and executed by another programming language. Not all programming languages support building or running wasm binaries yet but one that does is Go. Another is JavaScript and is supported by all the major web browsers.

This is the second tool we’ve built using wasm (the first was a tool to parse ExtendedDateTime Format date strings) and it is an approach to modular and portable functionality that continues to be promising. The ability to update EXIF data in images in JavaScript means that we can add the relevant metadata, like a credit line or a permanent URL, to zoomable images as they are created and before they are downloaded. Here’s an abbreviated version of what that looks like in (JavaScript) code:

var update = { "Artist": "Bob" };	
var enc_update = JSON.stringify(update);

var img = document.getElementById("image");

var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var b64_img = canvas.toDataURL("image/jpeg", 1.0);

// This is where the "magic" happens
var rsp = update_exif(b64_img, enc_update);

var blob = dataURLToBlob(rsp);
saveAs(blob, "example.jpg");

As of this writing the majority of EXIF tags are not yet supported. Currently only EXIF tags that are stored as strings are supported. I am still trying to get familiar with the requirements of the go-exif package so this is just a first step. I am hoping to enable the writing of numeric EXIF tags soon because the other place where SFO Museum has a save-to-file camera button that would benefit from dynamically-written EXIF tags is the historical maps webpage.

For example, this snapshot of a map of SFO in 1978 should have both a URL and GPS information embedded in its EXIF metadata. That’s possible to do now!

Demonstration

To demonstrate adding dynamically-generated EXIF metadata to images we’ve included the update_exif.wasm binary with this blog post. We’ve actually included two WebAssmebly binaries, one to update the EXIF data and another to return a list of EXIF tags supported by the go-exif-update package. We used this second binary to pre-populate a select menu with available tag names.

Once the two wasm binaries have finished loading you should see an Add property button beneath the image of the tabletop airplane with walrus. Each time you click the button a new row, containing a menu of EXIF tag names and an input field for a value to assign to that tag, will be created.

To finish writing the new EXIF tags to the image simply click the Update button. Once complete your web browser will prompt you to save the new image to your computer and you can inspect the file’s EXIF data with the tool of your choice. For example using the exiv2 command-line tool:

$> exiv2 -pa ~/Downloads/example.jpg
Exif.Image.Make                              Ascii       9  Airplane
Exif.Image.Model                             Ascii       7  Walrus

This is only a first release of the code to update EXIF metadata in JavaScript and it is expected that there will be a few “gotchas” before it’s considered stable for general use. One important consideration is that the update_exif.wasm binary is sufficiently large (7.2MB) that it can have a noticeable impact on the time it takes to load a webpage. This is especially true if WebAssembly binaries aren’t cached by web browsers. If you have any experience with these issues we’d love to hear about your experiences.

In the meantime we’re going to start thinking about how best to integrate this new functionality with our zoomable images code and we’ll keep you posted on our progress.