Metadata-Version: 2.4
Name: remove-ai-watermarks
Version: 0.20.2
Summary: AI watermark remover: strip visible and invisible AI watermarks (Gemini / Nano Banana sparkle, SynthID) and provenance metadata (C2PA, EXIF) from images
Project-URL: Repository, https://github.com/wiltodelta/remove-ai-watermarks
License: Apache-2.0
License-File: LICENSE
Keywords: ai-detection,ai-metadata,ai-watermark,ai-watermark-remover,c2pa,comfyui,content-credentials,exif,gemini,gemini-watermark,metadata-removal,nano-banana,provenance,remove-watermark,stable-diffusion,synthid,watermark-removal,watermark-remover
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Image Processing
Classifier: Topic :: Security
Classifier: Topic :: Utilities
Requires-Python: >=3.10.1
Requires-Dist: c2pa-python>=0.35.0
Requires-Dist: click>=8.0.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: opencv-python-headless>=4.8.0
Requires-Dist: piexif>=1.1.3
Requires-Dist: pillow-heif>=0.13.0
Requires-Dist: pillow>=10.0.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: all
Requires-Dist: accelerate>=0.25.0; extra == 'all'
Requires-Dist: diffusers>=0.38.0; extra == 'all'
Requires-Dist: huggingface-hub>=0.20.0; extra == 'all'
Requires-Dist: invisible-watermark>=0.2.0; extra == 'all'
Requires-Dist: onnxruntime>=1.16.0; extra == 'all'
Requires-Dist: pyright>=1.1.0; extra == 'all'
Requires-Dist: pytest-cov>=4.1.0; extra == 'all'
Requires-Dist: pytest-xdist>=3.5.0; extra == 'all'
Requires-Dist: pytest>=8.0.0; extra == 'all'
Requires-Dist: ruff>=0.4.0; extra == 'all'
Requires-Dist: safetensors; extra == 'all'
Requires-Dist: tokenizers<0.23,>=0.22; extra == 'all'
Requires-Dist: torch>=2.0.0; extra == 'all'
Requires-Dist: transformers<6,>=5; extra == 'all'
Requires-Dist: trustmark>=0.8.0; extra == 'all'
Requires-Dist: uv-outdated>=0.1.0; (python_version >= '3.12') and extra == 'all'
Requires-Dist: uv-secure>=0.12.0; (python_version >= '3.12') and extra == 'all'
Provides-Extra: detect
Requires-Dist: invisible-watermark>=0.2.0; extra == 'detect'
Provides-Extra: dev
Requires-Dist: invisible-watermark>=0.2.0; extra == 'dev'
Requires-Dist: pyright>=1.1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.5.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Requires-Dist: uv-outdated>=0.1.0; (python_version >= '3.12') and extra == 'dev'
Requires-Dist: uv-secure>=0.12.0; (python_version >= '3.12') and extra == 'dev'
Provides-Extra: esrgan
Requires-Dist: spandrel>=0.3.0; extra == 'esrgan'
Provides-Extra: gpu
Requires-Dist: accelerate>=0.25.0; extra == 'gpu'
Requires-Dist: diffusers>=0.38.0; extra == 'gpu'
Requires-Dist: safetensors; extra == 'gpu'
Requires-Dist: tokenizers<0.23,>=0.22; extra == 'gpu'
Requires-Dist: torch>=2.0.0; extra == 'gpu'
Requires-Dist: transformers<6,>=5; extra == 'gpu'
Provides-Extra: lama
Requires-Dist: huggingface-hub>=0.20.0; extra == 'lama'
Requires-Dist: onnxruntime>=1.16.0; extra == 'lama'
Provides-Extra: migan
Requires-Dist: huggingface-hub>=0.20.0; extra == 'migan'
Requires-Dist: onnxruntime>=1.16.0; extra == 'migan'
Provides-Extra: qwen-zimage
Requires-Dist: accelerate>=0.25.0; extra == 'qwen-zimage'
Requires-Dist: diffsynth<3,>=2.0.17; extra == 'qwen-zimage'
Requires-Dist: diffusers>=0.38.0; extra == 'qwen-zimage'
Requires-Dist: safetensors; extra == 'qwen-zimage'
Requires-Dist: tokenizers<0.23,>=0.22; extra == 'qwen-zimage'
Requires-Dist: torch>=2.0.0; extra == 'qwen-zimage'
Requires-Dist: torchvision>=0.20.0; extra == 'qwen-zimage'
Requires-Dist: transformers<6,>=5; extra == 'qwen-zimage'
Provides-Extra: trustmark
Requires-Dist: trustmark>=0.8.0; extra == 'trustmark'
Description-Content-Type: text/markdown

