Keeping up-to-date EXIF data is critically important for managing large libraries of photos. In addition to keeping your library organized, EXIF data also lets you sort, filter, and search your photo library on numerous criteria, making it easy to find the images you want, and fast. Unfortunately, many photographers, including myself, tend to let things slip when it comes to keeping metadata up to date. As a result, when it comes time to edit your EXIF data, you need to do it in bulk, which can be a tedious and time-consuming task.

EXIF stands for Exchangeable Image Format. It’s a standard that defines the data or information related to any media you capture with a digital camera. It can include data such as:

EXIF Data Seen in Adobe Lightroom
  • Image Size
  • File Name and Location on Your Computer
  • Camera and Lens Make/Model
  • Exposure Settings (Aperture, Shutter, ISO, etc)
  • Date and Time the Photo was Taken
  • Location and Elevation Where the Photo was Taken
  • Photographer’s Name and Contact Info
  • Copyright Info
  • Software Used to Post-Process the Image
  • Much More

Why Do You Need to Edit EXIF Data?

Regardless of whether you need to add or remove EXIF data, there are plenty of reasons to edit it. In my nearly two decades doing photography, here are some of the more common reasons I’ve had to edit EXIF data.

  • Strip out sensitive information when you post photos publicly on the web
  • Add location data or geotag images for cameras that don’t have GPS
  • Add or update titles, descriptions, and captions
  • Rate, label, and tag images
  • Add or update your contact info and/or copyright information
Maintaining Fully-Populated EXIF Data Makes Browsing and Searching Your Photo Library a Breeze

If you’re planning to sell your photography in any way, shape, or form, you better have fully populated EXIF data. For example, let’s consider stock photography websites. They use the EXIF data embedded in your images to return the most relevant images in search results. Without fully-populated EXIF data, your images won’t be returned in their searches, and you won’t make any sales as a result.

Available Tools to Bulk Edit EXIF Data

Thankfully, there are numerous tools available so you can edit your photos’ EXIF data. They all support bulk editing, so it doesn’t matter whether you’re updating one photo or a million.

  • Photo editors and organizers such as Adobe Lightroom
  • EXIF Editors are available for all operating systems, including iOS and Android. Many are free.
  • Python

Do be aware that while many EXIF editors advertise themselves as free, they often come with heavy restrictions if you don’t want to pay for the full software. Because of these restrictions, Python is one of the few tools that can edit EXIF data both for free and without restrictions. In this tutorial, we’re going to use Python to add EXIF data to a series of images.

Python Image Libraries

In previous tutorials, we’ve used Python’s Pillow Library to do everything from editing and post-processing to removing noise from and adding location data to photos. And we’ll show in this tutorial that you can use Pillow to add, edit, and remove EXIF data. However, there’s a better Python tool to manage and edit your EXIF data: the exif library.

So what makes the exif library better than Pillow? For that, we have to look at how the computer stores and reads EXIF data. In the computer, EXIF parameters are stored as numeric codes instead of English words. For example, instead of “Camera Make”, the computer just sees 271. Likewise, the computer sees 36867 instead of “Date/Time Image Taken”.

To edit the EXIF data using Pillow, you need to know the numeric key for each field you want to edit. Considering that there are thousands of these numeric keys in use, you’ll spend an incredible amount of time just searching for they numeric keys you want. On the other hand, the exif library uses human-readable keys to edit the EXIF data. We’ll go over how to use both libraries, so you can decide which one you prefer.

Install the Pillow and Exif Libraries (If You Haven’t Already)

Before diving into EXIF data, you’ll need to install the Python Pillow and Exif libraries if you haven’t already. With pip, it’s a couple quick commands in a Terminal or Command Prompt.

pip3 install pillow
pip3 install exif

Import the Image Property from both the Pillow and Exif Libraries into Your Python Script

In order to run code from the Pillow and Exif libraries, you’ll need to import the Image property from each library into your Python script. To avoid name conflicts, we’ll call them ExifImage and PillowImage. From the Pillow library, we’ll also import the ExifTags property, which converts the numeric EXIF tags into human-readable tags.

from exif import Image as ExifImage
from PIL import Image as PillowImage
from PIL import ExifTags

Images for this Demo

I’ve included three images with this tutorial, but you can add as many of your own as you please. One set has the metadata intact, which we’ll use for reading the metadata. I stripped the EXIF data out of the other set, so we can add it with Python. I also took the images with three different cameras.

