Introduction
Every photo you take contains more than meets the eye.
Hidden inside are EXIF metadata tags — GPS coordinates, camera serial numbers, timestamps, copyright notices, and even software info. While useful for photographers, this data can leak way more about you than you’d expect when you post a picture online.
So I wanted a simple tool that I could use on my own photos. My old process was a mess — a half-remembered crib sheet, three separate commands, and too much context-switching. I hated it. So I built something better. A robust, flexible little CLI tool for managing image metadata. I find it useful enough that I keep using it and polishing it.
My best elevator pitch:
Metaclean is a small, pipe-friendly CLI tool that scans images for metadata and safely strips it away, with the right defaults so you won’t accidentally destroy your originals.
Perfect for:
- Preparing photos for blog posts or public sharing
- Stripping GPS coordinates from family photos
- Cleaning a folder before archiving or handing off to clients
Quickstart
# Scan for metadata
metaclean --scan photo.jpg
# Strip metadata (safe copy in ~/Pictures/cleaned/)
metaclean --strip photo.jpg
Works with JPG, PNG, WebP and TIFF
Features
- Safe by default: writes copies with
_clean
added to the filename unless--inplace
is specified - Scan EXIF metadata including GPS, camera details, and copyright information
- Strip all metadata by default, rebuilding clean EXIF from scratch
- Add copyright tags with
--copyright
- Preserve specific tags with
--keep-date
,--keep-orientation
,--keep-icc
,--keep-dpi
- Pipe-friendly: works with
find
,xargs
,fd
, and similar tools
Usage
metaclean (--scan | --strip)
[OPTIONS] [FILES…]
Options:
--scan
— Scan and report metadata.--strip
— Strip metadata (writes clean copies unless--inplace
).--positives
— Only show files that contain metadata (scan mode).--show-gps
— Expand GPS info when scanning.--inplace
— Overwrite originals (safe atomic replace).--outdir DIR
— Directory for cleaned files (default:~/Pictures/cleaned
).--copyright TEXT
— Add a copyright tag.--keep-date
— PreserveDateTimeOriginal
tag.--keep-orientation
— Preserve orientation tag (pixels still corrected if not kept).--keep-icc
— Preserve ICC profile.--keep-dpi
— Preserve DPI.--force
— Process first frame of animated images (otherwise skipped).--quality N
— JPEG quality (default:95
).--progressive 0|1
— Force progressive JPEG encoding on (1
) or off (0
).
# Scan a single image for metadata
metaclean --scan photo.jpg
# Scan only images that have metadata (quiet mode)
metaclean --scan --positives ~/Pictures/*.jpg
# Strip metadata from a single file (safe copy in ~/Pictures/cleaned/)
metaclean --strip photo.jpg
# Strip metadata and overwrite originals (use with care)
metaclean --strip --inplace *.jpg
# Strip metadata but keep the original date and orientation tags
metaclean --strip --keep-date --keep-orientation *.jpg
# Add a copyright tag to your images
metaclean --strip --copyright "© forfaxx" ~/Photos/*.jpg
# Find all JPGs with metadata, then strip them in-place
find ~/Pictures -name '*.jpg' \
| metaclean --scan --positives \
| metaclean --strip --inplace
Example Output
forfaxx@shinobi ]:/mnt/d/sort
$ metaclean --scan misc040.jpg
=== Metadata for misc040.jpg ===
ResolutionUnit: 2
ExifOffset: 196
Make: Canon
Model: Canon PowerShot G3
Orientation: 1
DateTime: 2005:11:02 19:05:35
YCbCrPositioning: 1
XResolution: 180.0
YResolution: 180.0
forfaxx@shinobi ]:/mnt/d/sort
$ metaclean --strip --inplace misc040.jpg
[OK] Stripped metadata IN PLACE → misc040.jpg
forfaxx@shinobi ]:/mnt/d/sort
$ metaclean --scan misc040.jpg
[INFO] No EXIF metadata found in misc040.jpg

misc040-exif.jpg
— original file with EXIF (camera model, timestamp, etc.).

misc040.jpg
— cleaned by metaclean
(no EXIF; pixels preserved).

Using metaclean
in a pipeline or script
metaclean
is designed to work well in pipelines and scripts. A few examples:
Show me files with metadata (dry-run)
# Scan repo images and list only files that contain metadata
git ls-files -z -- '*.jpg' '*.jpeg' '*.png' '*.webp' '*.tif' '*.tiff' \
| xargs -0 metaclean --scan --positives \
| tee /tmp/metaclean_positives.txt
echo "Files with metadata: $(wc -l < /tmp/metaclean_positives.txt)"
In-place strip of only what’s staged for commit (pre-commit friendly)
# Safe atomic replace (your script’s default behavior) on staged images
git diff --cached --name-only -z -- '*.jpg' '*.jpeg' '*.png' '*.webp' '*.tif' '*.tiff' \
| xargs -0 metaclean --strip --inplace --keep-icc --keep-dpi
# Re-stage files that changed (helps if hook runs before commit)
git add --update
One-liner to strip everything under current directory into ~/Pictures/cleaned
find . -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \
-o -iname '*.webp' -o -iname '*.tif' -o -iname '*.tiff' \) -print0 \
| xargs -0 metaclean --strip --outdir "${HOME}/Pictures/cleaned"
- Makefile target for “pre-publish:clean-images”
# Makefile
IMGS := $(shell git ls-files -- '*.jpg' '*.jpeg' '*.png' '*.webp' '*.tif' '*.tiff')
OUT := static/img-clean
.PHONY: images-clean
images-clean:
@mkdir -p $(OUT)
@echo "→ Scanning and cleaning images into $(OUT)…"
@printf '%s\0' $(IMGS) \
| xargs -0 metaclean --scan --positives \
| metaclean --strip --keep-icc --keep-dpi --outdir $(OUT)
@echo "✓ Done."
# Optional: fold into your publish chain
publish: images-clean
./sync-adminjitsu.sh
Links and Stuff
- https://en.wikipedia.org/wiki/Metadata
- https://en.wikipedia.org/wiki/Exif
- https://www.canon-europe.com/pro/infobank/all-about-exif/
- https://dev.exiv2.org/projects/exiv2/wiki/The_Metadata_in_PNG_files
- https://pillow.readthedocs.io/en/stable/
Conclusion
Whether you’re cleaning up a single selfie or prepping an archive for public release, metaclean
has your back.
Have a neat pipeline or trick?
PRs and issues welcome! Or email me: feedback@adminjitsu.com