EZ LearnEZ Learn
Courses
EZ Board
Dashboard
All articles
python-for-cyber-securitypythondigital-forensicsexif

Image Metadata: EXIF Data

A single photograph gave away a fugitive's exact location. EXIF metadata is a hidden diary riding along with every picture: camera, timestamp and often GPS, all invisible on screen.

Ashish Revar17 October 20266 min read
1 video lesson 6:09 total
Sign in to track your progress

Video lesson

Indexing tells an investigator what exists. The next step is extraction: pulling the useful content out, and in digital forensics the useful content is often metadata the file's author never meant to share.

A single photograph fileVisible contentthe picture you seeHidden EXIF metadatacamera modeldate and timeGPS coordinates
Figure 3.2. A file carries hidden metadata alongside its visible content. In forensics, the hidden half is often where the evidence lives.

Reading a photograph's hidden diary

A photograph from a phone or camera typically carries EXIF metadata: the device model, the date and time, and frequently the GPS coordinates of where it was taken, unless an app has stripped them.

extract_exif.py

# extract_exif.py
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def extract_exif(image_path):
    raw = Image.open(image_path)._getexif()
    if not raw:
        return {}
    return {TAGS.get(tag_id, tag_id): value for tag_id, value in raw.items()}

def extract_gps(exif_data):
    gps = exif_data.get("GPSInfo")
    if not gps:
        return None
    return {GPSTAGS.get(k, k): v for k, v in gps.items()}

data = extract_exif("evidence_copy/photo_001.jpg")
print(f"Camera model: {data.get('Model', 'unknown')}")
print(f"Date taken: {data.get('DateTimeOriginal', 'unknown')}")
gps = extract_gps(data)
print(f"GPS data present: {gps}" if gps else "No GPS data in this image")

Sample output

Camera model: iPhone 13
Date taken: 2026:09:14 18:42:07
GPS data present: {'GPSLatitudeRef': 'N', 'GPSLatitude': (23.0, 13.0, 4.44), 'GPSLongitudeRef': 'E', 'GPSLongitude': (72.0, 38.0, 12.84)}

Those coordinates place the photograph in Gandhinagar to within a few metres. A picture that looks innocent on screen just disclosed exactly where it was taken, which is the whole lesson of the McAfee case below.

Python concept: _getexif() is Pillow's older, simpler method

_getexif() is a private method Pillow keeps for backward compatibility, and it conveniently flattens the standard Exif sub-fields and the GPS block into one plain dictionary, exactly as used above. Current Pillow code is encouraged to use the public .getexif() method instead, together with .get_ifd(0x8825) for the GPS block, which is more explicit about where each field actually lives inside the file. Either approach reads the same underlying data; _getexif() is simply the shorter route for a script like this one.

GPS coordinates in EXIF are stored as degrees, minutes and seconds, not plain decimal degrees, which is why GPSLatitude prints as a tuple like (23.0, 13.0, 4.44) rather than a single number such as 23.2179. Converting between the two is ordinary arithmetic:

dms_to_decimal.py

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

lat = dms_to_decimal((23.0, 13.0, 4.44), "N")
lon = dms_to_decimal((72.0, 38.0, 12.84), "E")
print(f"{lat:.4f}, {lon:.4f}")

Sample output

23.2179, 72.6369

Paste those two numbers into any map and the exact spot appears.

Real incident: John McAfee, 2012: a photograph that gave away a hideout

In December 2012, the software entrepreneur John McAfee was wanted for questioning by authorities in Belize and had gone into hiding. While on the run, he gave an interview to journalists from Vice magazine, who posted a photo of him to their website from a mobile phone. The photograph's EXIF metadata, the exact fields the code above reads, still contained the GPS coordinates where it was taken, which placed McAfee at a specific location in Guatemala. The coordinates were noticed within hours of the photo going online, and he was located shortly afterward.

What this teaches: the GPS fields extract_gps() pulls out are not a theoretical risk. A single photograph, shared without stripping its metadata, located a man who was actively trying not to be found. For an investigator this is a lead; for everyone else it is a reminder that a photograph carries a hidden diary of where and when it was taken.

Try it yourself: Check your own photographs

Most phones let you check whether location tagging was on when a photo was taken. Pick a recent photo of your own, run extract_exif.py against it, and see what it reveals. If GPS data is present, you have just reproduced, on a photo you control, exactly what located McAfee.

Check your understanding

Question 1: What kinds of information can EXIF metadata reveal about a photograph that are not visible on screen?

The device model and manufacturer, the exact date and time the photo was taken, and often the GPS coordinates of where it was taken, all stored separately from the visible picture and invisible to anyone just looking at the image.

Question 2: Why does extract_gps() need a separate function instead of reading the coordinates straight off the top-level exif data?

GPS fields in EXIF are stored inside their own nested block, identified by the key GPSInfo, with their own set of tag numbers that need the separate GPSTAGS lookup table to become readable field names. Treating them exactly like the top-level fields would either miss them or produce unreadable numeric keys.

Question 3: In the McAfee case, what specifically let investigators locate him, and why was it invisible to someone just viewing the photo?

The GPS coordinates embedded in the photograph's EXIF metadata. They are invisible because EXIF metadata sits alongside, not inside, the visible picture; nothing about looking at the photo on screen reveals that the coordinates are riding along with it.

Key takeaway: Key takeaway

A photograph is two documents in one: the picture anyone can see, and a hidden diary of camera, timestamp and often exact location. Pillow reads that diary in a few lines, and the McAfee case shows what one unstripped photograph can give away.

Assessments

Unit Assessment

Digital Forensics with Python

20 questions30 minPass: 60%

Start exam →

Comprehensive Assessment

Python for Cyber Security: Complete Assessment

100 questions120 minPass: 60%

Start final exam →

Related to this topic

Continue learning

Reference material

Cheatsheet

Python for Cyber Security — Cheatsheet

v1.0

Open resource

MCQ Bank

Python for Cyber Security — MCQ Bank

v1.0

Open resource

Question Bank

Python for Cyber Security — Question Bank

v1.0

Open resource

eBook

Python for Cyber Security — eBook

v1.0

Open resource

Discussion

Loading comments…
More articlesTest your knowledge
EZ MentorAI · Free

Image Metadata: EXIF Data

Hi! I'm EZ Mentor

Your AI tutor for
Image Metadata: EXIF Data

Sign in to ask, it's free.

EZ Mentor is AI-powered · Answers may not be perfect · 10 free questions / day

EZ LearnEZ Learn

Structured learning across Reverse Engineering, Cloud Security, and Research Methodology, plus games and practice tools in EZ Arena. Free, and open to anyone.

EZ Learn

  • Courses
  • EZ Articles
  • EZ Watch
  • EZ Talks
  • EZ Bytes
  • Cyber Hygiene

EZ Library

  • All Resources
  • eBooks & PDFs
  • Question Banks
  • MCQ Banks
  • Cheatsheets

EZ Exams

  • All Exams
  • REMA
  • Cloud Security
  • Research Methodology
  • Python for Cyber Security
  • Cyber Law & IPR
  • Community
  • EZ Board

EZ Arena

  • EZ Games
  • Live Quiz
  • ML Challenges
  • दिशा - Hygiene
  • सजग - Awareness
  • अभ्यास - Practice

Platform

  • About
  • Contact
  • Terms of Use
  • Disclaimer
  • Verify Certificate
  • Events

© 2026 EZ Learn by EpochZero. Educational content for learning purposes.

Platform Lead: Ashish Revar