Image DescriptionCameraGeotagged
Chicago Cubs vs Boston Red Sox Spring Training game in Mesa, ArizonaSamsung GalaxyYes
Stonehenge Memorial in Washington StateNikon D3000No
Beach Scene on Cape Cod, MassachusettsCanon EOS R5No

Back Up Your Images Before You Begin

Before you do anything with the Python code, make a copy of the folder containing your original images. You never know when something will go wrong. With a backup, you can always restore your images to their original state.

Reading EXIF Data with Python

First, we’ll loop through the images and extract the camera make and model, the date and time the image was taken, as well as the location data.

ParameterPillow PropertyExif Property
Camera Make271make
Camera Model272model
Timestamp36867datetime_original
GPS Info34853gps_latitude, gps_longitude

The steps to read the EXIF data from each image and output it to the terminal window are as follows.

  1. Open the image
  2. Extract the value of each metadata tag displayed in the table above
  3. Print the human-readable tag and the value in the terminal window.

Define the Universal Parameters You’ll Use to Extract EXIF Data in the Python Script

In our Python script, the first thing we need to do is define the universal parameters we’ll use throughout the script. First, we’ll create a list of the image filenames.

images = ["baseball.jpg", "cape-cod.jpg", "stonehenge.jpg"]

Next, define the EXIF Tags for the Pillow library that will extract the data we want. Remember, that Pillow uses the EXIF numeric tags.

PILLOW_TAGS = [
    271,    # Camera Make
    272,    # Camera Model
    36867,  # Date/Time Photo Taken
    34853,  # GPS Info
]

Finally, create a variable to store the EXIF tags for the Exif library. The Exif library uses human-readable tags, so please consult their documentation for the full list of tags.

EXIF_TAGS = [
    "make",
    "model",
    "datetime_original",
    "gps_latitude",
    "gps_latitude_ref",
    "gps_longitude",
    "gps_longitude_ref",
    "gps_altitude",
]

Read EXIF Data with the Pillow Library

To extract the EXIF data from all of the images at once, we’ll loop through the images variable we defined above. We’ll print the image filename and then set the image path inside the with-metadata folder.

for img in images:
    print(img)
    image_path = "with-metadata/{}".format(img)

Next, open the image with Pillow and extract the EXIF data using the getexif() method.

pillow_img = PillowImage.open(image_path)
img_exif = pillow_img.getexif()

Now, we’ll loop through the tags. Pillow has a property called ExifTags that we’ll use to get the human-readable definition of each numeric tag. Do note that you’ll need to wrap it in a try/except block to skip properties that are not set. Without it, you’ll get an error and the script will crash if a property is not set. For example, the Cape Cod and Stonehenge images do not have GPS/location data. Finally, print the human-readable tag and the value to the Terminal window.

for tag in PILLOW_TAGS:
    try:
        english_tag = ExifTags.TAGS[tag]
        value = img_exif[tag]
    except:
        continue
    print("{}: {}".format(english_tag, value))

Final Pillow Code

Put it all together into nice, compact block of code.

for img in images:
    print(img)
    image_path = "with-metadata/{}".format(img)
    pillow_img = PillowImage.open(image_path)
    img_exif = pillow_img.getexif()
    
    for tag in PILLOW_TAGS:
        try:
            english_tag = ExifTags.TAGS[tag]
            value = img_exif[tag]
        except:
            continue
        print("{}: {}".format(english_tag, value))

When you run the script, it will output the info about each photo.

baseball.jpg
Make: samsung
Model: SM-G965F
DateTimeOriginal: 2019:03:25 18:06:05
GPSInfo: æ0: b'Øx02Øx02Øx00Øx00', 1: 'N', 2: (33.0, 25.0, 50.0), 3: 'W', 4: (111.0, 52.0, 53.0), 5: b'Øx00', 6: 347.0, 7: (1.0, 6.0, 0.0), 27: b'ASCIIØx00Øx00Øx00GPS', 29: '2019:03:26'å

cape-cod.jpg
Make: Canon
Model: Canon EOS R5
DateTimeOriginal: 2022:03:22 20:58:52

stonehenge.jpg
Make: NIKON CORPORATION
Model: NIKON D3000
DateTimeOriginal: 2022:02:16 21:36:08

A Quick Word on Interpreting the GPS Output

When you look at the GPS output, you’re probably wondering what the hell you’re looking at. To decipher it, let’s break it down and look at the important components. FYI, Pillow returns latitude and longitude coordinates as tuples of (degrees, minutes, seconds).

1: 'N', 
2: (33.0, 25.0, 50.0), 
3: 'W', 
4: (111.0, 52.0, 53.0),
6: 347.0,

