# clawID

**Invisible & visible watermarking SDK for AI-generated images and video.**

[![PyPI](https://img.shields.io/pypi/v/clawid)](https://pypi.org/project/clawid/)
[![Python](https://img.shields.io/pypi/pyversions/clawid)](https://pypi.org/project/clawid/)
[![CI](https://github.com/Hawky-ai/clawID/actions/workflows/ci.yml/badge.svg)](https://github.com/Hawky-ai/clawID/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

> A research project by **[hawky.ai](https://hawky.ai)** — the AI content provenance platform.

clawID embeds a UUID-based watermark into images and video frames — invisible to the human eye but detectable by the SDK. Inspired by Google SynthID. Built for AI-generated asset provenance tracking.

**Links:** [PyPI](https://pypi.org/project/clawid/) · [GitHub](https://github.com/Hawky-ai/clawID) · [Hugging Face Space](https://huggingface.co/spaces/Hawky-ai/clawID) · [hawky.ai](https://hawky.ai)

---

## Features

- **Invisible watermarking** via DWT-QIM (Discrete Wavelet Transform + Quantization Index Modulation)
- **Resize-robust mode** (`algorithm='fm'`) — survives ±35% resize, JPEG compression, and minor edits
- **Visible watermarking** — overlay text/logo with configurable opacity and position
- **Video support** — watermark every Nth frame; detect from any single watermarked frame
- **REST API** — FastAPI server with `/embed` and `/detect` endpoints
- **Storage backends** — SQLite, PostgreSQL, MongoDB, Redis
- **CLI** — `clawid embed`, `clawid detect`, `clawid embed-video`, `clawid detect-video`

---

## Installation

```bash
# Core (images only)
pip install clawid

# With video support
pip install "clawid[video]"

# With REST API
pip install "clawid[api]"

# Everything
pip install "clawid[all]"
```

---

## Quick Start

### Images

```python
from clawid import embed, detect

# Embed invisible watermark
meta = embed(
    source='photo.jpg',
    output_path='photo_wm.png',
    metadata={'uid': 'creator123', 'platform': 'hawky.ai'},
)
print(meta['clawid'])  # e.g. "3f2a1b4c-..."

# Detect
result = detect('photo_wm.png')
print(result['uid'])       # creator123
print(result['platform'])  # hawky.ai
```

### Resize-robust mode

```python
meta = embed(
    source='photo.jpg',
    output_path='photo_wm.png',
    metadata={'uid': 'creator123'},
    algorithm='fm',   # survives ±35% resize
)
```

### Video

```python
from clawid import embed_video, detect_video

meta = embed_video(
    'input.mp4',
    'output_wm.mp4',
    metadata={'uid': 'creator123', 'platform': 'hawky.ai'},
    frame_stride=5,   # watermark every 5th frame
)

result = detect_video('output_wm.mp4')
print(result['uid'])  # creator123
```

### Visible watermark

```python
meta = embed(
    source='photo.jpg',
    output_path='photo_wm.png',
    metadata={'uid': 'creator123'},
    mode='visible',     # or 'both' for invisible + visible
    opacity=0.6,
    position='bottom-right',
)
```

---

## CLI

```bash
# Embed
clawid embed -i photo.jpg -o photo_wm.png --uid creator123 --platform hawky.ai

# Embed (resize-robust)
clawid embed -i photo.jpg -o photo_wm.png --uid creator123 --algorithm fm

# Detect
clawid detect -i photo_wm.png

# Video
clawid embed-video -i input.mp4 -o output_wm.mp4 --uid creator123
clawid detect-video -i output_wm.mp4

# Save to SQLite store on embed, enrich on detect
clawid embed -i photo.jpg -o wm.png --uid creator123 --store sqlite:///clawid.db
clawid detect -i wm.png --store sqlite:///clawid.db
```

---

## REST API

```bash
pip install "clawid[api]"
clawid serve --store sqlite:///clawid.db --port 8000
```

**Endpoints:**

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/embed` | Upload image, get back watermarked image + metadata |
| `POST` | `/detect` | Upload image, get back detected metadata |
| `GET`  | `/docs`   | Interactive Swagger UI |

```bash
# Embed via API
curl -X POST http://localhost:8000/embed \
  -F "file=@photo.jpg" \
  -F "uid=creator123" \
  -F "platform=hawky.ai" \
  --output photo_wm.png

# Detect via API
curl -X POST http://localhost:8000/detect \
  -F "file=@photo_wm.png"
```

---

## Storage Backends

```python
from clawid.storage import from_uri

# SQLite (local)
with from_uri('sqlite:///clawid.db') as store:
    store.save(meta['clawid'], meta)
    record = store.get(meta['clawid'])

# PostgreSQL
with from_uri('postgresql://user:pass@localhost/mydb') as store:
    store.save(meta['clawid'], meta)

# MongoDB
with from_uri('mongodb://localhost:27017/mydb') as store:
    store.save(meta['clawid'], meta)

# Redis
with from_uri('redis://localhost:6379/0') as store:
    store.save(meta['clawid'], meta)
```

---

## How It Works

### Invisible watermark (DWT-QIM)

The payload (UUID + metadata, CBOR-encoded + CRC-checked) is serialised to bits, then each bit is embedded by quantizing a coefficient in the Haar wavelet LL2 sub-band. Each LL2 coefficient represents a 4×4 pixel block, so a change of `delta/16 ≈ 2+ pixels` per block — above the uint8 quantization step — making the watermark survive JPEG compression and format round-trips.

| Mode | Delta | PSNR | Survives |
|------|-------|------|---------|
| `qim` (default) | 32 | ~51 dB | PNG/JPEG q≥75, minor edits |
| `fm` (resize-robust) | 192 | ~36 dB | ±35% resize, PNG/JPEG q≥75 |

### Video watermarking

Each video is processed frame by frame. Every Nth frame (`frame_stride`, default 5) receives the same DWT-QIM watermark with the same `clawid` UUID. Detection samples up to 10 frames and uses majority vote — detection succeeds as long as at least one watermarked frame survives.

---

## Docker

```bash
docker compose up
# API available at http://localhost:8000
```

---

## Development

```bash
git clone https://github.com/Hawky-ai/clawID
cd clawid
pip install -e ".[dev,api,video]"
pytest
```

---

## Links

| | |
|---|---|
| PyPI | https://pypi.org/project/clawid/ |
| GitHub | https://github.com/Hawky-ai/clawID |
| Hugging Face | https://huggingface.co/spaces/Hawky-ai/clawID |
| hawky.ai | https://hawky.ai |

---

## License

MIT — Copyright © 2024 [hawky.ai](https://hawky.ai)
