GeminiWatermarkTool Skill for Claude-Like Agents
Overview
GeminiWatermarkTool (GWT) removes visible Gemini AI watermarks from images using mathematically accurate reverse alpha blending, with optional AI denoising (FDnCNN + NCNN Vulkan GPU) for residual cleanup.
Source: https://github.com/allenk/GeminiWatermarkTool
Binary Location
Search in this order:
- Environment variable:
GWT_BINARY_PATH - System PATH:
GeminiWatermarkTool(or.exeon Windows) - Claude skill bin directory:
- Windows:
%USERPROFILE%\.claude\skills\gwt\bin\GeminiWatermarkTool.exe - Linux/macOS:
~/.claude/skills/gwt/bin/GeminiWatermarkTool
- Windows:
- Repo-local bin directory (validation mode / fallback):
- Windows:
.\bin\GeminiWatermarkTool.exe - Linux/macOS:
./bin/GeminiWatermarkTool
- Windows:
If not found, run the installer:
python ~/.claude/skills/gwt/install.py
For local validation inside this repo only:
python ~/.claude/skills/gwt/install.py --dir ./bin
Always pass --no-banner when calling GWT — suppresses ASCII art that wastes tokens.
Watermark Profile Selection (v0.3.1+)
GWT ships with two watermark profiles. The default targets Gemini 3.5 and later, with automatic legacy fallback.
| Profile | Targets | When tried |
|---|---|---|
| Current (V2) | Gemini 3.5 and later outputs | first, by default |
| Legacy (V1) | Pre-Gemini-3.5 outputs | automatically retried if V2 skips |
This means remove_watermark(input, output) already handles mixed Gemini-3.5+
and pre-3.5 inputs without supervision — the CLI tries the current profile,
and on skip retries with the legacy profile before reporting the final outcome.
Two opt-out paths exist for the rare case where you need to pin a profile:
no_legacy=Trueparameter — disable the automatic fallback (current only)remove_watermark_legacy/remove_watermark_batch_legacy— pin legacy only
Always start with remove_watermark / remove_watermark_batch. The
auto-fallback handles the common case. The dedicated *_legacy tools are
mostly there for callers that have side knowledge an image is pre-3.5 and
want to skip the V2 attempt entirely.
What to do when detection fails ("skipped")
A skipped=True result from the default tool means both profiles tried
their best and neither matched. The two indistinguishable causes are:
- The image was generated by Gemini, but its watermark has been destroyed by heavy editing/resizing/re-encoding.
- The image was not generated by Gemini at all.
Do NOT silently re-invoke remove_watermark_legacy — the automatic
fallback has already attempted that. Instead, surface the result to the
user and ask whether to escalate:
"I couldn't detect a Gemini watermark on this image (confidence X% on the current profile, Y% on legacy). Either it isn't a Gemini output, or the watermark has been damaged by post-processing. I can try forcing removal at a custom region if you can point me at one — otherwise there's nothing to do."
Escalation paths the agent can offer:
--fallback-region br:64,64,500,500 --snap— multi-scale search in a user-supplied area (good for resized / cropped images)- Lower
--threshold(e.g. 0.15) — relaxes the safety gate; risky on non-Gemini files but legitimate when the user is certain - Custom region in the GUI — most user-friendly for one-off cleanup
Decision Logic
Pipeline selection (automatic, based on flags)
| Flags | Internal behavior |
|---|---|
| No advanced flags | Standard 3-stage NCC detection → process or skip |
--fallback-region only | Standard detection first → if not found, apply to fallback region |
--fallback-region --snap | Skip standard detection entirely → snap search directly |
--force | Skip detection, process unconditionally |
--legacy | Pin V1 profile (pre-Gemini-3.5 outputs); skip the V2 attempt entirely |
--no-legacy | Disable the auto V2 → V1 fallback (current profile only) |
no --legacy and no --no-legacy | V2 first; auto-retry on V1 if V2 skips (v0.3.1+ default) |
Case A — Standard image (not resized after generation)
GeminiWatermarkTool --no-banner -i input.jpg -o clean.jpg
Detection on by default (threshold 25%). Non-watermarked images are skipped safely.
Case B — Image was resized or recompressed
--fallback-region --snap together skips standard detection and goes straight to
multi-scale snap search:
GeminiWatermarkTool --no-banner \
-i input.jpg -o clean.jpg \
--fallback-region br:64,64,500,500 \
--snap --snap-max-size 320 --snap-threshold 0.60 \
--denoise ai --sigma 50 --strength 120
Case C — Unknown image (try standard first, fallback on failure)
Use --fallback-region without --snap. Standard detection runs first;
fallback region only activates if standard detection fails:
GeminiWatermarkTool --no-banner \
-i input.jpg -o clean.jpg \
--fallback-region br:64,64,500,500 \
--denoise ai --sigma 50 --strength 120
Full CLI Reference
Core options
| Flag | Default | Description |
|---|---|---|
-i, --input <path> | — | Input file or directory |
-o, --output <path> | — | Output file or directory |
-f, --force | false | Skip detection, process unconditionally |
-t, --threshold <0.0-1.0> | 0.25 | Detection confidence threshold |
--force-small | — | Force small watermark size |
--force-large | — | Force large watermark size |
--legacy | — | Pin pre-Gemini-3.5 profile (V1); skips V2 attempt. |
--no-legacy | — | Disable the automatic V2 → V1 fallback. |
-v, --verbose | false | Detailed output |
-q, --quiet | false | Suppress output except errors |
--no-banner | — | Hide ASCII banner (always use in this skill) |
Region options
| Flag | Description |
|---|---|
--region <spec> | Explicit watermark region |
--fallback-region <spec> | Search region when standard detection fails |
Region spec formats:
| Format | Meaning |
|---|---|
x,y,w,h | Absolute pixel coordinates |
br:mx,my,w,h | Bottom-right: margin_right, margin_bottom, width, height |
bl:mx,my,w,h | Bottom-left relative |
tr:mx,my,w,h | Top-right relative |
tl:mx,my,w,h | Top-left / absolute |
br:auto | Gemini default position for this image size |
Snap engine
| Flag | Default | Description |
|---|---|---|
--snap | false | Multi-scale snap within region/fallback-region |
--snap-max-size <32-320> | 160 | Maximum watermark size to search |
--snap-threshold <0.0-1.0> | 0.60 | Minimum confidence to accept match |
Denoise / inpaint
| Flag | Default | Description |
|---|---|---|
--denoise <method> | off | ai | ns | telea | soft | off |
--sigma <1-150> | 50 | FDnCNN noise sigma (ai only) |
--strength <0-300> | 120 (ai) / 85 (others) | Blend strength in percent |
--radius <1-25> | 10 | Inpaint radius (ns / telea / soft only) |
Watermark Size Auto-Detection
| Profile | Small logo | Large logo | Threshold |
|---|---|---|---|
| V2 (default — Gemini 3.5+) | 36×36 | 96×96 | long side > 1024 → large |
V1 (--legacy, pre-3.5) | 48×48 | 96×96 | long side > 1024 → large |
Override with --force-small or --force-large. Profile is selected by
--legacy (off = V2, on = V1).
Parameter Tuning Guide
| Situation | Action |
|---|---|
| Faint residual | --denoise ai --sigma 50 --strength 120 |
| Visible edge artifacts | --sigma 75 --strength 180 |
| Strong residual (heavily resized) | --sigma 100 --strength 250 |
| Detection keeps skipping | Lower --threshold 0.15 or add --fallback-region |
| Snap finds nothing | Widen region, increase --snap-max-size 320 |
| Snap confidence too low | Lower --snap-threshold 0.40 |
| Wrong size detected | `-- |