Here’s what it all means.

  1. 'N' indicates that the latitude coordinate is in the northern hemisphere. It returns 'S' for southern hemisphere latitudes.
  2. (33.0, 25.0, 50.0) contains the degrees, minutes, and seconds of the latitude coordinates. In this case, it’s 33°25’50″N.
  3. 'W' indicates that the longitude coordinate is in the western hemisphere. It returns 'E' for eastern hemisphere longitudes.
  4. The (111.0, 52.0, 53.0) tuple contains the degrees, minutes, and seconds of the longitude coordinates. Here, it’s 111°52’53″W.
  5. 347.0 is the altitude at which the photo was taken, in meters.

Remember, it’s the baseball picture that’s geotagged. If we plot those coordinates on a map, it should return the Chicago Cubs’ Spring Training ballpark in Mesa, Arizona. Indeed, it even correctly shows us sitting down the first base line.

Chicago Cubs vs. Boston Red Sox Spring Training Game in March, 2019

Read EXIF Data with the Exif Library

Extracting EXIF data from your photos using the Exif library is very similar to the Pillow library. Again, we’ll start by printing the image filename and set the image path inside the with-metadata folder.

for img in images:
    print(img)
    image_path = "with-metadata/{}".format(img)

Next, we’ll read the image into the Exif library. However, unlike Pillow, the Exif library automatically extracts all the EXIF data when you instantiate the Image object. As a result, we do not need to call any additional methods or functions.

with open(image_path, "rb") as input_file:
    img = ExifImage(input_file)

Because the Exif library automatically extracts the EXIF data, all you need to do is just loop through the tags and extract each one with the get() method. And unlike the Pillow library, the Exif library also automatically handles instances where data points are missing. It won’t throw an error, so you don’t need to wrap it in a try/except block.

for tag in EXIF_TAGS:
    value = img.get(tag)
    print(“{}: {}”.format(tag, value))

Final Exif Library Code

When you put everything together, it’s even cleaner than using the Pillow library.

for img in images:
    print(img)
    image_path = “with-metadata/{}”.format(img)
    with open(image_pdaath, ”rb”) as input_file:
        img = ExifImage(img_file)

    for tag in EXIF_TAGS:
        value = img.get(tag)
        print(“{}: {}”.format(tag, value))

When you run the script, the output from the Exif library should be identical to the output from the Pillow library, with one exception. The Exif Library breaks down the GPS data into its components. You’ll still get the same tuples you do with the Pillow library, but it labels what each component of the GPS data is using English words instead of numeric codes.

baseball.jpg
make: samsung
model: SM-G965F
datetime_original: 2019:03:25 18:06:05
gps_latitude: (33.0, 25.0, 50.0)
gps_latitude_ref: N
gps_longitude: (111.0, 52.0, 53.0)
gps_longitude_ref: W
gps_altitude: 347.0

cape-cod.jpg
make: Canon
model: Canon EOS R5
datetime_original: 2022:03:22 20:58:52
gps_latitude: None
gps_latitude_ref: None
gps_longitude: None
gps_longitude_ref: None
gps_altitude: None

stonehenge.jpg
make: NIKON CORPORATION
model: NIKON D3000
datetime_original: 2022:02:16 21:36:08
gps_latitude: None
gps_latitude_ref: None
gps_longitude: None
gps_longitude_ref: None
gps_altitude: None

Writing, Editing, and Updating EXIF Data Using Python

To demonstrate how to write and edit EXIF data, we’re going to add a simple copyright message to the all three images. That message will simply say ”Copyright 2022. All Rights Reserved.” We’ll also add your name to the EXIF data as the artist/photographer.

Universal Tags We’ll Use Throughout the Python Script

Just like we did when we read the EXIF data from the image, we’ll define the artist and copyright tags we’ll use to edit the EXIF data in each library. We’ll also store the values we’ll set the tags to in the VALUES variable.

