Skip to main content

🧼 imgstrip

Share the picture. Keep everything else to yourself.

Photos quietly carry your location, your camera, the time you took them, and sometimes more. imgstrip removes all of it, then checks its own work before it saves anything.

PyPI License: AGPL v3

Quick start · How it works · Everyday use · Web app · Good to know


Why imgstrip?

Most metadata removers delete the tags they recognize and copy the rest of the file untouched. Anything they don't recognize survives.

imgstrip works the other way around. It reads only the pixels and builds a brand-new file from them. There is nothing left to leak because nothing from the old file was copied over.

$ imgstrip --check holiday.jpg
FOUND    holiday.jpg (JPEG 640x480): 4 item(s)
           [metadata] EXIF: make=NIKON, model=COOLPIX P6000, date=2008:10:22 16:28:39
           [metadata] GPS location: 43.467448, 11.885127
           [hidden]   Embedded EXIF thumbnail: 6702 bytes
           [metadata] XMP: 4000 bytes

$ imgstrip holiday.jpg
cleaned  holiday.jpg -> holiday.clean.jpg
           removed: EXIF, GPS location, Embedded EXIF thumbnail, XMP

$ imgstrip --check holiday.clean.jpg
clean    holiday.clean.jpg (JPEG 640x480)

Your original file is never touched. The clean copy is saved next to it.

🚀 Quick start

You need Python 3.10 or newer.

pip install imgstrip

Prefer to keep it out of your main Python setup? pipx install imgstrip works too.

Then try it:

imgstrip photo.jpg          # writes photo.clean.jpg
imgstrip-web                # or use the point-and-click web app

Want to be sure the install works? Run imgstrip --self-test. It builds 21 booby-trapped test images, cleans them in every mode, and has independent image readers confirm the results.

Install from source instead
git clone https://github.com/lloydsato/imgstrip.git
cd imgstrip
pip install .

🔍 How it works

flowchart LR
    A[Your photo] --> B[Decode to raw pixels]
    B --> C[Write a brand-new file]
    C --> D{Check 1: is every part of the new file accounted for?}
    D -->|yes| E{Check 2: do the pixels still match?}
    D -->|no| X[Stop. Nothing is saved]
    E -->|yes| F[Clean copy saved]
    E -->|no| X

If either check fails, nothing is written. Failing safe is the whole point.

