Skip to main content

MagicDispel

Remove private metadata from photos on your own computer, without touching image quality.

magicdispel photo.jpg
magicdispel "photo one.heic" screenshot.png
magicdispel --anonymous photo.jpg

Type magicdispel and a space, drag one or more photos into the terminal, and press Enter. A cleaned copy named photo_clean.jpg appears next to each original, without the dates and times that screenshots and phone cameras put in names: Screenshot 2026-09-23 at 15.14.15.png becomes Screenshot_clean.png. Originals are never modified and existing files are never overwritten: further copies get _clean_1, _clean_2... --keep-name keeps the name as it is; --anonymous names the copy photo_<random>.jpg instead. It changes the name only, not what the picture shows.

How it works

MagicDispel does not hunt for known metadata to delete. It writes a new file from only the parts a viewer needs to show the image, such as the compressed pixels, color profile, orientation, DPI, transparency, animation timing and HDR gain maps, and leaves everything else behind: location, capture time, camera and lens details, author, comments, editing software, thumbnails, depth maps and portrait mattes, C2PA manifests, and private or unknown data blocks, wherever a format stores them.

  • Image data is copied byte for byte. Only BMP is re-encoded, losslessly, as PNG.
  • ICC color profiles keep their color data; their dates become a fixed placeholder (2000-01-01), their descriptions Clean, and device and creator fields are cleared.
  • Every result is checked before it is saved. The format's rebuilder parses it again on its own; Pillow must decode identical pixels and frames (for HEIC, which Pillow cannot decode, every image item is compared byte for byte instead); and ExifTool, if installed, gives an independent second reading. If any check fails, nothing is saved.
  • Everything happens on your computer: no uploads, telemetry or network access.

This is not an anonymity tool. What the picture shows, a match with a copy published earlier, or the account it is shared from can still identify people and places. Removing depth and style data also limits later portrait, depth-of-field and style edits. See privacy and format details.

Install

One command installs MagicDispel and everything it needs. It uses uv, which brings its own Python when the system has none that fits, and ends by showing the MagicDispel logo.

macOS and Linux:

curl -LsSf https://raw.githubusercontent.com/v1nc3nt-continualab/magicdispel/main/install.sh | sh

Windows (PowerShell):

powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/v1nc3nt-continualab/magicdispel/main/install.ps1 | iex"

If magicdispel is not found afterwards, open a new terminal window.

Already using uv or pipx (Python 3.10 or newer):

uv tool install magicdispel
pipx install magicdispel

To update, run the install command again, or uv tool upgrade magicdispel. To remove MagicDispel, run uv tool uninstall magicdispel.

ExifTool is optional: when version 12.73 or newer is installed, MagicDispel uses it to double-check every result. Install it with brew install exiftool, sudo apt install libimage-exiftool-perl or winget install --exact --id OliverBetz.ExifTool.

Usage

magicdispel --check
magicdispel --version
magicdispel photo.jpg screenshot.png portrait.heic
magicdispel --anonymous photo.jpg
magicdispel --keep-name "Screenshot 2026-09-23 at 15.14.15.png"
magicdispel -- "-filename-starts-with-a-dash.jpg"

Quote paths containing spaces, or drag the files into the terminal. On Windows, drag-and-drop depends on the terminal; a quoted path always works. Folders are not processed recursively. Run magicdispel on its own to see the logo and how to use it. If ExifTool is installed somewhere unusual, set MAGICDISPEL_EXIFTOOL to its full path.

Exit codes: 0 success or help, 1 one or more files not cleaned, 2 invalid arguments, 130 interrupted. A failed file does not stop the rest of a batch.

Formats

