TextMark 是一个事后文字水印方案:对任意已有文本加水印,无需模型参与、无需改动一个可见字符。水印分两层,可单独使用也可叠加:
| 层 | 载体 | 特性 |
|---|---|---|
| 隐形层 | Unicode 变体选择符(零宽,肉眼不可见) | Reed-Solomon 纠错(每块纠 16 字节)· 可选 deflate 压缩 · 可选 AES-GCM-256 加密 · CRC32 完整性校验 |
| AI 可读层 | 📜 开头的 emoji 序列(每个 emoji = 1 字节) | 刻意保持简单:无压缩、无加密、无纠错,任何 AI 仅凭公开规范即可手工解码 |
| 能力 | 说明 |
|---|---|
| 🫥 隐形水印 | 变体选择符编码,肉眼完全不可见,复制粘贴后依然存活 |
| 🧮 Reed-Solomon 纠错 | GF(2⁸),每块 223 + 32 字节,可纠正 16 字节随机错误 |
| 🔐 可选加密 | AES-GCM-256,密钥由 PBKDF2-SHA256(10 万次迭代)派生 |
| 🗜️ 可选压缩 | 长消息自动 deflate,帧更短、隐形字符更少 |
| 🧩 分段嵌入 | 每个段落末尾各放一份完整副本(最多 20 份),任一段落被单独复制也能解码 |
| 🤖 AI 可读 emoji 层 | 可选(默认关闭):把文本 + 公开提示词发给任意够强的 AI,它就能读出水印 |
| 🧼 一键清除 | 移除两层水印并逐字还原原文;❤️ 等真实变体选择符不会被误删,加密水印无需密码也能清除 |
| 🖥️ 纯本地运行 | 无服务器、无构建、无依赖、零网络请求,file:// 协议下全功能可用 |
| 🎨 手作暖色界面 | 赤茶配色、衬线大标题配无衬线正文、手绘虚线边框、大字引用、全圆角纸感底纹;字体全部走系统字体栈 |
| 📱 响应式 + 深色模式 | 桌面标签导航、手机悬浮底部标签栏、安全区适配、≥44px 触控目标、可安装为 PWA |
| ♿ 无障碍 | 完整 ARIA tablist、方向键导航、aria-live 提示、尊重 prefers-reduced-motion |
| 🌐 中英双语 | 界面一键切换 |
下载仓库,双击 index.html。完事 —— 包括加密在内的所有功能在 file:// 下都可用。
把 6 个站点文件放到任意静态托管即可(GitHub Pages / Vercel / Netlify / Cloudflare Pages):
index.html app.js codec.js style.css icon.svg manifest.webmanifest
git clone https://github.com/88lin/textmark.gitTip
部署后把规范页 URL 公开分享出去 —— 方案越公开,第三方 AI 解码越可靠。详细步骤见 DEPLOY.md。
- 粘贴原文(也可「打开文件」或把
.txt/.md直接拖进页面); - 填写要藏进文本里的水印消息,例如
© 2026 张三 · 文档编号 A-17; - 可选:设密码(即加密)、选插入方式(文末追加 / 分段嵌入)、勾选 emoji 签名条(默认关闭);
- 点「生成带水印文本」或按
⌘/Ctrl + Enter—— 结果会自动自检一次解码,再复制、下载,或一键跳到检测页验证。
粘贴任意文本,页面自动扫描两层水印并解码;同一条消息的多份副本会合并显示份数,加密水印会提示输入密码。
粘贴文本 → 点「清除水印」,两层水印被移除、其余字符逐字保留。加密水印无需密码即可清除。
把带水印文本 + SPEC.md 里的「AI 解码提示词」一起发给任意够强的 AI,它就能读出 emoji 签名条里的消息 —— 无需运行任何代码。
Important
AI 可读层建议只用于 ≤140 字节的短消息:更长的 emoji 序列会让 AI 手工解码容易出错。长消息请依赖隐形层 + 本站检测。
MAGIC "TM" (2B) | VERSION (1B) | FLAGS (1B)
| [SALT(16B) + IV(12B) — 仅加密时]
| LEN (4B, 大端) | PAYLOAD | CRC32 (4B, IEEE)
整帧经 Reed-Solomon 保护:GF(2⁸),本原多项式 0x11D,每块 223 数据 + 32 校验字节,可纠正 16 字节错误。每个字节编码为一个变体选择符:b < 16 → U+FE00+b,否则 → U+E0100+(b−16)。
EMAGIC "Te" (2B) | LEN (2B, 大端) | 消息 UTF-8 字节 | SUM8 (1B)
每个 emoji = 1 字节,字节值 = emoji 在 256 表中的序号。表规则无需查表即可换算:
| 字节范围 | 码位 |
|---|---|
b < 80 |
U+1F600 + b |
80 ≤ b < 208 |
U+1F300 + (b − 80) |
b ≥ 208 |
U+1F380 + (b − 208) |
完整规范(含检测策略、插入策略、清除语义与 AI 提示词)见 SPEC.md。
codec.js 是零依赖 UMD 模块:浏览器里挂在 window.TextMarkCodec,Node 里直接 require()。
const TM = require('./codec.js'); // 浏览器:const TM = window.TextMarkCodec;
// 加水印
const { text, stats } = await TM.encode(cover, '© 2026 张三', {
password: '', // 非空则 AES-GCM-256 加密(并自动关闭 emoji 层)
mode: 'end', // 'end' 文末追加 | 'paragraphs' 每段末尾各一份
emojiLayer: true // 是否附加 AI 可读 emoji 签名条
});
// stats: { frameBytes, invisibleCharsPerCopy, invisibleCharsTotal, replicas,
// emojiChars, encrypted, compressed, emojiLayer }
// 检测解码
const { found, results, errors, needsPassword } = await TM.decode(text, { password: '' });
// results: [{ layer: 'invisible' | 'emoji', message, copies, encrypted?, compressed? }]
// 清除水印(同步)
const { text: clean, removed } = TM.strip(text);
// removed: { invisible, invisibleChars, emoji, emojiChars }Note
decode() 永不静默出错:损坏的副本进 errors,加密但没给密码时 needsPassword === true。
textmark/
├── index.html # 页面(4 个标签页 + 完整 ARIA)
├── app.js # UI 逻辑、i18n、主题、标签路由
├── codec.js # 编解码核心(UMD,浏览器 + Node 通用)
├── style.css # 设计变量、深色模式、响应式
├── icon.svg # 图标(favicon / apple-touch-icon / PWA)
├── manifest.webmanifest # PWA 清单
├── SPEC.md # 公开规范
├── DEPLOY.md # 部署指南
├── TEST_REPORT.md # 测试报告
├── README.md # 本文件(中文)
├── README.en.md # English README
├── LICENSE # PolyForm Noncommercial 1.0.0
└── tests/
├── codec.test.js # 单元测试(Node,33 用例)
├── e2e_browser.py # 浏览器端到端(Playwright,含移动端)
└── shots/ # 截图
零依赖:不引用任何 npm / CDN 包,加密使用浏览器原生 SubtleCrypto,单元测试只用 Node 内置 node:assert。
node tests/codec.test.js # 单元测试(零依赖)
python tests/e2e_browser.py # 浏览器端到端(需 playwright)33 passed, 0 failed
单元测试覆盖:emoji 表完整性 · CRC32 标准向量 · RS 纠错(1/4/8/16 字节错误 + 20 字节明确报错)· 帧/加密/压缩往返 · VS16 冲突 · 抗 3% 随机损坏 · 分段嵌入(每段都有副本 / 单段幸存 / 20 份上限)· 段内相邻多帧 · emoji 层校验 · 清除后逐字还原 · 10KB 端到端。
端到端另外验证:加水印后自检解码、分段副本数、双层检测、阴性对照、清除后与原文全等、256 格 emoji 表与过滤、深浅色与中英切换,以及 390×844 手机视口下的悬浮底栏、无横向溢出、≥40px 触控目标。
完整报告见 TEST_REPORT.md。
| 场景 | 隐形层 | emoji 层 |
|---|---|---|
| 浏览器 / 编辑器之间复制粘贴 | ✅ 存活 | ✅ 存活 |
| Markdown 渲染后复制 | ✅ 预期存活 | ✅ 存活 |
| 微信 / 备忘录 / Google Docs 复制 | ✅ 预期存活 | ✅ 预期存活 |
| 短信 / 激进的清洗管道 | ✅ 存活 | |
| 轻度编辑(改几个字) | ✅ 分段模式下幸存 | |
| AI 改写 / 翻译 / 重排 | ❌ 破坏 | ❌ 破坏 |
- RS 纠错覆盖随机字节错误;删除或插入隐形字符会让该副本不可解码(响亮报错,绝不错误解码)—— 分段嵌入可缓解;
- emoji 层无加密、无纠错(为方便 AI 手工解码刻意简化),仅有 SUM8 完整性校验;
- 加密与「任何 AI 可读」互斥:设置密码时 emoji 层自动关闭。
Caution
规范公开的必然代价:任何人都能移除水印(本站「清除水印」页就是干这个的)。TextMark 解决的是溯源与泄露追踪,不是防篡改,也不是 DRM。
本项目采用 PolyForm Noncommercial License 1.0.0:仅授权非商业用途。
- ✅ 允许:个人学习研究、实验测试、业余项目,以及慈善机构、学校、公共研究机构、政府部门等非营利组织的使用;
- ✅ 允许:在保留版权与许可声明(
Required Notice)的前提下修改、二次开发与再分发; - ❌ 不允许:任何商业用途 —— 包括集成进商业产品或付费服务、公司内部生产环境使用、以本项目为基础提供收费服务。
Warning
需要商业授权请通过 Issue 联系作者另行取得书面许可。
历史说明:v1 的早期提交曾以 MIT 发布,已按 MIT 取得的那些副本继续受 MIT 约束;自本许可证生效后的版本按 PolyForm Noncommercial 授权。
Copyright © 2026 88lin