自动打码听起来像是做一次 OCR,然后直接盖一个黑框。真正可用的版本不是这样,它更像一条流水线:先识别文本,再判断哪些片段有风险,把这些片段映射回图片坐标,加上更安全的留白,最后让用户在导出前复查结果。
这也是 智能文本打码 这类浏览器端工具比较合理的实现方式。Tesseract.js 很适合这个场景,因为它可以直接在客户端运行,返回结构化的 OCR 区块数据,也避免为了识别邮箱或账号把隐私截图先上传到服务端。
为什么这里适合用 Tesseract.js
- 它能直接在浏览器里运行,适合隐私敏感的编辑流程。
- 它返回的不只是纯文本,还有 block、line、word 级别的几何信息。
- 它支持自动旋转,适合手机拍照文档和方向不正的截图。
但这依然不代表 OCR 等于打码。OCR 只能提供候选结果,真正的产品能力在于你怎么处理这些候选区域,是否保守,是否可复查,是否可编辑。
第 1 步:先准备 OCR 用的源图
编辑器里更稳妥的做法,是先把上传图片绘制到一个离屏 canvas 上。这个 canvas 专门给 OCR 使用,而用户看到的可视化编辑区域则继续负责交互和渲染。
const ocrSource = document.createElement("canvas");
ocrSource.width = image.naturalWidth;
ocrSource.height = image.naturalHeight;
const context = ocrSource.getContext("2d");
context?.drawImage(image, 0, 0);这样做的关键点在于,OCR 应该基于原始像素尺寸工作,而不是基于界面里被 CSS 缩放后的显示尺寸。
第 2 步:懒加载并复用 worker
Tesseract.js 不算轻,没必要每次点击“自动检测”都重新创建 worker。更好的模式是按需加载模块,首次创建 worker,之后在多次扫描之间复用,等编辑器卸载时再释放。
if (!ocrWorkerRef.current) {
const createWorker = await loadOcrWorkerFactory();
ocrWorkerRef.current = await createWorker("eng", 1, { logger });
await ocrWorkerRef.current.setParameters({
tessedit_pageseg_mode: "11",
preserve_interword_spaces: "1",
});
}这里有两个参数很关键:
tessedit_pageseg_mode: "11"更适合截图和混合文档这种稀疏文本布局。preserve_interword_spaces: "1"能让后续的模式匹配更稳定。
第 3 步:拿到几何信息,而不只是文本
如果目标是打码,只有 OCR 文本还不够。你真正需要的是能生成可编辑遮挡框的坐标信息。
const result = await worker.recognize(
asset.ocrSource,
{ rotateAuto: true },
{ blocks: true }
);rotateAuto: true 对手机拍的图很有帮助。blocks: true 则能拿到 paragraph、line、word 以及它们的边界框,这才是后续打码逻辑真正要消费的数据。
第 4 步:按行匹配敏感模式
一个实用做法是按 OCR 的每一行来处理,先重新拼出一行文本,再记录每个单词在这行文本里的字符偏移。这样你既可以对整行做正则匹配,又能把命中的范围反查回具体 OCR 单词。
比较适合这样处理的类别包括:
- phone
- url
- date
- id
- account
- amount
- name
- address
这个项目里的实现就是先构造 lineText,记录每个单词的 offset,然后对不同类别执行正则匹配,再找出所有与命中区间重叠的 OCR 单词。
第 5 步:把命中的单词变成打码区域
确定哪些 OCR 单词属于同一次命中之后,就可以合并它们的边界框,再加上一层 padding。框画得太紧虽然看起来精确,但经常会漏掉文字边缘。对打码来说,略大一点通常比过于精确更安全。
const region = createPaddedRegion(bounds, imageWidth, imageHeight, 0.08, 0.3);这一步其实是自动打码里非常重要的产品决策。padding 太小,容易残留可读内容;padding 太大,又会把上下文遮掉太多,影响结果可用性。
第 6 步:把自动检测当作建议,不要当成最终结果
更合理的交互不是“扫描完直接修改原图”,而是“扫描后先插入可复查的候选遮挡区域,用户确认后再导出”。
这也是为什么编辑器里替换的是自动生成的遮挡层,而不是不经确认直接导出。用户可以删掉误判的区域,也可以手动补上漏检的内容,最后再保存。
对于隐私工具来说,复查不是兜底,而是功能本身的一部分。
OCR 辅助打码最常见的失败点
下面这些情况都很容易出现漏检或误判:
- 低对比度截图
- 表格里很小的密集文本
- worker 只加载英文时遇到混合语言内容
- 一个标识符被 OCR 切成了不自然的多段
- 像 “ID” 或 “Total” 这样的标签被正则命中,但实际并不敏感
所以自动打码更适合和 文档打码工具 以及 截图打码工具 这种手动能力配合使用,而不是做成一个完全不可见的一键导出动作。
生产级工具该把边界放在哪里
Tesseract.js 是 OCR 引擎,不是完整方案。真正决定产品质量的,是它外面的那一层实现边界:
- 是否坚持客户端扫描
- 是否高效复用 worker
- 是否保留稳定的几何坐标
- 是否只匹配真正有价值的敏感类别
- 是否用更保守的 padding
- 是否要求导出前复查
这些决策做对了,OCR 辅助打码才会从“演示效果”变成真正可用的功能。