(If you're reading this on PyPI and the diagram shows as plain text, the GitHub page renders it.)

🛠 Everyday use

I want to... Run
See what a photo gives away, without changing it imgstrip --check photo.jpg
Clean one photo imgstrip photo.jpg
Clean a whole folder, including subfolders imgstrip -r my-photos/ -o clean-photos/
Replace the originals with clean versions imgstrip -i photo.jpg
Give outputs random names (file names can leak dates) imgstrip --random-name photo.jpg
Clean a JPEG with no quality loss at all imgstrip --jpeg-lossless photo.jpg
Convert while cleaning imgstrip --format png photo.jpg
Preview what would happen, write nothing imgstrip -n photo.jpg

Run imgstrip --help to see every option.

Going further

Switch What it does
--deep Also scans the pixels for signs of hidden data (LSB steganography).
--scrub-lsb Randomizes the least-significant bit of every pixel value, which destroys hidden LSB messages. The change is invisible (at most 1/255).
--scrub-prnu Disrupts your camera's sensor fingerprint, a pattern in the pixels themselves that can link a photo to a specific camera. Moves parts of the picture by a few pixels.
--icc sanitize Keeps the exact colors using a rebuilt, anonymous color profile.
--c2pa Signs each clean image with a Content Credential, so you can show it was sanitized without being altered. Needs the optional extra: pip install 'imgstrip[c2pa]'.

🖥 Web app

imgstrip-web

Drop photos onto the window and each one shows what it gives away. Click Clean, then download the results one by one, as a ZIP, or save them straight to a folder.

The imgstrip web app after four photos were dropped on it. One row is open and lists what that photo reveals: GPS location, camera model, time taken, body serial number, lens and editing software. A button at the bottom reads Clean 4 images.

Open Options for the same switches as the command line: Deep scan, Keep JPEG data bit-exact, Scrub least-significant bits, Disrupt camera fingerprint, Sign with Content Credentials, plus the output format, quality and colour profile.

  • Runs only on your computer (127.0.0.1) and works offline.
  • Your originals are never written to disk, and nothing is uploaded anywhere.
  • On a shared computer, start it with imgstrip-web --no-browser and open the printed link yourself.

📁 What it handles

Formats
Everyday photos JPEG, PNG, WebP, GIF (animated too), HEIC/HEIF (iPhone), AVIF
Also supported TIFF, BMP, and ICO, PSD, TGA, QOI, JPEG 2000 and other less common formats (these come out as PNG)
Not supported Camera RAW files (DNG, CR2, NEF, ARW...). Export to JPEG, PNG or TIFF first. Vector formats (SVG, PDF, EPS) are also unsupported.

Removed: EXIF, GPS, XMP, IPTC, comments, camera serial numbers, embedded thumbnails, depth maps, color profiles that name your device, data tacked on after the image, and colors hidden under transparent pixels.

⚠️ Good to know

No tool can do everything, and it's better to know the limits up front.

  • What's in the picture stays. Faces, street signs, reflections and landmarks can reveal more than any tag.
  • Your camera's sensor fingerprint stays unless you use --scrub-prnu. Even then, nobody can prove it's gone.
  • File names can leak dates (IMG_20240517_133700.jpg). Use --random-name.
  • A clean scan isn't proof. "Not detected" means the tests found nothing, not that nothing is hidden.
  • Invisible watermarks built to survive re-saving (such as SynthID) live in the picture itself and may survive.
  • JPEGs are re-encoded (quality 95) by default. Use --jpeg-lossless to avoid any quality loss. That mode keeps the image data exactly as it was, so it doesn't clear steganography hidden in the image data itself.
  • -i is not a secure erase. Old copies can linger in backups, cloud sync history and SSD wear-leveling.
  • Very grainy JPEGs may be refused by the default mode because the re-encoded copy would drift too far from the original, and imgstrip would rather refuse than save something it couldn't verify. Use --jpeg-lossless for those.

📚 Learn more

The full technical reference covers every option, the exact list of what gets removed, how the sensor-fingerprint scrub was measured, optional Content Credentials (C2PA) signing for journalists, and how the project is tested:

➡️ Technical reference

🧪 Development

pip install -e '.[test]'
pytest

📄 License

imgstrip is free software, released under the GNU Affero General Public License v3.0 or later. If you modify it and offer it to others over a network, the AGPL requires you to share your changes under the same license.

Questions, bug reports and odd files that break it are welcome in the issue tracker.

Metadata

Release files for imgstrip 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for imgstrip 1.0.1
File Size Uploaded
imgstrip-1.0.1.tar.gz 344.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for imgstrip 1.0.1
File Interpreter ABI Platform
imgstrip-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 612.3 kB

Release files / imgstrip-1.0.1.tar.gz

Download URL imgstrip-1.0.1.tar.gz
Size 344.7 kB
Tags Source
SHA-256 checksum
How to use checksums
2463ffe42a2dacc38f3f31b674d7fac6445ebd9bb834935a59d90f4a5cd6decb
BLAKE2b-256 checksum
How to use checksums
d5f9566023804381441047f55715cbfed08c282e887d0b69197d93cf20b5dd73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / imgstrip-1.0.1-py3-none-any.whl

Download URL imgstrip-1.0.1-py3-none-any.whl
Size 267.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
490d0b36ac8f865688badbdfb380992afd7ff9ab2809348b8f67c652713128f5
BLAKE2b-256 checksum
How to use checksums
0257068b746b6266972b7d88e7fd7270c7bb9952f7b8989a17c7cf6ecd6aa5a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.2

2 release files

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page