Format Kept Removed
JPEG image data, JFIF density, orientation, DPI, color space, ICC profile; HDR gain-map images (MPF), Apple HDR headroom and gain-map XMP other EXIF and XMP, IPTC/Photoshop, comments, C2PA, thumbnails, maker notes, trailing data
PNG, APNG image data, palette, transparency, color chunks (sRGB, gAMA, cHRM, cICP, HDR), DPI, animation, ICC profile, orientation text, time stamps, C2PA, private chunks, anything after the end
HEIC, HEIF image items and tiles, HDR gain maps (Apple and ISO), alpha, orientation, ICC profile, HDR XMP fields EXIF, other XMP, Apple property lists, depth and calibration, portrait and semantic mattes, style maps, thumbnails, unused data
AVIF as HEIF, including animations; sequence times, names and user data are cleared as HEIF
WebP image data, alpha, animation, ICC profile, orientation other EXIF, XMP, unknown chunks
GIF images, palettes, frame timing, transparency, loop count, ICC profile comments, text overlays, XMP, other extensions
TIFF image data, decoding tags, DPI, orientation, page numbers, ICC profile EXIF and GPS directories, XMP, IPTC, Photoshop, descriptions, private tags, sub-images
BMP converted to lossless PNG with the same pixels, DPI and profile everything else
RAW, video, PDF not supported; RAW files built on TIFF (DNG, CR2, NEF...) are recognized and refused

Variants that cannot be rebuilt safely, such as BigTIFF, fragmented image sequences or unknown HEIF item types, are refused rather than passed through. Images up to 268 megapixels are checked (enough for 200-megapixel phone photos); larger ones are refused.

Development

python -m venv .venv
# Activate the environment for your shell.
python -m pip install -e ".[test]" build
python -m unittest discover -s tests -v
python -m build

The tests need only Pillow. When ExifTool is installed, they also add metadata the way other programs write it and let ExifTool double-check each result; CI runs them both ways. No personal photos are included.

Before and after any change to the cleaning code, run the regression harness over a folder of real sample photos kept outside the repository:

python scripts/make_probes.py ~/magicdispel-corpus    # adds synthetic leak probes
python scripts/regression.py ~/magicdispel-corpus     # saves a run under runs/
python scripts/regression.py ~/magicdispel-corpus --baseline ~/magicdispel-corpus/runs/<run>.json

It checks that every output looks identical to its input (Pillow, and macOS ImageIO/ColorSync when available), that no probe marker survives, and, against a baseline, that no sample changes outcome or gains metadata. Pure refactors should also pass --identical, and --without-exiftool checks the path users without ExifTool take.

.github/workflows/test.yml runs the tests on macOS, Windows and Linux with Python 3.10 and 3.13, with and without ExifTool, and the install scripts on all three. release.yml publishes a tagged version to PyPI once those pass.

License and attribution

MagicDispel is MIT licensed. ExifTool, an optional companion, is developed by Phil Harvey and distributed separately under its own license. MagicDispel is not affiliated with ExifTool.

Release files for magicdispel 0.1.0

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

Source distribution (sdist)

Source distribution for magicdispel 0.1.0
File Size Uploaded
magicdispel-0.1.0.tar.gz 96.9 kB Details

Built distribution (wheel)

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

Total release size: 157.9 kB

Release files / magicdispel-0.1.0.tar.gz

Download URL magicdispel-0.1.0.tar.gz
Size 96.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6c56413963597c59562f14a1df0f24dc1dd7a9ed542c5a4e32b0051fc845b717
BLAKE2b-256 checksum
How to use checksums
2fa9a99411c372725acdf0ac8ed8c13df74186a0d1b165762c805f94cbc6fb84
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 Sep 23, 2026.

Transparency log

Release files / magicdispel-0.1.0-py3-none-any.whl

Download URL magicdispel-0.1.0-py3-none-any.whl
Size 61.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ad998e41220e4c8f403509d2bb7a726d8aabe0742d4ae9ab86d43ed685afebfa
BLAKE2b-256 checksum
How to use checksums
43583844e87ed9abaee0c08be375daec901ab9bacd4039f61024e11688d17c95
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 Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

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