# Remove AI Watermarks

Remove AI provenance marks from images you generated yourself:

- known visible labels such as the Gemini sparkle and vendor text marks;
- invisible pixel watermarks through diffusion regeneration;
- C2PA, EXIF, XMP, IPTC, and related AI metadata.

> Try it online at [raiw.cc](https://raiw.cc) if you do not want to install Python
> or run diffusion models locally.

[![PyPI](https://img.shields.io/pypi/v/remove-ai-watermarks?logo=pypi&logoColor=white)](https://pypi.org/project/remove-ai-watermarks/)
[![Python](https://img.shields.io/pypi/pyversions/remove-ai-watermarks?logo=python&logoColor=white)](https://pypi.org/project/remove-ai-watermarks/)
[![Downloads](https://static.pepy.tech/badge/remove-ai-watermarks/month)](https://pepy.tech/project/remove-ai-watermarks)
[![License](https://img.shields.io/pypi/l/remove-ai-watermarks?color=blue)](LICENSE)
[![Tests](https://github.com/wiltodelta/remove-ai-watermarks/actions/workflows/test.yml/badge.svg)](https://github.com/wiltodelta/remove-ai-watermarks/actions/workflows/test.yml)
[![Sponsor](https://img.shields.io/badge/Sponsor-GitHub-db61a2?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/wiltodelta)

> This project is for lawful use on content you own. It does not target stock
> agency previews or other watermarks that protect third party paid content.
> See [scope, safety, and legal notes](docs/legal-and-safety.md).

## Choose what you want to do

| Goal | Command | GPU |
| --- | --- | --- |
| Find provenance signals and watermarks | `identify` | No |
| Remove known visible AI marks | `visible` | No |
| Erase a region you select | `erase` | No |
| Strip AI metadata | `metadata` | No |
| Regenerate an image to disrupt invisible watermarks | `invisible` | Recommended |
| Run visible, invisible, and metadata removal | `all` | Recommended |
| Process a directory | `batch` | Depends on mode |

## Quick start

Install the core CLI:

```bash
uv tool install remove-ai-watermarks
```

Inspect an image:

```bash
remove-ai-watermarks identify image.png
```

Remove a known visible mark and AI metadata:

```bash
remove-ai-watermarks visible image.png -o clean.png
```

Strip metadata without running visible inpainting or diffusion:

```bash
remove-ai-watermarks metadata image.png --remove -o clean.png
```

For invisible watermark removal, install the diffusion dependencies:

```bash
uv tool install --force "remove-ai-watermarks[gpu]"
remove-ai-watermarks invisible image.png -o clean.png
```

If the local detectors cannot confirm an invisible watermark but you know the
image came from an AI generator, add `--force`:

```bash
remove-ai-watermarks invisible image.png -o clean.png --force
```

See the [installation guide](docs/installation.md) for Homebrew, uv, optional
features, and development setup.

## Examples

### Visible Gemini mark

| Before | After |
| --- | --- |
| ![Image with a visible Gemini watermark](demo_banana_before.png) | ![Image after visible watermark removal](demo_banana_after.png) |

### High quality invisible removal

The `qwen-zimage` profile is the highest fidelity option for face heavy images.
It is CUDA only and uses a much larger model stack than the default ControlNet
profile.

```bash
uv tool install --force "remove-ai-watermarks[qwen-zimage]"
remove-ai-watermarks invisible image.png -o clean.png \
  --pipeline qwen-zimage --force
```

| OpenAI example before | OpenAI example after |
| --- | --- |
| [![OpenAI portrait grid before qwen-zimage](data/synthid/originals/ChatGPT%20Image%20May%2030,%202026,%2010_31_08%20AM.png)](data/synthid/originals/ChatGPT%20Image%20May%2030,%202026,%2010_31_08%20AM.png) | [![OpenAI portrait grid after qwen-zimage](docs/images/qwen-zimage/ChatGPT/ChatGPT%20Image%20May%2030,%202026,%2010_31_08%20AM_full_clean.png)](docs/images/qwen-zimage/ChatGPT/ChatGPT%20Image%20May%2030,%202026,%2010_31_08%20AM_full_clean.png) |

| Gemini example before | Gemini example after |
| --- | --- |
| [![Gemini sign before qwen-zimage](data/synthid/originals/Gemini_Generated_Image_633uuy633uuy633u.png)](data/synthid/originals/Gemini_Generated_Image_633uuy633uuy633u.png) | [![Gemini sign after qwen-zimage](docs/images/qwen-zimage/Gemini/Gemini_Generated_Image_633uuy633uuy633u_full_clean.png)](docs/images/qwen-zimage/Gemini/Gemini_Generated_Image_633uuy633uuy633u_full_clean.png) |

These exact output files were checked with the matching provider verifiers. That
result applies to these files, not to every seed, image, or future watermark
version.

## Common recipes

### Remove every detected visible mark

```bash
remove-ai-watermarks visible image.png -o clean.png
```

The default `--mark auto` checks all registered visible marks and removes every
match. If the mark is visible to you but the detector misses it, select its
region explicitly:

```bash
remove-ai-watermarks erase image.png \
  --region 1640,1930,400,100 \
  -o clean.png
```

`--region` uses `x,y,width,height` and may be repeated.

### Use a learned fill backend

The core install uses OpenCV inpainting when no learned backend is installed.
For more difficult backgrounds:

```bash
uv tool install --force "remove-ai-watermarks[migan]"
remove-ai-watermarks visible image.png -o clean.png --backend migan
```

```bash
uv tool install --force "remove-ai-watermarks[lama]"
remove-ai-watermarks visible image.png -o clean.png --backend lama
```

### Reduce CUDA memory use

```bash
remove-ai-watermarks invisible image.png -o clean.png \
  --cpu-offload --force
```

CPU offload lowers CUDA memory pressure by moving model components between CPU
and GPU. It is slower and has no effect on CPU or MPS.

### Process a directory

```bash
remove-ai-watermarks batch ./images --mode visible
remove-ai-watermarks batch ./images --mode all
```

## What the tool can recognize

Visible mark support includes:

- Google Gemini and Nano Banana sparkle;
- Doubao, Jimeng, Qwen, Kling, Baidu, LibLibAI, and RunningHub labels;
- one calibrated Samsung Galaxy AI label variant.

Metadata and provenance inspection covers C2PA, EXIF, XMP, IPTC, common
generator parameters, China TC260 AIGC labels, and several vendor specific
signals. Optional decoders add support for open DWT-DCT watermarks and Adobe
TrustMark.

The exact support matrix, including important locale and detector limits, lives
in [supported signals](docs/supported-signals.md).

## How it works

Visible removal follows three steps:

1. Detect a registered mark in its expected area.
2. Build a mask around the mark.
3. Fill only the masked region with OpenCV, MI-GAN, or LaMa.

Metadata removal uses format aware stripping. JPEG metadata removal preserves
the encoded image scan instead of recompressing it. Other supported containers
use their corresponding metadata path.

Invisible removal is different. It regenerates the image through a diffusion
pipeline to disrupt pixel and frequency domain watermarks. This changes the
image and cannot guarantee that a proprietary verifier will reject every
output.

See [supported signals](docs/supported-signals.md) and
[known limitations](docs/known-limitations.md) for the full technical boundary.

## Python API

```python
import remove_ai_watermarks as raiw

result, removed = raiw.remove_visible("watermarked.png", "clean.png")
print(removed)
```

The high level API accepts a file path or a BGR NumPy array. For path inputs it
also reads provenance metadata, preserves alpha, and can strip AI metadata from
the written result.

See the [Python API guide](docs/python-api.md) for visible removal, provenance
inspection, metadata stripping, and diffusion usage.

## ComfyUI

The separate
[ComfyUI Remove AI Watermarks](https://github.com/wiltodelta/ComfyUI-remove-ai-watermarks)
package provides nodes for visible removal, detection, region erasing, and
invisible removal.

## Important limitations

- A missing local signal means unknown, not clean. Proprietary pixel
  watermarks may remain after metadata has been stripped.
- Visible removal reconstructs a small region. Results depend on the background
  and selected fill backend.
- Invisible removal changes the whole image and may alter faces, text, or fine
  detail.
- `qwen-zimage` requires CUDA. The other diffusion profiles also support the
  devices listed by `remove-ai-watermarks invisible --help`.
- Provider watermark systems can change. Validate important outputs with the
  provider's own verifier when one is available.

## Documentation

Start with the [documentation index](docs/index.md).

- [Installation](docs/installation.md)
- [CLI guide](docs/cli.md)
- [Python API](docs/python-api.md)
- [Supported signals](docs/supported-signals.md)
- [Known limitations](docs/known-limitations.md)
- [Scope, safety, and legal notes](docs/legal-and-safety.md)
- [Module internals](docs/module-internals.md)
- [Release and distribution](docs/release-and-distribution.md)

Research notes and historical experiments are listed separately in the
[documentation index](docs/index.md). They explain past decisions but do not
define the current public API.

## Contributing

Install the development environment and run the project gate:

```bash
uv sync --frozen --extra dev
bash maintain.sh
```

See [module internals](docs/module-internals.md) before changing a subsystem
with documented invariants.

## License

[Apache 2.0](LICENSE). Copyright 2025-2026 wiltodelta.