PILLOW_TAGS = [
    315,     # Artist Name
    33432,   # Copyright Message
[

EXIF_TAGS = [
    “artist”,
    ”copyright”,
]

VALUES = [
    “Matthew Gove”,    # Artist Name
    ”Copyright 2022 Matthew Gove. All Rights Reserved.”  # Copyright Message
]

How to Edit EXIF Data with the Pillow Library

In order to edit the EXIF data, you need to open the image with the Pillow Library and load the EXIF data using the getexif() method. This code is identical to when we read the metadata. The only difference is that we’re loaded the image from the without-metadata folder.

for img in images:
    image_path = “without-metadata/{}”.format(img)
    pillow_image = PillowImage.open(image_path)
    img_exif = pillow_img.getexif()

Now, all we have to do is loop through the tags we want to set (which are in the PILLOW_TAGS variable) and set them to the corresponding values in VALUES.

for tag, value in zip(PILLOW_TAGS, VALUES):
    img_exif[tag] = value

Finally, just save the changes to your image. For the purposes of this tutorial, we are saving the final images separate from the originals. When you update your EXIF data, feel free to overwrite the original image. You can always restore from the backup we made if needed.

output_file = img
pillow_img.save(output_file, exif=img_exif)

That’s all there is to it. When you put it all together, you have a nice, efficient, and compact block of code.

for img in images:
    image_path = “without-metadata/{}”.format(img)
    pillow_image = PillowImage.open(image_path)
    img_exif = pillow_img.getexif()

    for tag, value in zip(PILLOW_TAGS, VALUES):
        img_exif[tag] = value

    output_file = img
    pillow_img.save(output_file, exif=img_exif)

How to Edit EXIF Data with the Exif Library

Editing EXIF data with the Exif library is even easier than it is using Pillow. We’ll start by loading the image without the metadata into the Exif library. You can cut and paste this code from the script that reads the EXIF data. Just don’t forget to change the with-metadata folder to without-metadata.

for img in images:
    image_path = “without-metadata/{}”.format(img)
    with open(image_path, ”rb”) as input_file:
        exif_img = ExifImage(input_file)

Here’s where it gets really easy to edit the EXIF data and set new values. If you have a lot of EXIF data to edit, by all means put everything into a loop. However, for simplicity, you also do this.

exif_img.artist = “Matthew Gove
exif_img.copyright = “Copyright 2022 Matthew Gove. All Rights Reserved.”

Then save the file. Like we did with the Pillow library, we’ll save everything to a new file for purposes of the tutorial. However, feel free to overwrite the images when you use it in the real world.

output_filepath = img
with open(output_filepath, ”wb”) as ofile:
    ofile.write(exif_img.get_file())

Put it all together and you can update and edit your EXIF data with just 10 lines of Python code.

for img in images:
    image_path = "without-metadata/{}".format(img)
    with open(image_path, "rb") as input_file:
        exif_img = ExifImage(input_file)
    
    exif_img.artist = "Matthew Gove"
    exif_img.copyright = "Copyright 2022 Matthew Gove. All Rights Reserved."

    with open(img, "wb") as ofile:
        ofile.write(exif_img.get_file())

Confirming Your EXIF Edits Worked

The final step in editing your EXIF data is to confirm that the Python code actually worked. In the script, I copied logic from when we read the EXIF data to confirm that our edits were added and saved correctly. Indeed, when you run the script, you’ll see the following confirmation in the Terminal window. Alternatively, you can open the photo in any photo editor, such as Adobe Lightroom, to confirm that the new EXIF data has been added to it.

PILLOW
=======
baseball.jpg 
Artist: Matthew Gove
Copyright: Copyright 2022 Matthew Gove. All Rights Reserved.

cape-cod.jpg
Artist: Matthew Gove
Copyright: Copyright 2022 Matthew Gove. All Rights Reserved.

stonehenge.jpg
Artist: Matthew Gove
Copyright: Copyright 2022 Matthew Gove. All Rights Reserved.

################################

EXIF
======
baseball.jpg
artist: Matthew Gove
copyright: Copyright 2022 Matthew Gove. All Rights Reserved.

cape-cod.jpg
artist: Matthew Gove
copyright: Copyright 2022 Matthew Gove. All Rights Reserved.

stonehenge.jpg
artist: Matthew Gove
copyright: Copyright 2022 Matthew Gove. All Rights Reserved.

Download the Code in This Tutorial

You can download the code we wrote in this tutorial from our Bitbucket repository. Please feel free to play around with it and update it to suit your needs. If you have any questions, leave them in the comments below.

Conclusion

Python is an incredibly powerful tool to update and edit your EXIF data. And best of all, it’s one of the few EXIF editing tools that is completely free, without any restrictions on what you can do with it. It’s fast, easy-to-use, and infintely scalable. EXIF metadata is not the sexiest aspect of photography by any means. But it is one of the most critical. When you don’t manage it correctly, you are literally costing yourself both time and money.

If you want help getting started with your EXIF data, please get in touch with us today. As experts in both photography and data science, there are not many people who know the ins and outs of EXIF data better than we do. Alternatively, if you would just like to see more tutorials, I invite you to please join our email list and subscribe to our YouTube channel. See you in the next tutorial.

Comments are closed.