Files
remove-ai-watermarks/docs/installation.md
T
Victor KuznetsovandClaude Opus 5 52b2c115e8 Delete every knob the fixed profiles cannot honor
The CLI still advertised --model, --steps, --guidance-scale, --device and a
deprecated --auto. Each pinned a value the two surviving profiles fix -- the
model stack, the per-stage distilled schedule, CFG 1.0, CUDA -- so the only
outcome any of them had was an error raised several frames below the caller,
under a message naming an internal profile. A flag whose sole result is a
refusal is worse than no flag: it advertises a capability that does not exist,
and it lets a wrapper thread a value that will silently do nothing. They are
gone from the parser, from InvisibleEngine, and from WatermarkRemover, so the
failure is now a TypeError or a Click "No such option" at the point the caller
can act on.

The install hint was wrong in the same way. is_available() checked torch and
diffusers, then told the user to install [diffusion] -- which contains neither
DiffSynth nor the Z-Image face stage both profiles run. Following the advice
produced a second, different failure. The module list and the extra name now
live once in watermark_profiles (REMOVAL_MODULES, INVISIBLE_EXTRA) and are read
by both the CLI gate and the remover's precondition, which cannot drift apart
because they are the same tuple.

The adaptive-polish default moved out of the argument parser. It was resolved by
reading Click's parameter source, which put per-profile data in the CLI layer,
left the engine declaring the opposite default (False vs True) so a library
caller and a CLI caller on one profile got different output, and lost the polish
entirely for anything that supplies the flag non-interactively. The flag is now
tri-state (default=None) and resolve_adaptive_polish owns the per-profile
answer. The seed follows the same rule: the CLI stopped pre-resolving it.

Dead code removed with it: six scan_*_video wrappers and the _scan_video helper
none of them had a caller for, PNG_METADATA_KEYS, feather_region_composite and
the remover region path that was only reachable from a no-caller convenience
wrapper, remove_watermark_batch on both layers, try_empty_device_cache, the
_generate/_run_qwen_zimage pass-through pair, self.model_id, and the _internal
PEP 562 shim that no caller ever went through. get_device now answers cuda or
cpu only: mps and xpu travelled one frame to the same CUDA-only refusal while
costing a device probe each, and that refusal now names the resolved device, so
device=None on a CUDA-less host says 'cpu' rather than 'None'. The XPU wheel
index went with them.

Docs: README, cli, installation, python-api, supported-signals,
known-limitations and module-internals all still described the removed profiles,
the CPU/MPS/XPU ladder, a `default`->`sdxl` alias, and the wrong extra.
known-limitations still listed the retired SDXL strength ladder as current.
scripts/smoke_matrix.py and real_examples_e2e.py drove --device mps.

Next release is 0.25.0, not a patch: this removes public parameters and
narrows a published extra on top of the released 0.24.0.

pre-commit: 1) maintain.sh - exit 0 (1091 tests, Pyright 0 errors, no
vulnerabilities); 2) /simplify - 4 agents, 11 findings applied, 2 skipped
(dropping the `device` parameter entirely, which raiw-app pins; folding
diffsynth into the `diffusion` extra, which video-only callers do not need);
3) docs sync - grepped every removed identifier across README, docs/, scripts/,
.claude/; updated 9 docs; 4) CLAUDE.md - added the no-error-only-knobs rule to
.claude/rules/development.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 15:38:40 -07:00

6.7 KiB

Installation

Python 3.10.1 or newer is required.

Default metadata mode

The default package provides:

  • provenance inspection;
  • AI metadata inspection and removal.

It installs Pillow, piexif, and c2pa-python for reading metadata directly from files. It does not install NumPy, OpenCV, pillow-heif, Torch, diffusion models, or invisible-watermark decoders.

Install it as an isolated command with uv:

uv tool install remove-ai-watermarks

Or with pipx:

pipx install remove-ai-watermarks

You can also install the Homebrew package on macOS or Linux:

brew install wiltodelta/tap/remove-ai-watermarks

Visible watermark removal

Visible mark detection, OpenCV inpainting, and manual region erasing need the visible extra:

uv tool install --force "remove-ai-watermarks[visible]"

Add heif only when the pixel path must decode HEIC, HEIF, or AVIF:

uv tool install --force "remove-ai-watermarks[visible,heif]"

Video processing

Video metadata inspection and stripping work with the default package. Stable visible-mark identification and removal, full video cleaning, and visible/all batch modes need the video extra:

uv tool install --force "remove-ai-watermarks[video]"

The extra includes the visible pixel runtime and PyAV for preserving variable frame timestamps. Video SynthID regeneration also needs the diffusion stack:

uv tool install --force "remove-ai-watermarks[video,diffusion]"

Invisible watermark removal

Install the qwen-zimage extra:

uv tool install --force "remove-ai-watermarks[qwen-zimage]"

Both remaining profiles run a Z-Image face stage on the DiffSynth runtime, so both need this extra. It includes the diffusion dependencies; diffusion on its own covers the torch and diffusers imports but not the face stage, so it is not enough to run a removal.

An NVIDIA GPU is required. qwen-zimage and sdxl-zimage are CUDA-only, and construction refuses any other device rather than falling back to a slow or broken one. There is no CPU, MPS or XPU path for invisible-watermark removal. Visible-mark removal, metadata stripping and every identify command still run anywhere.

Video SynthID regeneration is a separate VAE path and does still run on CPU or MPS; it needs the diffusion extra, not this one.

Feature extras

Extras are composable. Install only the capabilities and file formats the application actually uses:

Extra Capability Automatically includes Torch or model download
pixels Shared BGR array and image-processing runtime NumPy, headless OpenCV No
heif HEIC, HEIF, and AVIF pixel decoding pillow-heif No
visible Visible mark detection, OpenCV inpainting, and manual erasing pixels No
video Visible video identification/removal and timestamp preservation visible, PyAV No
detect Open DWT-DCT detection for Stable Diffusion, SDXL, and FLUX pixels, PyWavelets No
trustmark Adobe TrustMark detection trustmark Yes
diffusion Torch and Diffusers runtime; video SynthID regeneration pixels, Torch, Diffusers Yes
migan MI-GAN ONNX fill backend visible, ONNX Runtime Model download, no Torch
lama big-LaMa ONNX fill backend visible, ONNX Runtime Model download, no Torch
qwen-zimage Invisible image-watermark removal, both CUDA-only profiles diffusion, DiffSynth Yes
all Every production feature All rows above Yes
dev Tests, linting, typing, and upstream parity checks visible, detect, upstream invisible-watermark Yes, for parity tests

Dependency composition:

flowchart LR
    visible --> pixels
    video --> visible
    detect --> pixels
    diffusion --> pixels
    migan --> visible
    lama --> visible
    qwen["qwen-zimage"] --> diffusion
    heif
    trustmark

heif and trustmark are independent branches. Combine them explicitly with another feature when required. The all bundle contains every production branch but never includes dev.

Examples:

# Metadata plus torch-free DWT-DCT detection
uv tool install --force "remove-ai-watermarks[detect]"

# Visible removal with HEIC/AVIF support and MI-GAN
uv tool install --force "remove-ai-watermarks[migan,heif]"

# Visible video removal with preserved timestamps
uv tool install --force "remove-ai-watermarks[video]"

# DWT-DCT and TrustMark detection without diffusion removal
uv tool install --force "remove-ai-watermarks[detect,trustmark]"

# Every production capability
uv tool install --force "remove-ai-watermarks[all]"

# An arbitrary minimal combination
uv tool install --force "remove-ai-watermarks[migan,detect]"

heif stays independent so applications that only process PNG, JPEG, or WebP do not install libheif. detect uses the in-tree torch-free decoder and does not install the upstream invisible-watermark package. Optional models download their weights on first use.

The old gpu and remove aliases are intentionally not provided. Use diffusion and visible respectively.

Install from the repository

git clone https://github.com/wiltodelta/remove-ai-watermarks.git
cd remove-ai-watermarks
uv sync --frozen

Add the feature groups required for your work:

uv sync --frozen --extra dev
uv sync --frozen --extra dev --extra diffusion

Run commands from the repository root:

uv run remove-ai-watermarks --help

Development setup

Install development dependencies:

uv sync --frozen --extra dev

Run the complete project gate:

bash maintain.sh

The script runs dependency checks, linting, formatting checks, type checking, and the test suite.

Hugging Face authentication

Pass a Hugging Face token directly when the selected model or account requires one:

remove-ai-watermarks invisible image.png --hf-token "$HF_TOKEN"

The CLI also loads HF_TOKEN from the environment and from a local .env file. The same name is documented in .env.example.

Troubleshooting

The first model run is slow

Diffusion and learned fill backends may download model weights on first use. Later runs reuse their caches.

The command skips invisible removal

The normal behavior is to skip diffusion when no supported local signal is found. A missing signal does not prove that the image is clean. If you know the image came from a relevant generator, use --force.

If the CLI reports that the removal dependencies are unavailable, install the qwen-zimage extra. diffusion alone covers Torch and Diffusers but not the DiffSynth face stage that both profiles run. Video SynthID removal is a separate path and needs video and diffusion.