Privacy Tools Guide

When you capture a photo with your smartphone, the image file contains more than just pixel data. Modern mobile phones embed extensive metadata within each photo, including GPS coordinates, device information, timestamps, and camera settings. This metadata, known as EXIF (Exchangeable Image File Format), can reveal sensitive information about your location, habits, and device. For developers and power users who value privacy, understanding how to strip EXIF location data before sharing photos becomes essential.

Understanding EXIF Location Data

EXIF data lives inside image files themselves, added automatically by your phone’s camera application. Location data appears as GPS coordinates stored in specific EXIF tags: GPSLatitude, GPSLongitude, GPSAltitude, and related fields. When you share a photo directly from your phone’s gallery, you may inadvertently transmit this embedded location information to recipients or third-party platforms.

The implications extend beyond simple privacy concerns. Metadata can reveal your home address, workplace, travel patterns, and the exact times you visit specific locations. Social media platforms, messaging apps, and cloud storage services may retain this metadata even after you upload images, creating lasting records of your movements.

Inspecting EXIF Metadata

Before removing metadata, you should understand what information your photos contain. Several tools allow you to examine EXIF data from the command line.

The exiftool utility, created by Phil Harvey, provides metadata inspection:

# Install on macOS
brew install exiftool

# View all EXIF data from an image
exiftool photo.jpg

# Extract only GPS coordinates
exiftool -gps:all photo.jpg

# List all tags containing "GPS" in the name
exiftool -s -s -s -gps:all photo.jpg

For a lighter-weight alternative, the identify command from ImageMagick displays basic metadata:

identify -verbose photo.jpg | grep -i gps

Python’s Pillow library offers programmatic access:

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

def get_exif_data(image_path):
    image = Image.open(image_path)
    exif_data = image._getexif()

    if not exif_data:
        return {}

    gps_info = {}
    for tag, value in exif_data.items():
        tag_name = TAGS.get(tag, tag)
        if tag_name == "GPSInfo":
            for gps_tag in value:
                gps_tag_name = GPSTAGS.get(gps_tag, gps_tag)
                gps_info[gps_tag_name] = value[gps_tag]

    return gps_info

gps_data = get_exif_data("photo.jpg")
print(gps_data)

Stripping EXIF Data with Command-Line Tools

Once you identify the metadata, removing it requires several approaches depending on your workflow.

Using exiftool

The most straightforward method uses exiftool with the -all= flag to remove all metadata:

# Remove all metadata, creating a new file
exiftool -all= -overwrite_original photo.jpg

# Remove only GPS data while preserving other metadata
exiftool -gps:all= -overwrite_original photo.jpg

# Batch process all JPEG files in a directory
exiftool -all= -overwrite_original *.jpg

The -overwrite_original flag modifies the original file. Remove this flag to create copies instead.

Using ImageMagick

ImageMagick’s mogrify command strips metadata by default when converting images:

# Convert to PNG (strips EXIF automatically)
mogrify -format png photo.jpg

# Explicitly remove metadata during conversion
mogrify -strip photo.jpg

The -strip flag removes all image profiles and metadata.

Using Python

For programmatic batch processing, Pillow handles metadata removal:

from PIL import Image
import os

def strip_exif(input_path, output_path=None):
    image = Image.open(input_path)

    # Create a new image without EXIF data
    data = list(image.getdata())
    clean_image = Image.new(image.mode, image.size)
    clean_image.putdata(data)

    # Save without EXIF
    if output_path is None:
        output_path = input_path

    clean_image.save(output_path, image.format)
    print(f"Stripped EXIF from {input_path}")

# Batch process directory
for filename in os.listdir("./photos"):
    if filename.lower().endswith((".jpg", ".jpeg", ".png")):
        strip_exif(f"./photos/{filename}")

A more efficient approach uses the ImageOps.exif_transpose() method, which also corrects orientation:

from PIL import Image, ImageOps

def strip_exif_efficient(input_path, output_path=None):
    with Image.open(input_path) as image:
        # Correct orientation based on EXIF
        image = ImageOps.exif_transpose(image)

        # Save without metadata
        if output_path is None:
            output_path = input_path

        # Preserve format and quality
        save_kwargs = {}
        if image.format == "JPEG":
            save_kwargs["quality"] = 95

        image.save(output_path, **save_kwargs)

Platform-Specific Solutions

Android

Android developers can use the androidx.exifinterface library to manipulate EXIF data:

import androidx.exifinterface.media.ExifInterface

fun removeExifFromFile(filePath: String) {
    val exif = ExifInterface(filePath)

    // Clear all GPS-related tags
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE, null)
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, null)
    exif.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, null)
    exif.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, null)
    exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, null)
    exif.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, null)

    exif.saveAttributes()
}

For complete removal, create a new file and copy only pixel data.

iOS

iOS developers work with CGImageSource and CGImageDestination from the Core Graphics framework:

import ImageIO
import UniformTypeIdentifiers

func stripEXIF(from url: URL) -> Data? {
    guard let source = CGImageSourceCreateWithURL(url as CFURL, nil),
          let uti = CGImageSourceGetType(source),
          let mutableData = CFDataCreateMutable(nil, 0),
          let destination = CGImageDestinationCreateWithData(mutableData, uti, 1, nil) else {
        return nil
    }

    let removeProperties: [CFString: Any] = [
        kCGImageDestinationLossyCompressionQuality: 1.0
    ]

    CGImageDestinationAddImageFromSource(destination, source, 0, removeProperties as CFDictionary)
    CGImageDestinationFinalize(destination)

    return mutableData as Data
}

Automating the Workflow

For developers who frequently share photos, automation scripts improve the process. A simple shell script processes incoming images:

#!/bin/bash

INPUT_DIR="$1"
OUTPUT_DIR="$2"

mkdir -p "$OUTPUT_DIR"

for image in "$INPUT_DIR"/*.jpg "$INPUT_DIR"/*.jpeg; do
    if [ -f "$image" ]; then
        filename=$(basename "$image")
        exiftool -all= -overwrite_original -o "$OUTPUT_DIR/$filename" "$image"
        echo "Processed: $filename"
    fi
done

Git pre-commit hooks can automatically strip metadata from images added to repositories:

# .git/hooks/pre-commit
#!/bin/bash

for image in $(git diff --cached --name-only --diff-filter=AM | grep -E '\.(jpg|jpeg|png)$'); do
    if [ -f "$image" ]; then
        exiftool -all= -overwrite_original "$image"
        git add "$image"
    fi
done

Best Practices for Privacy

When handling mobile photo metadata, consider these guidelines:

Default to stripping metadata unless you specifically need it. Remove location data before sharing on social platforms or messaging applications.

Verify after processing by re-inspecting files with exiftool to confirm sensitive data no longer exists.

Preserve originals by keeping unmodified copies in a secure location while distributing stripped versions.

Automate your workflow using scripts or alias shortcuts for commonly-used commands. Adding this to your shell profile:

alias strip-gps='exiftool -gps:all= -overwrite_original'

This allows quick GPS removal from the current directory with a single command.

Built by theluckystrike — More at zovo.one