Image watermark library for MoonBit: visible and invisible traceable watermarks with embed/extract/verify APIs and a CLI.
Dependencies
| 类型 | API | 说明 |
|---|---|---|
| 文本水印 | RgbaImage::embed_text + TextConfig | 内置 5×7 点阵字体(A-Z / 0-9 / 常用符号),支持缩放、透明度、定位 |
| 随机点阵水印 | RgbaImage::embed_dots + DotConfig | 确定性 PRNG(xorshift64)按网格落点;同一 seed 完全可复现 → 可提取、可溯源 |
| Logo 水印 | RgbaImage::embed_logo | 任意 RGBA 图叠加,支持透明 PNG |
| 平铺水印 | RgbaImage::embed_tiled + TiledConfig | 全幅网格平铺,防截屏/盗摄 |
| API | 说明 |
|---|---|
| RgbaImage::embed_invisible + extract_invisible | LSB 逐位嵌入(RGB 通道各 1 bit/像素);key 派生 keystream 整体混淆,错误 key 在 magic 校验处被拒绝;容量 = 宽×高×3/8 字节 |
| verify_invisible | magic 校验通过即判定存在 |
| API | 说明 |
|---|---|
| extract_dots | 用同一 DotConfig 复现点位置,统计深色命中率(0.0~1.0) |
| verify_dots | 命中率 ≥ 阈值(默认 0.9)判定水印存在 |
| verify_invisible | LSB 水印 magic 校验 |
| trace_dots | 对候选 DotConfig 数组溯源:返回命中率最高者索引(≥ 阈值);分发场景为每个接收者分配独立 seed,泄漏即锁定接收者 |
| 场景 | 推荐能力 | 机制 |
|---|---|---|
| 电商主图 / 详情页防同行盗图 | 可见(Logo / 文本) | 店铺名 + 商品信息角落或平铺,搬运必留痕 |
| 素材 / 图库预览防盗 | 可见 + 不可见 | 预览图盖半透明水印;样图嵌客户 ID |
| 内部设计稿 / 文档截图泄密溯源 | trace_dots | 每个员工 / 供应商独立 seed,外泄即定位 |
| 图片版权确权(摄影 / 插画 / 设计) | LSB 不可见 | 创作时嵌入作者 ID + 时间,维权时提取作证 |
| API 图片 / 头像接口追踪 | LSB 不可见 | 按调用方嵌入 ID,识别爬虫、盗链、二次分发 |
| 广告 / 营销素材渠道追踪 | trace_dots | 不同投放渠道不同 seed,泄漏渠道一测便知 |
| 社交 / UGC 平台防二创搬运 | 平铺 | 全幅网格水印,截图翻拍仍可见 |
| 直播 / 视频切片防搬运 | 可见 + 点阵(动态) | 平台名 + 时间戳 + 观众 ID,配合 OBS 浏览器源落地 |
| 报告 / 报表 / 合同截图防外泄 | 平铺 + 文本 | 公司名 + 部门,截屏即留痕 |
| 取证存证 | 文本 + LSB | 时间 + 拍摄者身份,形成证据链 |
moon add yuzhiblue/moon-watermark// 1. 生成测试图(或 decode_png 解码真实图片)
let img = @lib.RgbaImage::new(320, 240, 0xFFFF_FFFF)
// 2. 文本水印:平台名 + 时间戳(直播贴片场景)
let tcfg = @lib.TextConfig::new("LIVE 2026-10-03", 8, 8, 2, 0.6, 0xFF00_00FF)
let _ = img.embed_text(tcfg)
// 3. 点阵溯源水印:seed = 观众/接收者 ID
let dcfg = @lib.DotConfig::default()
let _ = img.embed_dots(dcfg)
// 4. 编码 → 解码 → 提取验证
let png = img.encode_png()
let back = @lib.decode_png(png.unwrap()).unwrap()
let rate = @lib.extract_dots(back, dcfg) // ≥0.9 判定水印存在


| 攻击 | 点阵水印命中率 | LSB 不可见水印 | 说明 |
|---|---|---|---|
| PNG 无损往返 | 1.0 ✅ | 可提取 ✅ | LSB 的可靠载体 |
| JPEG q60 重压 | 1.0 ✅ | 提取失败 ❌ | 深色点高对比经 JPEG 保留;LSB 被量化破坏 → JPEG 场景需 DCT 域水印(roadmap) |
| 裁剪半幅(保留行格) | 1.0 ✅ | — | 点阵网格按行列索引相对化,裁剪不破坏行格时完全命中 |
| 缩放至 1/2(Nearest) | 0.0 ❌ | — | 像素网格重采样后点位置错位;缩放鲁棒需频域方案(roadmap) |
| 包 | 作者 | 定位 | 与 moon-watermark 差异 |
|---|---|---|---|
| pixelforge | 0717lee | 通用图像处理(合成/滤镜/编解码) | 无安全水印的嵌入-提取-溯源概念 |
| moonwatermarkkit | Oyc996 | 流处理"事件时间水印" | 非图像水印 |
| watermark-toolkit | V1GreenSummer | LLM 文本水印 | 非图像水印 |
pub struct DotConfig {
density : Double
dot_size : Int
seed : Int64
opacity : Double
grid_offset_x : Int
grid_offset_y : Int
}pub struct RgbaImage {
width : Int
height : Int
data : FixedArray[Byte]
}fn RgbaImage::resize(self : RgbaImage, width : Int, height : Int, sampler : SampleMode) -> RgbaImagepub struct TextConfig {
text : String
x : Int
y : Int
font_size : Int
opacity : Double
angle : Double
color : Int
}fn TextConfig::new(text : String, x : Int, y : Int, font_size : Int, opacity : Double, color : Int) -> TextConfigpub struct TiledConfig {
text : String
font_size : Int
spacing_x : Int
spacing_y : Int
opacity : Double
color : Int
}fn TiledConfig::new(text : String, font_size : Int, spacing_x : Int, spacing_y : Int, opacity : Double, color : Int) -> TiledConfigfn blend_pixel(dst : Int, src : Int, alpha : Int) -> Intfn xorshift64_next(state : UInt64) -> UInt64Install
Download zipImage watermark library for MoonBit: visible and invisible traceable watermarks with embed/extract/verify APIs and a CLI.
Dependencies