programming

How to Get Metadata of Image in Python

admin · 10 min read · July 29, 2024
How to Get Metadata of an Image in Python (Pillow, exifread, ExifTool, GPS & IPTC/XMP) — 2026 Guide
ProgrammingInsider Updated September 2026
Python · Image Processing

How to Get Metadata of an Image in Python

A complete, working guide to reading, adding, and removing Exif, GPS, IPTC, and XMP metadata from images using Pillow, exifread, piexif, and ExifTool — with fixes for the method Pillow removed.

12 min read Python 3.9+ Pillow 10+ compatible
What changed in this update The original version of this guide relied on img._getexif(), a private Pillow method that was removed in Pillow 10 and now raises an AttributeError. Every example below uses the current public API, adds human-readable tag names (which most competing tutorials skip), and adds GPS decoding and IPTC/XMP coverage that weren’t in the original article.

Metadata is the information a camera, phone, or editing tool stores inside an image file alongside the actual pixels — things like the capture date, camera model, exposure settings, and sometimes GPS coordinates. If you’re building a photo organizer, a forensic tool, a bulk watermarking script, or just need to strip GPS data before publishing a photo, Python gives you several ways to read and write it. This guide covers all of them.

What image metadata actually is

Metadata generally falls into three standards, and which one you need depends on the task:

  • Exif (Exchangeable Image File Format) — camera settings and capture conditions: aperture, shutter speed, ISO, focal length, timestamp, and GPS location. Present mainly in JPEG and TIFF files from cameras and phones.
  • IPTC (International Press Telecommunications Council) — editorial fields used in journalism and stock photography: caption, keywords, byline, and copyright notice. Added manually or by asset-management software, not by the camera.
  • XMP (Extensible Metadata Platform) — an Adobe-designed, XML-based format that can carry Exif- and IPTC-like fields plus custom data, and can be embedded in far more file types (PDF, video, PNG) than Exif can.

Pillow and exifread only read Exif. For IPTC and XMP you need a separate library, covered further down.

Setup

Install the libraries used in this guide as you need them — you don’t need all of them for every task:

terminal
pip install Pillow exifread piexif iptcinfo3 python-xmp-toolkit

You’ll also need a sample image that actually contains Exif data. Photos exported from Instagram, WhatsApp, or Photoshop’s “Save for Web” are frequently stripped of metadata — use an original, unedited photo straight off a phone or camera to follow along.

Reading metadata with Pillow

Pillow is the most common way to touch image metadata in Python. The method used in most older tutorials, img._getexif(), was undocumented and has been removed as of Pillow 10. Use Image.getexif() instead, paired with TAGS so you get readable field names rather than numeric IDs.

python
from PIL import Image
from PIL.ExifTags import TAGS

img = Image.open("example.jpg")
exif_data = img.getexif()

if not exif_data:
    print("No Exif data found in this image.")
else:
    for tag_id, value in exif_data.items():
        tag_name = TAGS.get(tag_id, tag_id)
        print(f"{tag_name:25}: {value}")

This prints things like camera make, model, and orientation. Some fields — including GPS data — live in a nested IFD (image file directory) rather than the top-level dictionary, which is why a plain loop sometimes looks emptier than you’d expect from a photo you know has metadata. Pillow exposes those nested IFDs through get_ifd():

python
from PIL.ExifTags import IFD

exif_ifd = exif_data.get_ifd(IFD.Exif)
for tag_id, value in exif_ifd.items():
    tag_name = TAGS.get(tag_id, tag_id)
    print(f"{tag_name:25}: {value}")
PNG and WebP files PNG rarely carries Exif. If you’re working with PNGs, check img.info instead — tools like Stable Diffusion and many screenshot utilities store metadata as plain text chunks there (img.info.get("parameters") is a common key for AI-generated images, for example).

Reading metadata with exifread

exifread is a dedicated Exif parser that tends to surface more tags — including GPS, thumbnail, and maker-note fields — than Pillow does by default, and it works without decoding the full image.

python
import exifread

with open("example.jpg", "rb") as f:
    tags = exifread.process_file(f, details=False)

for tag, value in tags.items():
    if tag not in ("JPEGThumbnail", "TIFFThumbnail"):
        print(f"{tag:30}: {value}")

details=False skips the thumbnail and maker-note blobs, which keeps the output readable for a quick inspection.

Extracting GPS coordinates

