Skip to content

Commit 422f3dc

Browse files
committed
feat: SVG support with limitations
1 parent e4c49a6 commit 422f3dc

18 files changed

Lines changed: 1592 additions & 123 deletions

Cargo.lock

Lines changed: 277 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ description = "Invisible robust watermarking system for multimedia files"
88
clap = { version = "4", features = ["derive"] }
99
image = "0.25"
1010
imageproc = "0.26.1"
11+
num-complex = "0.4.6"
1112
rand = "0.8"
1213
rand_chacha = "0.3"
14+
rustfft = "6.4.1"
1315
sha2 = "0.10"
16+
tiny-skia-path = "0.12.0"
17+
usvg = "0.47.0"
1418

1519
[dev-dependencies]
1620
tempfile = "3"

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ build: debug release ## Build both debug and release
1818
test-unit: ## Run unit tests (debug)
1919
cargo test --lib
2020

21-
test-integration: ## Run integration tests with real images (debug)
21+
test-integration: ## Run integration tests with real images and SVGs (debug)
2222
cargo test --test picture_tests
23+
cargo test --test svg_tests
2324

2425
test: test-unit test-integration ## Run all tests (debug)
2526

README.md

Lines changed: 62 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -2,163 +2,107 @@
22

33
[![Build](https://github.com/infinilabs/infinishield/actions/workflows/build.yml/badge.svg)](https://github.com/infinilabs/infinishield/actions/workflows/build.yml)
44

5-
A command-line tool for embedding invisible, robust watermarks into images with cropping resistance.
5+
A command-line tool for embedding invisible watermarks into images and SVG files.
66

7-
## How It Works
7+
## What It Does
88

9-
infinishield embeds text messages (e.g., copyright notices, user IDs) into images in a way that is:
9+
infinishield hides a short text message (e.g., a copyright notice) inside an image or SVG file. The watermark is:
1010

11-
- **Invisible** — changes are imperceptible to the human eye
12-
- **Blind** — extraction does not require the original image
13-
- **Password-protected** — only someone with the correct password can extract the watermark
14-
- **Cropping-resistant** — watermark survives partial image cropping (feature-point mode)
11+
- **Invisible** — no visible changes to the file
12+
- **Password-protected** — only someone with the password can extract it
13+
- **Cropping-resistant** — survives partial image cropping (for short messages)
1514

16-
### Dual-Mode Embedding
15+
## Supported Formats
1716

18-
infinishield automatically selects the best embedding mode based on image content and message length:
19-
20-
**Feature-Point Mode** (default for short messages ≤ 7 bytes):
21-
- Detects stable keypoints using oriented FAST corners
22-
- Embeds the same watermark at every keypoint via spread spectrum
23-
- Survives cropping: majority vote across surviving keypoints recovers the message
24-
- Max message: 7 bytes
25-
26-
**Global DWT Mode** (fallback for longer messages):
27-
- 1-level Haar wavelet transform on the full image
28-
- Spread spectrum embedding in the HL detail subband
29-
- Higher capacity but no cropping resistance
30-
- Max message depends on image size (e.g., ~40 bytes for 1024×1024)
31-
32-
### Auto Intensity
33-
34-
When `--intensity` is omitted, infinishield selects optimal strength based on image size:
35-
36-
| Image Size | Auto Intensity |
37-
|-----------|:--------------:|
38-
| < 0.5 MP | 7 |
39-
| 0.5–2 MP | 5 |
40-
| 2–8 MP | 4 |
41-
| > 8 MP | 3 |
42-
43-
Smaller images need higher intensity to survive u8 quantization; larger images can use lower intensity for better invisibility.
17+
| Format | Status |
18+
|--------|--------|
19+
| JPEG, PNG, WebP, BMP, TIFF, GIF | Supported |
20+
| SVG | Supported |
21+
| MP4, WebM (video) | Planned |
4422

4523
## Building
4624

47-
Requires Rust 1.70+ (no system libraries needed — pure Rust implementation).
25+
Requires [Rust](https://rustup.rs/) 1.70+.
4826

4927
```bash
50-
cargo build --release
28+
make release # Build optimized binary
5129
```
5230

53-
The binary will be at `target/release/infinishield`.
31+
The binary will be at `target/release/infinishield`. Run `make help` to see all available commands.
5432

5533
## Usage
5634

5735
### Embed a Watermark
5836

5937
```bash
60-
# Minimal — uses default message, password, and auto intensity
61-
infinishield embed -i source.jpg -o output.png
62-
63-
# Full — all parameters explicit
64-
infinishield embed \
65-
-i source.jpg \
66-
-m "Infini" \
67-
-p "d1ng0" \
68-
-o output.png \
69-
--intensity 5
70-
71-
# Dry run — preview without writing output
72-
infinishield embed -i source.jpg -o output.png --dry-run
73-
```
38+
# Simplest — embeds default message "Infini" with default password
39+
infinishield embed -i photo.jpg -o watermarked.png
7440

75-
| Flag | Required | Default | Description |
76-
|------|----------|---------|-------------|
77-
| `-i, --input` | yes || Input image path (PNG, JPEG, WebP, BMP, TIFF, GIF) |
78-
| `-o, --output` | yes || Output image path (PNG recommended for lossless) |
79-
| `-m, --message` | no | `"Infini"` | Message to embed as watermark |
80-
| `-p, --password` | no | `"d1ng0"` | Password for scrambling and verification |
81-
| `--intensity` | no | auto | Embedding strength (1-10). Auto-selected from image size if omitted |
82-
| `--dry-run` | no || Preview embedding info without writing the output file |
41+
# Custom message and password
42+
infinishield embed -i photo.jpg -m "MyMark" -p "secret" -o watermarked.png
8343

84-
**Output format:** Any format supported by the `image` crate (PNG, JPEG, WebP, BMP, TIFF, GIF). PNG is recommended because it is lossless. A warning is printed if the output format is lossy (JPEG, WebP, GIF) as compression may degrade the watermark.
44+
# SVG file
45+
infinishield embed -i logo.svg -o logo_wm.svg -m "Hi"
8546

86-
Example output:
87-
```
88-
[成功] 水印已嵌入。
89-
[信息] 模式: feature-point | 消息: "Infini" (6 字节) | 强度: 7 | 抗压缩率: 中
90-
[信息] 图像: 700x496 | 特征点: 200 | 容量上限: 7 字节
91-
[信息] 输出: output.png
47+
# Preview without writing (dry run)
48+
infinishield embed -i photo.jpg -o out.png --dry-run
9249
```
9350

94-
Dry-run output:
95-
```
96-
[模拟] 水印嵌入预览 (未生成文件):
97-
[信息] 模式: feature-point | 消息: "Infini" (6 字节) | 强度: 3 | 抗压缩率: 低
98-
[信息] 图像: 3840x2160 | 特征点: 200 | 容量上限: 7 字节
99-
[信息] 输出: output.png
100-
```
51+
| Option | Required | Default | Description |
52+
|--------|----------|---------|-------------|
53+
| `-i` | yes || Input file |
54+
| `-o` | yes || Output file (PNG recommended for images) |
55+
| `-m` | no | `"Infini"` | Message to hide (max 7 bytes for cropping resistance) |
56+
| `-p` | no | `"d1ng0"` | Password |
57+
| `--intensity` | no | auto | Embedding strength (1-10, images only) |
58+
| `--dry-run` | no || Show info without writing output |
10159

102-
### Verify / Extract a Watermark
60+
### Verify / Extract
10361

10462
```bash
105-
# Minimal — uses default password
106-
infinishield verify -i suspicious_image.jpg
63+
# Check if a file contains a watermark
64+
infinishield verify -i watermarked.png
10765

108-
# With explicit password
109-
infinishield verify -i suspicious_image.jpg -p "d1ng0"
66+
# With a specific password
67+
infinishield verify -i watermarked.png -p "secret"
11068
```
11169

112-
| Flag | Required | Default | Description |
113-
|------|----------|---------|-------------|
114-
| `-i, --input` | yes || Input image path to verify |
115-
| `-p, --password` | no | `"d1ng0"` | Password used during embedding |
116-
117-
Output on success:
70+
Example output:
11871
```
119-
[分析中] 正在执行频域扫描...
12072
[验证结果] 匹配成功!(置信度: 99.3%)
12173
[提取内容] "Infini"
12274
```
12375

124-
Output on failure (no watermark or wrong password):
125-
```
126-
[验证结果] 失败。未检测到有效水印,或密码错误。
127-
```
128-
129-
## Running Tests
76+
### Help
13077

13178
```bash
132-
make test-unit # Unit tests (debug)
133-
make test-integration # Integration tests with real images (debug)
134-
make test # All tests (debug)
135-
make test-release # All tests (release)
136-
make sanity # Full check: fmt + lint + build + all tests (debug & release)
79+
infinishield # Show full help
80+
infinishield --version # Show version
13781
```
13882

139-
## Current Limitations
83+
## Limitations
14084

141-
- **Short messages only for cropping resistance** — messages up to 7 bytes (e.g., "Infini") survive cropping. Longer messages (e.g., "Copyright: InfiniLabs") still work but lose cropping protection.
142-
- **No rotation or scaling resistance** — the watermark survives cropping and compression, but not if the image is rotated or resized.
143-
- **Raster images only** — JPEG, PNG, WebP, BMP, TIFF, GIF. SVG and video support is planned.
144-
- **Lossy output degrades watermark** — saving as JPEG or WebP compresses the watermark. PNG or BMP output is recommended. A warning is printed for lossy formats.
85+
**Images:**
86+
- Messages up to 7 bytes survive cropping. Longer messages work but lose cropping protection.
87+
- Rotation and resizing are not supported — only cropping and compression.
88+
- Saving as JPEG degrades the watermark. Use PNG for best results.
14589

146-
## Project Structure
90+
**SVG:**
91+
- Only works on SVGs with complex paths. Simple shapes (rectangles, circles) have too few coordinates.
92+
- Message capacity is typically 2-7 bytes depending on SVG complexity.
93+
- SVG editors that reformat coordinates may destroy the watermark.
14794

95+
**General:**
96+
- Video support is planned but not yet available.
97+
98+
## Running Tests
99+
100+
```bash
101+
make test # All tests (debug)
102+
make sanity # Full check: format + lint + build + all tests
103+
make clean # Remove build artifacts and test outputs
148104
```
149-
src/
150-
├── main.rs # CLI entry point with format auto-detection
151-
├── lib.rs # Module declarations
152-
├── common/
153-
│ ├── engine.rs # WatermarkEngine trait, EmbedResult, ExtractResult, EmbedInfo
154-
│ ├── ecc.rs # Repetition-based error correction coding
155-
│ ├── scramble.rs # ChaCha20-seeded Fisher-Yates bit permutation
156-
│ ├── password.rs # SHA256 password hashing
157-
│ └── temp_input_for_inference.rs # Managed inference buffer
158-
├── raster/
159-
│ ├── mod.rs # RasterEngine: feature-point + global DWT dual mode
160-
│ ├── dwt.rs # 1-level 2D Haar wavelet transform
161-
│ └── features.rs # Oriented FAST keypoint detection + patch extraction
162-
├── vector/ # (Phase 2: SVG Fourier descriptor watermarking)
163-
└── video/ # (Phase 3: Video temporal Harris + 3D-SVD)
164-
```
105+
106+
## Documentation
107+
108+
- [Technical Details](docs/tech_details.md) — architecture, algorithms, design decisions

0 commit comments

Comments
 (0)