portwatcher/rust-blind-watermark
GitHub: portwatcher/rust-blind-watermark
Rust 盲图像水印库与 CLI 工具,支持基于密钥在 RGB/RGBA 图像中嵌入和盲提取文本或字节 payload,并对常见图像编辑操作保持一定鲁棒性。
Stars: 0 | Forks: 0
# blind-watermark
`blind-watermark` 是一个 Rust 库,用于在原始的 RGB8/RGBA8 图像缓冲区中嵌入和提取盲文本或字节 payload。
盲提取意味着提取过程只需要带水印的图像缓冲区和相同的密钥/配置。它不需要原始图像、原始文本或调用方提供的水印长度。
此 crate 是最初的 v0.1 核心实现。它使用确定性的密钥派生块置换、自描述的认证 payload 帧、仅亮度的 Haar + DCT 系数对嵌入以及重复比特恢复。它并不宣称具备任意的防篡改能力。
## 示例
```
use blind_watermark::{
embed_text, extract_text, ColorMode, ImageBufferRef, PixelFormat, RobustnessProfile,
ThreadConfig, WatermarkConfig, WatermarkKey, WatermarkStrength,
};
let width = 384;
let height = 384;
let stride = width * 3;
let image = vec![128u8; stride * height];
let config = WatermarkConfig {
key: WatermarkKey::from_bytes([7u8; 32]),
strength: WatermarkStrength::High,
robustness: RobustnessProfile::Balanced,
color_mode: ColorMode::LumaOnly,
threads: ThreadConfig::Single,
};
let input = ImageBufferRef {
data: &image,
width: width as u32,
height: height as u32,
stride,
pixel_format: PixelFormat::Rgb8,
};
let watermarked = embed_text(input, "hello watermark", &config)?;
let recovered = extract_text(watermarked.as_ref(), &config)?;
assert_eq!(recovered, "hello watermark");
# Ok::<(), blind_watermark::WatermarkError>(())
```
## API 概览
- `embed_text(image, text, config) -> Result`
- `extract_text(image, config) -> Result`
- `embed_payload(image, payload_bytes, config) -> Result`
- `extract_payload(image, config) -> Result, WatermarkError>`
- `capacity(image, config) -> Result`
- `estimate_robust_capacity(image, config) -> Result`
核心 API 作用于借用的输入缓冲区,并返回具有所有权的输出缓冲区。RGBA 的 alpha 字节将被完整保留。
## CLI
此 crate 还构建了一个小型的 `bwm` 二进制程序,用于面向 JPEG 的冒烟测试:
```
cargo run --bin bwm -- embed \
--key 0707070707070707070707070707070707070707070707070707070707070707 \
--input tests/fixtures/test.jpg \
--output tests/artifacts/test-watermarked.jpg \
--text 'bwm-ok-2026'
cargo run --bin bwm -- extract \
--key 0707070707070707070707070707070707070707070707070707070707070707 \
--input tests/artifacts/test-watermarked.jpg
```
`bwm extract` 会尝试原始图像方向以及 180、90 和 270 度旋转。它不执行任意裁剪的重同步。
## CI 与发布
GitHub Actions 配置了以下功能:
- 推送、拉取请求和手动触发时的 CI:格式检查、Clippy、完整测试以及明确的 JPEG 鲁棒性测试。
- 在 `v*.*.*` 标签上发布:验证并为 Linux x86_64、macOS x86_64、macOS aarch64 和 Windows x86_64 构建 `bwm` 发布二进制文件,将它们附加到 GitHub 发布中,并将 crate 发布到 crates.io。
crates.io 发布优先通过 GitHub Actions OIDC 使用 crates.io Trusted Publishing。对于首次发布,请创建一个新的 crates.io API token,并将其存储为名为 `CARGO_REGISTRY_TOKEN` 的仓库 secret。
## Payload 格式
在嵌入之前,payload 字节被封装为以下格式:
- magic bytes:`BWMK`
- 格式版本:`1`
- 标志:`u16`
- payload 长度:`u32`
- payload 类型:文本 UTF-8 或二进制
- 密钥派生的 BLAKE3 MAC 截断至 128 位
- payload 字节
完整的帧在嵌入前会使用密钥派生的流进行白化处理。提取过程会解码重复的比特位,对帧进行解白化处理,检查头部和 MAC,然后返回 payload。
## 鲁棒性配置
鲁棒性是概率性的,取决于图像大小、payload 大小、强度以及嵌入后应用的变换。
当前已测试的行为涵盖:
- 无攻击的 RGB/RGBA 往返
- UTF-8 文本往返
- 密钥错误失败
- 容量拒绝
- alpha 保留
- 确定性输出
- 轻微亮度和小范围确定性噪声测试
- 通过 `bwm` 二进制程序进行的固定装置 JPEG 嵌入/编辑/提取,包括 JPEG 质量-85 重编码、10% 同画布边界裁剪损坏、可见的对角线和矩形遮挡、更强的亮度/对比度/噪声变化,以及旋转 180 度的已编辑 JPEG
`Robust` 配置使用高重复率,其 payload 容量远低于 `Fast` 或 `Balanced`。当前版本未实现任意几何同步,因此在依赖此 crate 之前,应针对您自己的图像集评估偏移裁剪、缩放、截图 pipeline 以及社交媒体重压缩等情况。
## 实现说明
对于每个选定的 8x8 块,当前实现会:
1. 将 RGB/RGBA 像素转换为亮度,
2. 应用一次局部 Haar 变换,
3. 对低频子带应用 4x4 DCT,
4. 通过强制两个中频 DCT 系数之间的排序边距来嵌入一个比特,
5. 应用逆 DCT 和逆 Haar,
6. 根据生成的亮度差值偏移 RGB 通道,同时保持 alpha 不变。
这是一个紧凑的变换域实现,符合任务书中 v0.1 的目标,但它还不是一个完整的 DWT-DCT-SVD 移植。该 crate 保持了公共 API 和模块边界的就绪状态,以便未来进行 SVD 或 ECC 升级。
## 限制
没有任何水印能够在任意的破坏性编辑中幸存。此 crate 有意使用“鲁棒盲水印”的措辞,而不是“防篡改水印”。如果图像被严重裁剪、旋转、缩小、模糊、压缩、覆盖或颜色截断,提取可能会失败。
容量取决于图像大小。在嵌入大型 payload 之前,请使用 `capacity`。
标签:Rust, 可视化界面, 图像处理, 数字水印, 盲水印, 网络流量审计, 通知系统