Happy Face LogoHAPPY IMG
内容
指南最近审核: 2026-04-22

如何用 Tesseract.js 实现 OCR 辅助自动打码

一份面向实现的实用指南,讲清楚如何用 Tesseract.js、可复查的候选区域和浏览器端图片处理来做自动文本打码。

自动打码听起来像是做一次 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 单词。

比较适合这样处理的类别包括:

  • email
  • 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 辅助打码才会从“演示效果”变成真正可用的功能。

Happy Face Mascot