Metadata-Version: 2.4
Name: gemini-logo-remover
Version: 0.2.0
Summary: Remove the Gemini watermark from images - runs locally, no server needed.
License: MIT
Project-URL: Homepage, https://app.gemini-logo-remover.workers.dev
Project-URL: Documentation, https://app.gemini-logo-remover.workers.dev/developers
Keywords: gemini,watermark,logo,remover,image,ai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Multimedia :: Graphics
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.22
Requires-Dist: Pillow>=9.0
Provides-Extra: inpaint
Requires-Dist: opencv-python-headless>=4.5; extra == "inpaint"
Provides-Extra: api
Requires-Dist: requests>=2.28; extra == "api"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: requests>=2.28; extra == "dev"
Dynamic: license-file

# gemini-logo-remover

Remove the Gemini watermark from images — **locally, no server, no upload.**

```bash
pip install gemini-logo-remover
```

```python
from gemini_logo_remover import remove_logo

remove_logo("gemini-image.png", "clean.png")
```

## How it works

Gemini stamps a translucent white star in the bottom-right corner:
`out = (1 − α)·original + α·white`. This package reverses that exact blend, so the pixels
come back instead of being guessed:

1. **Locate** the mark at the known, size-derived slot positions.
2. **Fit** the overlay's strength (and a few px of position and colour) so one scaled alpha
   shape cancels it. Text and texture cannot be cancelled this way, so they are never mistaken
   for the mark.
3. **Reverse the blend** — lossless; text under the star comes back.
4. **Clean up** compression dots along the star's edge, but only isolated outliers in smooth
   areas, never real detail.
5. **Check** what is left, and inpaint only a leftover or a mark that no alpha overlay explains.

Everything outside the star's 96×96 box is returned bit-for-bit as it was. It runs on your
machine with `numpy` and `Pillow` — about 0.1 s per image.

The calibrated alpha maps for the current star come from
[gemini-watermark-remover](https://github.com/GargantuaX/gemini-watermark-remover)
(MIT, © 2025 Jad, © 2024 AllenK / Kwyshell).

## Usage

### One image

```python
from gemini_logo_remover import remove_logo

result = remove_logo("in.png", "out.png")        # saves out.png
print(result.method, result.clean, result.warnings)

# no file written, work with the Pillow image instead
result = remove_logo("in.png")
result.image.show()
result.save("later.jpg")                          # .jpg -> JPEG, otherwise PNG
```

`image` can be a path, `bytes`, an open binary file, or a `PIL.Image`.

`Result` fields: `image`, `method` (`alpha` = lossless, `inpaint`, `alpha+inpaint`, `none`),
`detected`, `slot` (`v1` old mark / `v2` current star / `v3`), `confidence`, `clean`,
`warnings`, `steps` (what ran), `output_path`.

### Many images, in parallel

```python
from gemini_logo_remover import remove_logo_many

items = remove_logo_many(["a.png", "b.png", "c.jpg"], "cleaned/", workers=4)
for item in items:
    print(item.source, "ok" if item.ok else f"failed: {item.error}")
```

One bad file never stops the others; failures are returned in the list.

### Command line

```bash
gemini-logo-remover photo.png                     # writes photo_clean.png next to it
gemini-logo-remover *.png -o cleaned/ --workers 4
gemini-logo-remover photo.png --mode alpha        # lossless only
python -m gemini_logo_remover photo.png           # same thing
```

### Options

| Option | Default | Meaning |
| --- | --- | --- |
| `mode` | `auto` | `auto`: reverse the watermark, inpaint only what is left. `alpha`: lossless only, never inpaints (image unchanged + a warning if it cannot). `inpaint`: skip the alpha step. |
| `sparkle` | `False` | Also inpaint the small V3 slot. Unverified; can damage text near the corner. |
| `region` | none | `(x, y, width, height)`: skip detection and inpaint exactly this box. |
| `backend` | `local` | `local` runs on your machine. `api` uses a hosted server instead (see below). |

### Errors

- `InvalidImageError` — the input is not a readable image.
- `ApiError` — only for `backend="api"`.
- `GeminiLogoRemoverError` — base class of both.

## Optional extras

```bash
pip install "gemini-logo-remover[inpaint]"   # OpenCV inpainting for the rare non-alpha marks
pip install "gemini-logo-remover[api]"       # backend="api" (needs requests)
```

Without the `inpaint` extra a built-in numpy fill is used. It is fine for flat backgrounds; install
the extra for textured ones. Most current Gemini images never need inpainting at all.

### Hosted API instead of local

```python
remove_logo("in.png", "out.png", backend="api",
            api_url="https://your-server.example/api/v1/remove", api_key="...")
```

Only the bottom-right corner (≤ 480×480 px) is uploaded and the cleaned corner is pasted back
locally. Defaults can be set with `GEMINI_LOGO_REMOVER_API_URL` and `GEMINI_LOGO_REMOVER_API_KEY`.

## Limits

- It targets **original Gemini exports**. Screenshots, resized or heavily re-compressed copies move the
  mark off its exact position and change its pixels, so the reversal may not apply; you then get
  `method == "none"` and a warning, never a silently damaged image.
- A faint (1–3 levels) trace can remain on some backgrounds, mostly dark panels.
- It does not remove invisible watermarks (such as SynthID).

## Development and publishing

```bash
cd python
pip install -e ".[dev]"
pytest

python -m build
twine check dist/*
twine upload dist/*
```

Bump `version` in `pyproject.toml` and `__version__` for every release — PyPI never accepts the
same version twice. `tools/gen_alpha_data.py` regenerates the embedded alpha maps from the web
project.