This is the part most tutorials on this topic skip entirely, even though it’s usually the actual reason someone wants image metadata — checking or stripping the location a photo was taken at. GPS data is stored as degrees/minutes/seconds, so it needs a conversion step to become a usable latitude/longitude pair.

python
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def get_gps_coordinates(path):
    img = Image.open(path)
    exif_data = img.getexif()
    gps_ifd = exif_data.get_ifd(next(k for k, v in TAGS.items() if v == "GPSInfo"))

    if not gps_ifd:
        return None

    gps = {GPSTAGS.get(k, k): v for k, v in gps_ifd.items()}

    def to_decimal(dms, ref):
        degrees, minutes, seconds = dms
        decimal = float(degrees) + float(minutes) / 60 + float(seconds) / 3600
        if ref in ("S", "W"):
            decimal = -decimal
        return decimal

    lat = to_decimal(gps["GPSLatitude"], gps["GPSLatitudeRef"])
    lon = to_decimal(gps["GPSLongitude"], gps["GPSLongitudeRef"])
    return lat, lon

coords = get_gps_coordinates("example.jpg")
print(coords or "No GPS data in this image.")

The result is a plain (latitude, longitude) tuple you can drop straight into Google Maps, a geocoding API, or a mapping library like Folium.

Reading everything with ExifTool

ExifTool isn’t a Python library — it’s a standalone command-line tool — but it reads more metadata formats (Exif, IPTC, XMP, maker notes, and video metadata) than any single Python package, so it’s worth calling from a script via subprocess when you need full coverage rather than just Exif.

terminal
# Windows (via Chocolatey)
choco install exiftool

# macOS
brew install exiftool

# Debian/Ubuntu
sudo apt install libimage-exiftool-perl
python
import subprocess, json

result = subprocess.run(
    ["exiftool", "-json", "example.jpg"],
    capture_output=True, text=True
)
metadata = json.loads(result.stdout)[0]

for key, value in metadata.items():
    print(f"{key:25}: {value}")

Using -json gives you a structured dictionary instead of parsing plain-text output, which is far easier to work with programmatically.

Reading IPTC and XMP metadata

Neither Pillow nor exifread touches IPTC or XMP. If a task needs captions, keywords, or copyright fields set by editorial software, reach for a library built for that standard instead.

IPTC with iptcinfo3

python
from iptcinfo3 import IPTCInfo

info = IPTCInfo("example.jpg", force=True)
print("Caption:", info["caption/abstract"])
print("Keywords:", info["keywords"])
print("Byline:", info["by-line"])

XMP with python-xmp-toolkit

python
from libxmp.utils import file_to_dict

xmp = file_to_dict("example.jpg")
for namespace, fields in xmp.items():
    for field in fields:
        print(namespace, field)

python-xmp-toolkit wraps Adobe’s Exempi C library, so on Linux you may need sudo apt install libexempi8 before pip install will build successfully.

Writing and adding metadata

To modify Exif data, use piexif — it handles the binary Exif structure so you don’t have to build it by hand.

Editing an existing tag

python
import piexif
from PIL import Image

img = Image.open("example.jpg")
exif_dict = piexif.load(img.info.get("exif", b""))

exif_dict["0th"][piexif.ImageIFD.Artist] = "Your Name"

exif_bytes = piexif.dump(exif_dict)
img.save("example_with_metadata.jpg", exif=exif_bytes)

Using img.info.get("exif", b"") instead of indexing img.info["exif"] directly avoids a KeyError on images that have no Exif block yet.

Adding new tags from scratch

python
import piexif
from PIL import Image

img = Image.open("example.jpg")

exif_dict = {
    "0th": {
        piexif.ImageIFD.Artist: "Your Name",
        piexif.ImageIFD.Make: "Your Camera Make",
        piexif.ImageIFD.Model: "Your Camera Model",
    },
    "Exif": {
        piexif.ExifIFD.DateTimeOriginal: "2026:09:01 10:00:00",
    },
}

exif_bytes = piexif.dump(exif_dict)
img.save("example_with_new_metadata.jpg", exif=exif_bytes)

Adding metadata with ExifTool instead

python
import subprocess

subprocess.run([
    "exiftool",
    "-Artist=Your Name",
    "-Make=Your Camera Make",
    "-Model=Your Camera Model",
    "-DateTimeOriginal=2026:09:01 10:00:00",
    "-overwrite_original",
    "example.jpg",
])

ExifTool can also write IPTC and XMP fields the same way (for example, -Caption-Abstract=... or -XMP:Title=...), which piexif cannot, since piexif is Exif-only.

