Usage

Warning

Back up your photos before using this tool! You are responsible for any unexpected data loss that may occur through improper use of this package.

Opening an Image

Open an image with EXIF metadata using the Python open() built-in function. Ensure the binary mode flag (i.e. 'rb') is set. Pass this image file object into the exif.Image class:

>>> from exif import Image
>>> with open('grand_canyon.jpg', 'rb') as image_file:
...     my_image = Image(image_file)
...

Alternatively, supply a file path or image bytes to the exif.Image class:

>>> my_image = Image('grand_canyon.jpg')

>>> from exif import Image
>>> with open('grand_canyon.jpg', 'rb') as image_file:
...     image_bytes = image_file.read()
...
>>> my_image = Image(image_bytes)

Verify that an image has EXIF metadata by leveraging the has_exif attribute:

>>> my_image.has_exif
True

Accessing Tags

List all tags present in an image with dir():

>>> dir(my_image)
['<unknown EXIF tag 59932>', '<unknown EXIF tag 59933>', '_exif_ifd_pointer', '_gps_ifd_pointer', '_segments', 'aperture
_value', 'brightness_value', 'color_space', 'components_configuration', 'compression', 'datetime', 'datetime_digitized',
'datetime_original', 'exif_version', 'exposure_bias_value', 'exposure_mode', 'exposure_program', 'exposure_time', 'f_
number', 'flash', 'flashpix_version', 'focal_length', 'focal_length_in_35mm_film', 'get', 'get_file', 'get_thumbnail',
'gps_altitude', 'gps_altitude_ref', 'gps_datestamp', 'gps_dest_bearing', 'gps_dest_bearing_ref', 'gps_horizontal_
positioning_error', 'gps_img_direction', 'gps_img_direction_ref', 'gps_latitude', 'gps_latitude_ref', 'gps_longitude',
'gps_longitude_ref', 'gps_speed', 'gps_speed_ref', 'gps_timestamp', 'has_exif', 'jpeg_interchange_format', 'jpeg_
interchange_format_length', 'lens_make', 'lens_model', 'lens_specification', 'make', 'maker_note', 'metering_mode',
'model', 'orientation', 'photographic_sensitivity', 'pixel_x_dimension', 'pixel_y_dimension', 'resolution_unit',
'scene_capture_type', 'scene_type', 'sensing_method', 'shutter_speed_value', 'software', 'subject_area', 'subsec_time_
digitized', 'subsec_time_original', 'white_balance', 'x_resolution', 'y_and_c_positioning', 'y_resolution']

The Image class facilitates three different tag access paradigms. Leverage attribute syntax for an intuitive object-oriented feel. Alternatively, leverage indexed/item syntax of additional methods for more control.

Attribute Syntax

Access EXIF tag values as attributes of the Image instance:

>>> my_image.gps_latitude
(36.0, 3.0, 11.08)
>>> my_image.gps_longitude
(112.0, 5.0, 4.18)
>>> my_image.make
'Apple'
>>> my_image.model
'iPhone 7'

Change the EXIF tag value by modifying the attribute value:

>>> my_image.make = "Python"

Set new attribute values to add EXIF tags to an image:

>>> from exif import LightSource
>>> my_image.light_source = LightSource.DAYLIGHT

Use del notation to remove EXIF tags from the image:

>>> del my_image.gps_latitude
>>> del my_image.gps_longitude

Indexed/Item Syntax

Alternatively, use indexed/item syntax to read, modify, add, and remove attribute tags:

>>> my_image["orientation"]
1
>>> my_image["software"] = "Python Script"
>>> del my_image["maker_note"]

Methods

Leverage the dictionary-style get() method to gracefully handle cases where attributes do not exist:

>>> my_image.get("color_space")
<ColorSpace.UNCALIBRATED: 65535>
>>> my_image.get("nonexistent_tag")
None

Call set() with a tag name and value to add or modify it:

>>> self.image.set("model", "EXIF Package")

Call delete() with a tag name to remove it from the image:

>>> self.image.delete("datetime_original")

Erase all EXIF tags in an image using the delete_all() method:

>>> my_image.delete_all()

Writing/Saving the Image

Write the image with modified EXIF metadata to an image file using open() in binary write (i.e. 'wb') mode:

>>> with open('modified_image.jpg', 'wb') as new_image_file:
...     new_image_file.write(my_image.get_file())
...

Extract the thumbnail embedded within the EXIF data by using get_thumbnail() instead of get_file().

Cookbook

Add Geolocation

Add geolocation metadata to an image by providing tuples of degrees, minutes, and decimal seconds:

>>> from exif import Image
>>> image = Image("cleveland_public_square.jpg")
>>>
>>> image.gps_latitude = (41.0, 29.0, 57.48)
>>> image.gps_latitude_ref = "N"
>>> image.gps_longitude = (81.0, 41.0, 39.84)
>>> image.gps_longitude_ref = "W"
>>> image.gps_altitude = 199.034  # in meters
>>> image.gps_altitude_ref = GpsAltitudeRef.ABOVE_SEA_LEVEL
>>>
>>> # Then, save image to desired location using code discussed above.

Add Timestamps

Use datetime_original and datetime_digitized to add timestamps to an image (e.g., from a scanner):

>>> from exif import Image, DATETIME_STR_FORMAT
>>> from datetime import datetime
>>> datetime_taken = datetime(year=1999, month=12, day=31, hour=23, minute=49, second=12)
>>> datetime_scanned = datetime(year=2020, month=7, day=11, hour=10, minute=11, second=37)
>>>
>>> image = Image("my_scanned_photo.jpg")
>>> image.datetime_original = datetime_taken.strftime(DATETIME_STR_FORMAT)
>>> image.datetime_digitized = datetime_scanned.strftime(DATETIME_STR_FORMAT)
>>> # Then, save image to desired location using code discussed above.

Use with NumPy and OpenCV Image Encoder

This sample script was provided by Rune Monzel.

It demonstrates how to use this package with NumPy and an image encoder, specifically OpenCV in this case:

import exif
import cv2
import numpy as np

# Create a random 2D array within range [0 255]
image = (np.random.rand(800, 1200) * 255).astype(np.uint8)

# decode to the appropriate format
# jpg -> compressed with information loss)
status, image_jpg_coded = cv2.imencode('.jpg', image)
print('successful jpg encoding: %s' % status)
# tif -> no compression, no information loss
status, image_tif_coded = cv2.imencode('.jpg', image)
print('successful tif encoding: %s' % status)

# to a byte string
image_jpg_coded_bytes = image_jpg_coded.tobytes()
image_tif_coded_bytes = image_tif_coded.tobytes()

# using the exif format to add information
exif_jpg = exif.Image(image_jpg_coded_bytes)
exif_tif = exif.Image(image_tif_coded_bytes)

# providing some information
user_comment = "random image"
software = "created in python with numpy"
author = "Rune Monzel"

# adding information to exif files:
exif_jpg["software"] = exif_tif["software"] = software
exif_jpg["user_comment"] = exif_tif["user_comment"] = user_comment

# show existing tags
print(exif_jpg.list_all())

# save image
with open(r'random.tif', 'wb') as new_image_file:
    new_image_file.write(exif_tif.get_file())
with open(r'random.jpg', 'wb') as new_image_file:
    new_image_file.write(exif_jpg.get_file())