|
2 | 2 |
|
3 | 3 | [](https://github.com/infinilabs/infinishield/actions/workflows/build.yml) |
4 | 4 |
|
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. |
6 | 6 |
|
7 | | -## How It Works |
| 7 | +## What It Does |
8 | 8 |
|
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: |
10 | 10 |
|
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) |
15 | 14 |
|
16 | | -### Dual-Mode Embedding |
| 15 | +## Supported Formats |
17 | 16 |
|
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 | |
44 | 22 |
|
45 | 23 | ## Building |
46 | 24 |
|
47 | | -Requires Rust 1.70+ (no system libraries needed — pure Rust implementation). |
| 25 | +Requires [Rust](https://rustup.rs/) 1.70+. |
48 | 26 |
|
49 | 27 | ```bash |
50 | | -cargo build --release |
| 28 | +make release # Build optimized binary |
51 | 29 | ``` |
52 | 30 |
|
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. |
54 | 32 |
|
55 | 33 | ## Usage |
56 | 34 |
|
57 | 35 | ### Embed a Watermark |
58 | 36 |
|
59 | 37 | ```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 |
74 | 40 |
|
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 |
83 | 43 |
|
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" |
85 | 46 |
|
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 |
92 | 49 | ``` |
93 | 50 |
|
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 | |
101 | 59 |
|
102 | | -### Verify / Extract a Watermark |
| 60 | +### Verify / Extract |
103 | 61 |
|
104 | 62 | ```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 |
107 | 65 |
|
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" |
110 | 68 | ``` |
111 | 69 |
|
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: |
118 | 71 | ``` |
119 | | -[分析中] 正在执行频域扫描... |
120 | 72 | [验证结果] 匹配成功!(置信度: 99.3%) |
121 | 73 | [提取内容] "Infini" |
122 | 74 | ``` |
123 | 75 |
|
124 | | -Output on failure (no watermark or wrong password): |
125 | | -``` |
126 | | -[验证结果] 失败。未检测到有效水印,或密码错误。 |
127 | | -``` |
128 | | - |
129 | | -## Running Tests |
| 76 | +### Help |
130 | 77 |
|
131 | 78 | ```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 |
137 | 81 | ``` |
138 | 82 |
|
139 | | -## Current Limitations |
| 83 | +## Limitations |
140 | 84 |
|
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. |
145 | 89 |
|
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. |
147 | 94 |
|
| 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 |
148 | 104 | ``` |
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