Removing metadata

Stripping metadata is one of the most common real-world reasons to touch this at all — usually before publishing a photo publicly.

python
# Option 1: Pillow — re-save without passing exif data
from PIL import Image

img = Image.open("example.jpg")
data = list(img.getdata())
clean_img = Image.new(img.mode, img.size)
clean_img.putdata(data)
clean_img.save("clean.jpg")

# Option 2: ExifTool — strips Exif, IPTC, and XMP in one pass
import subprocess
subprocess.run(["exiftool", "-all=", "example.jpg", "-overwrite_original"])

The Pillow approach rebuilds the image from raw pixel data, which drops the Exif block entirely. ExifTool’s -all= is the more thorough option since it also clears IPTC and XMP, which the Pillow method leaves untouched.

Library comparison

LibraryReadsWritesFormats supportedBest for
PillowExif, GPS (via IFD)No (pair with piexif)JPEG, TIFF, PNG text chunksQuick reads inside an existing image-processing pipeline
exifreadExif, GPS, thumbnailsNoJPEG, TIFFDeep Exif inspection without decoding pixels
piexifExifYesJPEG, TIFFAdding or editing Exif tags in Python
iptcinfo3IPTCYesJPEGEditorial captions, keywords, bylines
python-xmp-toolkitXMPYesJPEG, PNG, PDF, videoXMP packets and custom namespaces
ExifTool (CLI)Exif, IPTC, XMP, maker notesYes500+ formatsOne tool that reads and writes everything

Common errors and fixes

ErrorCauseFix
AttributeError: 'Image' object has no attribute '_getexif'Pillow 10+ removed the private methodUse img.getexif()
exif_data is empty or NoneImage has no Exif block (PNG, screenshot, or metadata already stripped)Check with if not exif_data before iterating
KeyError: 'exif' on piexif.load(img.info['exif'])Image has no existing Exif segment to loadUse img.info.get("exif", b"")
Tag values print as raw bytes, e.g. b'2026:09:01'Some Exif fields are stored as bytes, not stringsCall .decode() on the value if isinstance(value, bytes)
GPS tags missing after looping exif_data.items()GPS lives in a nested IFD, not the top levelUse exif_data.get_ifd(...) as shown above

A privacy note worth acting on

Strip GPS before you publish Photos taken on a phone with location services on almost always embed exact GPS coordinates. If you’re building anything that lets users upload images publicly — a listing site, a forum, a portfolio — strip GPS/Exif data server-side before storage, using the removal code above, rather than relying on users to do it themselves.

FAQ

What is image metadata?

Information embedded in an image file describing the image itself — capture date, camera settings, GPS location, author, and copyright — separate from the pixel data.

How do I get metadata from an image in Python?

Use Image.getexif() from Pillow together with PIL.ExifTags.TAGS for human-readable names, or use exifread for a wider set of Exif and GPS tags.

Why does img._getexif() fail in newer Pillow versions?

It was a private, undocumented method removed in Pillow 10. Use the public Image.getexif() method instead.

How do I extract GPS coordinates from a photo in Python?

Read the GPSInfo Exif tag, map its sub-tags with GPSTAGS, then convert the degrees/minutes/seconds values to decimal latitude and longitude, as shown in the GPS section above.

Can Python read IPTC and XMP metadata, not just Exif?

Yes — use iptcinfo3 for IPTC fields and python-xmp-toolkit for XMP packets, since Pillow and exifread only cover Exif.

How do I add metadata to a JPG in Python?

Build an Exif dictionary with piexif, dump it to bytes with piexif.dump(), and pass it to img.save(path, exif=exif_bytes).

How do I remove all metadata from an image?

Re-save the image with Pillow without an exif argument, or run exiftool -all= file.jpg -overwrite_original to strip Exif, IPTC, and XMP together.

Does Exif work on PNG files?

Rarely. PNG doesn’t natively store Exif the way JPEG and TIFF do; check img.info for text chunks instead, which is where tools like screenshot utilities and AI image generators often store metadata.

Is ExifTool a Python library?

No — it’s a standalone command-line program, called from Python via the subprocess module. It covers more metadata formats than any single Python package.

Why is my exif_data empty?

Most likely the image genuinely has no Exif block — this is common for images downloaded from social media, screenshots, or files already run through a metadata stripper.

© 2026 Programming Insider — Reviewed and updated for Pillow 10+ compatibility.

Leave a Reply