EXIF data with a pelican-photos Gallery


By jeffmackinnon

Way back in the day, when I was using Flickr as one of my daily visits, I really enjoyed learning HOW these amazing photographers made these pictures happen through the exif data. This is where I learned about the affect of aperature, etc. I would copy the settings with my old Canon XSi and grow.

When I added the galleries to this site with the pelican-photos the only way to do this was adding an exif.txt file to each folder. There is a recommended third-party software to do it, but I didn't find it intuitive and gave up.

This weekend however, I had a very little bit of time and decided to see what file metadata I could pull using python.

Using Python to extract EXIF data

I tried the piexif module without much luck, and then found this GIST from @jpstroop that did most of the work for me.

def _map_key(k):
        return TAGS[k]
    except KeyError:
        return GPSTAGS.get(k, k)

# Creates a dictionary of image EXIF meta data from an image, borrowed from a github gist
def get_exif(image_path):
    metadata = {}
    with Image.open(image_path) as i:
        info = i._getexif()
        [ metadata.__setitem__(_map_key(k), v) for k, v in info.items() ]
        return metadata
    except AttributeError:
        return None

I use the exact fucntions from @jpstroop.

Walking and writing with Python

The next step was to figure out how to walk all the directories in my photo gallery and make sure that I was getting them all, for that I do this:

# The directory of the source photos, the same as PHOTO_LIBRARY in pelicanconf.py
# I run this in a WSL instance, but pelican is run on the host windows machine, hence the sample directory
dir = '/mnt/c/Users/jeff/Pictures'

for root, subdirectories, files in os.walk(dir):
    for subdirectory in subdirectories:
        print(os.path.join(root, subdirectory))

This is goes through each directory and prints the path. I don't need that for the final product, but I like knowing that something is happening when I run the script, so I kept it.

Creating a text file with everything

Once I made sure that was working the way that I hoped, I wrote a function that will be called for every subdirectory. I called it write_exif_file(directory), this creates the text file and then loops over every .jpg file there and writes the exif data in the way needed for pelican-photos and that I think looks "good". [*]

That function looks like this: [†]

def write_exif_file(directory):
# Open the exif.txt file, create if it doesn't exist, in the current folder.
txt = open(directory+'/exif.txt', 'w')

for file in os.listdir(directory):

    # check the files which are end with specific extension
    # Everything that I want to have EXIF information for is a jpg, but you can add others too.
    if file.endswith(".jpg"):
        # Need to iterate through the files in the list and pass each to the
        image = get_exif(directory +'/'+os.path.join(file))
            os.path.join(file) + ': ' +
            str(image.get('Model')) +
            ' with a ' + str(image.get('LensModel')) +
            ' - ' + str(image.get('ExposureTime')) + 's, ' + # I want to change this to fractions, but it works for now.
            'f/' + str(image.get('FNumber')) +
            ' at ISO-' +  str(image.get('ISOSpeedRatings')) +

# Close the text file now that we are done with it.
return None

For now I'm only including:

  • Model,
  • Lens,
  • Exposure,
  • F-Stop, and
  • ISO

I may add GPS to them in the future, but as for the settings needed to replicate these shots with your own camera, I think this is enough.

Finding the code snippet

I created a GIST for this code snippet here - pelican-photos-create-exif-files. Until this weekend I didn't even know that GIST was a site. As I go through creating these little scripts for myself I am way more likely to neeed a function, or code-snippet than an entire repo. I will probably be adding some more here as I go along, as a backup storage if nothing else.

If you have any suggestions on how to make this "slicker". If you think its useful and want to copy/paste it as a function in the plugin be my guest. I don't have the bandwidth right now to figure out how to do a proper pull-request for the plugin, or the expereince to know how to update the code in a way that won't break everything else.


[*]There is still some work to do there, especially for the exposure time. I want it to be fractional for less than a second, but its "good enough" for this iteration.
[†]If anyone knows CSS and wants to help me add syntac highlighting to this theme, let me know.

This post is part 3 of the "How I Pelican" series:

  1. Installing Pelican for the first time again
  2. I updated a theme
  3. EXIF data with a pelican-photos Gallery
  4. Custom CSS per page or article with pelican
  5. Batch Files are your friend

To join a conversation on Twitter click here.