Pheser
Photo Metadata Privacy Toolkit -- scan, clean, redact, compare, and export EXIF metadata from images.
pip install pheser
Features
| Feature | Description |
|---|---|
| Scan | Full EXIF dump with privacy risk score (0-100) and Google Maps link for GPS |
| Clean | Remove GPS only, all EXIF, specific tags, or keep-only-safe-tags mode |
| Remake | Recreate metadata with custom Make/Model/DateTime/GPS values |
| Redact | Spoof GPS coordinates, randomize timestamps, replace device info |
| Compare | Diff EXIF between two images (before/after verification) |
| Batch | Process entire directories recursively with any operation |
| Export | Save scan results as JSON, CSV, or plain-text report |
Orientation and display geometry tags are always preserved -- your image will never be rotated by Pheser.
Installation
pip install pheser
Requirements: Python 3.11+, Pillow >= 10.0, piexif >= 1.1.3
CLI
Scan
pheser scan photo.jpg
pheser scan photo.jpg --export report.json --fmt json
pheser scan photo.jpg --export report.csv --fmt csv
pheser scan photo.jpg --no-hash --no-risk
Clean
# Remove GPS only (default)
pheser clean photo.jpg
# Strip ALL EXIF
pheser clean photo.jpg --mode all
# Remove specific tags
pheser clean photo.jpg --mode tags --tags Make Model Software
# Keep only safe tags (removes GPS + device serials + owner info)
pheser clean photo.jpg --mode keep_basic -o safe_photo.jpg
Remake
pheser remake photo.jpg --make Sony --model "Alpha 7" --artist "Jane Doe"
pheser remake photo.jpg --inject-gps 48.8584 2.2945
Redact (Spoof)
# Replace GPS with random coordinates
pheser redact photo.jpg --random-gps
# Spoof exact location
pheser redact photo.jpg --spoof-gps 51.5074 -0.1278
# Randomize everything
pheser redact photo.jpg --random-gps --random-datetime --spoof-device Apple "iPhone 15"
Compare
pheser compare original.jpg cleaned.jpg
Batch
pheser batch ./photos --op clean-gps --out-dir ./photos_clean
pheser batch ./photos --op redact-random --recursive
pheser batch ./photos --op clean-all --dry-run
Python API
from pheser import scan, clean, redact, remake, batch_process
from pheser.compare import compare
from pheser.exporter import export_report
# Scan
results = scan("photo.jpg", raw=True)
print(results["risk_score"]) # 0-100
print(results["gps"]) # {"latitude": ..., "maps_url": ...}
# Clean GPS
clean("photo.jpg", mode="gps")
# Strip all EXIF
clean("photo.jpg", mode="all", output_file="stripped.jpg")
# Remove specific tags
clean("photo.jpg", mode="tags", remove_tags=["Make", "Model", "Software"])
# Keep only safe metadata
clean("photo.jpg", mode="keep_basic")
# Spoof GPS + randomize datetime
redact("photo.jpg", randomize_gps=True, randomize_datetime=True)
# Inject fake GPS
redact("photo.jpg", spoof_gps=(35.6762, 139.6503)) # Tokyo
# Recreate with custom values
remake("photo.jpg", make="Fujifilm", model="X100V", artist="John")
# Compare two files
diff = compare("before.jpg", "after.jpg")
# Export scan report
results = scan("photo.jpg", raw=True)
export_report(results, "report.json", fmt="json")
export_report(results, "report.csv", fmt="csv")
export_report(results, "report.txt", fmt="txt")
# Batch process a folder
batch_process(
"photos/",
lambda src, dst: clean(src, dst, mode="gps", verbose=False),
out_dir="photos_clean/",
recursive=True,
)
Privacy Risk Score
| Score | Label | Meaning |
|---|---|---|
| 0 | Safe | No sensitive metadata |
| 1-19 | Low | Minor device info only |
| 20-49 | Medium | Device + timestamps present |
| 50-100 | High | GPS location data found |
Supported Formats
.jpg / .jpeg -- .tiff / .tif -- .webp
License
MIT -- Copyright (c) 2025 AzzTE
Metadata
Release files for pheser 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pheser-1.0.0.tar.gz | 16.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pheser-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.7 kB
Release files / pheser-1.0.0.tar.gz
| Download URL | pheser-1.0.0.tar.gz |
|---|---|
| Size | 16.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bb9e801ca5b0d12c2e1c22042f8dd4b55beb012577a695817e47e74144f1992b
|
|
BLAKE2b-256 checksum How to use checksums |
3cab8206ec4e6a1eec2a50e2b7428cb34276af2a88923e9917e73b2b643144f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / pheser-1.0.0-py3-none-any.whl
| Download URL | pheser-1.0.0-py3-none-any.whl |
|---|---|
| Size | 19.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
08d677bdf8c2c9f4d68cdd1e4d7a71f69d02bcddc4d94b8d2ca78f7dd5bafca7
|
|
BLAKE2b-256 checksum How to use checksums |
8368c16c9afdd7b7ec63ef90b0762ba32a6705e9cda85d02bcccd95c7eda187a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|