Piexif
Piexif is a pure Python library designed to simplify EXIF data manipulation. It enables reading, writing, and removing EXIF tags from JPEG, WebP, and TIFF image files without relying on external image processing libraries. The library's current version is 1.1.3, and releases are made as needed to address issues or add features.
Warnings
- breaking Version 1.0.0 introduced significant breaking changes. `piexif.ZerothIFD` was renamed to `piexif.ImageIFD`, and the `dump` function's argument signature changed from accepting three separate IFD dictionaries to a single combined dictionary.
- gotcha Piexif has known issues when handling negative GPS coordinates (longitude/latitude). Directly passing negative values can lead to errors during `piexif.dump()` due to expected unsigned values.
- gotcha When loading EXIF data from an image, especially when integrating with Pillow (`PIL.Image.open(filename).info["exif"]`), attempting to access `img.info["exif"]` directly might raise a `KeyError` if the image file contains no EXIF data.
- gotcha Functions like `piexif.dump()` or `piexif.transplant()` can raise an `InvalidImageDataError` if the input image data is malformed, corrupted, or contains an empty thumbnail segment, which `piexif` cannot process. This was partially addressed in version 1.0.12 with more explicit error handling.
- gotcha When resizing an image with Pillow and then saving it with modified EXIF data, the `XResolution` and `YResolution` tags in the `0th IFD` might not automatically update to reflect the new dimensions. This can lead to EXIF metadata that doesn't match the actual image size.
Install
-
pip install piexif
Imports
- piexif
import piexif
- ImageIFD, ExifIFD, GPSIFD, InteropIFD, TAGS
import piexif # Access constants like: piexif.ImageIFD.Make piexif.TAGS['Exif'][piexif.ExifIFD.DateTimeOriginal]
Quickstart
import piexif
from PIL import Image
import os
# Create a dummy JPEG file for demonstration
dummy_image_path = "dummy_image_with_exif.jpg"
new_image_path = "output_image_with_modified_exif.jpg"
# Create a simple image (requires Pillow)
img = Image.new('RGB', (60, 30), color = 'red')
img.save(dummy_image_path)
# 1. Load EXIF data
try:
# Create a minimal EXIF dictionary
zeroth_ifd = {
piexif.ImageIFD.Make: "PiexifTest",
piexif.ImageIFD.XResolution: (72, 1),
piexif.ImageIFD.YResolution: (72, 1)
}
exif_ifd = {
piexif.ExifIFD.DateTimeOriginal: "2026:04:11 12:34:56"
}
exif_dict_initial = {"0th": zeroth_ifd, "Exif": exif_ifd, "GPS": {}, "Interop": {}, "1st": {}, "thumbnail": None}
exif_bytes_initial = piexif.dump(exif_dict_initial)
img.save(dummy_image_path, exif=exif_bytes_initial)
exif_dict = piexif.load(dummy_image_path)
print("Original Camera Make:", exif_dict["0th"][piexif.ImageIFD.Make])
# 2. Modify an EXIF tag
exif_dict["0th"][piexif.ImageIFD.Make] = "PiexifModified"
# 3. Dump the modified EXIF data to bytes
exif_bytes = piexif.dump(exif_dict)
# 4. Insert the new EXIF data into an image (or save with Pillow)
img_to_modify = Image.open(dummy_image_path)
img_to_modify.save(new_image_path, exif=exif_bytes)
# 5. Verify the change
modified_exif_dict = piexif.load(new_image_path)
print("Modified Camera Make:", modified_exif_dict["0th"][piexif.ImageIFD.Make])
finally:
# Clean up dummy files
if os.path.exists(dummy_image_path):
os.remove(dummy_image_path)
if os.path.exists(new_image_path):
os.remove(new_image_path)