资讯中心

零基础用 Tesseract.js 把图片变成可复制文字:从 1 个 HTML 文件到批量识别实战

📅 2026/8/14 9:20:48
零基础用 Tesseract.js 把图片变成可复制文字:从 1 个 HTML 文件到批量识别实战
零基础用 Tesseract.js 把图片变成可复制文字从 1 个 HTML 文件到批量识别实战【免费下载链接】tesseract.jsPure Javascript OCR for more than 100 Languages 项目地址: https://gitcode.com/GitHub_Trending/te/tesseract.js接手公司旧系统时我遇到过一个尴尬场景财务部门每天要手工录入上百张银行回单上的交易信息眼睛盯屏幕盯到干涩还时不时敲错数字。后来我给他们的浏览器页面加了一个按钮——上传图片文字自动出现在输入框里。这个按钮背后的引擎就是本文要讲的 Tesseract.js。Tesseract.js 是一个纯 JavaScript 编写的 OCR光学字符识别库支持 100 多种语言的文字识别。它把经典的 Tesseract OCR 引擎编译成了 WebAssembly意味着不需要安装任何本地软件、不需要配置后端服务一个 HTML 文件加几行代码就能在浏览器里完成文字提取。读完本文你将收获弄清楚 Worker、语言数据、进度事件这三个核心概念不再被报错信息吓到用 3 行核心代码写出第一个能跑的图片识别页面学会把识别速度从每张图等半天优化到批量并行秒出掌握中英文混合识别、指定区域识别等让结果更准的实用技巧避开新手最容易踩的 5 个坑PDF、手写体、内存、缓存、首次加载动手之前先弄懂三个核心概念很多教程上来就甩代码跑通了却不知道为什么遇到问题就抓瞎。所以我先用一分钟讲清楚 Tesseract.js 的骨架之后每一段代码你都能看懂它在干什么、为什么这么写。第一个概念Worker识别工作单元createWorker创建的对象内部会启动一个独立的 Web Worker 线程专门跑 OCR 引擎。图片发进去识别完把文本返回给主线程。它的特点是可以复用——创建一次反复喂图片全部识别完再销毁。这也是性能优化的关键后面会细说。第二个概念语言数据traineddata识别中文和识别英文用的是不同的模型文件。首次使用时Tesseract.js 会自动从网络下载对应的.traineddata文件并缓存到浏览器 IndexedDB第二次打开页面就不需要重复下载了。这也是为什么你第一次运行会比第二次慢很多——那不是卡死是在下载模型。第三个概念进度事件logger识别是异步的过程包含加载语言包 → 初始化 → 识别 → 输出多个阶段。通过logger回调你可以把每一阶段的进度打出来或渲染成进度条用户就知道程序还在干活不是死机了。第一版一个 HTML 文件跑通图片识别理论讲完直接上第一个能运行的例子。新建一个index.html复制以下内容!DOCTYPE html html head !-- 通过国内 CDN 引入免安装 -- script srchttps://cdn.jsdelivr.net/npm/tesseract.js5/dist/tesseract.min.js/script /head body input typefile iduploader acceptimage/* pre idresult识别结果将显示在这里/pre script (async () { // ① 创建 Workereng 表示识别英文1 是识别引擎模式 const worker await Tesseract.createWorker(eng, 1, { logger: m console.log(进度: ${m.status} ${(m.progress * 100).toFixed(1)}%) }); // ② 绑定文件选择事件 document.getElementById(uploader).addEventListener(change, async (e) { const file e.target.files[0]; if (!file) return; // ③ 识别图片并取出文本 const { data: { text } } await worker.recognize(file); document.getElementById(result).textContent text; }); })(); /script /body /html代码就三件事创建 Worker → 监听文件上传 → recognize 拿结果。用浏览器打开这个文件选一张印刷体英文图片试试。上面这张图是项目自带的标准测试样本包含重复的 The quick brown dog jumped over the lazy fox 等句子。识别它你会得到几乎一字不差的文本。控制台里能看到完整的进度流水loading tesseract core→initializing tesseract→recognizing text→ 完成。提示createWorker的完整签名是createWorker(langs, oem, options)。oem参数填1表示使用 LSTM 神经网络模型默认且效果最好一般不用改。把识别做快做稳Worker 复用与提前预热第一版能跑了但如果你照着网上的老教程写很可能会写出这种代码每次上传图片都createWorker一次。这是我见过最多的性能杀手。createWorker要完成加载引擎核心、下载语言数据、初始化模型三步每一步都耗时。在浏览器缓存命中、网络状况好的情况下这个过程也要花好几秒。如果你上传 10 张图就创建 10 次 Worker光初始化就耗掉大半时间内存还被反复占用又释放。正确的姿势是Worker 全局只创建一次循环喂图片最后 terminate 一次。这也是项目官方示例 examples/browser/basic-efficient.html 采用的模式// Worker 在页面加载时创建一次 const worker await Tesseract.createWorker(eng, 1, { logger: function(m){ console.log(m); } }); // 每次上传复用同一个 Worker const recognize async function(evt){ const files evt.target.files; for (let i0; ifiles.length; i) { const ret await worker.recognize(files[i]); console.log(ret.data.text); } } const elm document.getElementById(uploader); elm.addEventListener(change, recognize);再进一步如果你知道用户大概率会用到 OCR可以在页面加载后、用户还没选图片前就提前创建 Worker 并下载语言包。等用户真正上传图片时识别几乎是即点即出。官方的性能文档docs/performance.md专门强调了这个提前预热策略。⚠️注意如果应用只有少量用户需要 OCR就不要在页面加载时就下载约 15MB 的引擎与语言包等用户点开识别功能时再初始化更划算。让识别结果更准中英文混合与区域限定基础识别没问题了但真实场景往往更刁钻图片里既有中文又有英文或者整张图有很多干扰信息我只想要其中一小块。中英文混合识别语言代码用拼接即可中文简体是chi_simconst worker await Tesseract.createWorker(chi_simeng, 1, { logger: m console.log(m) }); const ret await worker.recognize(mixed-language.png); console.log(识别结果:, ret.data.text);只识别指定区域如果你的场景是票据上的金额栏证件的号码区用rectangle限定矩形区域能显著提升准确率和速度——引擎不必在整张图上找文字// 仅识别图片中 left:0, top:0, 宽300, 高200 的区域 const { data: { text } } await worker.recognize(imageFile, { rectangle: { left: 0, top: 0, width: 300, height: 200 } });限定字符集当你知道识别目标只会出现某些字符时比如银行卡号、验证码只有数字用setParameters告诉引擎准确率立竿见影await worker.setParameters({ tessedit_pageseg_mode: Tesseract.PSM.SINGLE_LINE, // 单行文本模式 tessedit_char_whitelist: 0123456789 // 只允许数字 });比如上面这张银行账单类图片如果业务只要识别金额数字配合SINGLE_LINE和数字白名单识别速度与准确率都会比全图无脑识别好得多。提示PSM页面分割模式是 Tesseract 最常用的调优旋钮。默认是整块文本SINGLE_BLOCK遇到单行、单字符、稀疏文本等特殊情况换对应模式往往比调其他参数更有效。完整参数可参考项目文档 docs/api.md 与 docs/tesseract_lang_list.md。批量图片不再排队把 45 秒压到 15 秒的 Scheduler前面说了 Worker 要复用但一个 Worker 同时只能处理一张图。当你要识别几十张图时单 Worker 串行处理就成了瓶颈。项目文档的对比数据很直观单 Worker 处理 10 张图平均耗时 45 秒而 4 个 Worker 并行处理只需约 15 秒。并行方案就是 Scheduler调度器。它的作用是把一批 Worker 组成一个池子自动把识别任务分发给空闲的 Workerconst scheduler Tesseract.createScheduler(); // 批量创建 4 个 Worker 并加入调度器 for (let i 0; i 4; i) { const worker await Tesseract.createWorker(eng); scheduler.addWorker(worker); } // 并发提交 10 个识别任务 const results await Promise.all( imageFiles.map(file scheduler.addJob(recognize, file)) ); // 汇总结果 const allTexts results.map(r r.data.text); await scheduler.terminate(); // 会同时终止池内所有 Worker项目官方示例 examples/browser/basic-scheduler.html 就是这么组织的你可以直接对照学习。⚠️注意三点Worker 数量不是越多越好。每个 Worker 内存占用很高建议不超过 CPU 核心数否则容易崩溃。池内 Worker 必须同构——同样的语言、同样的参数。因为 Scheduler 不保证任务分给哪个 Worker如果 Worker 配置不同识别结果会随分配对象漂移。Node.js 后端里长期跑的服务建议每处理几百个任务就把 Scheduler 终止重建一次。原因是 WebAssembly 的内存只会扩张不回收且引擎会不断把见过的词写进内部词典跑久了内存和词典都会膨胀详见 docs/workers_vs_schedulers.md。从浏览器到后端Node.js 端 30 秒接入浏览器端搞定后你会发现 Node.js 端几乎零学习成本——API 完全一样只是引入方式不同npm install tesseract.js然后写一个recognize.jsconst { createWorker } require(tesseract.js); (async () { // 与浏览器端完全相同的调用方式 const worker await createWorker(chi_simeng, 1, { logger: m console.log(m), }); const { data: { text } } await worker.recognize(./tests/assets/images/meditations.jpg); console.log(识别结果:, text); await worker.terminate(); // 识别完释放资源 })();项目里的 Node 示例位于 examples/node/包含识别、批量调度、图片预处理、PDF 场景等多个可直接运行的脚本。服务端做 OCR 的典型姿势是前端上传图片 → 后端 Worker 识别 → 返回结构化文本。如果你要把识别结果转成 PDF 或 JSON仓库里 examples/node/download-pdf.js 就是现成参考。新手最容易踩的 5 个坑坑 1识别 PDF 文件失败。Tesseract.js 不支持直接吃 PDF。要么先用 PDF.js 这类库把 PDF 渲染成 PNG 再识别要么换用基于它扩展的 Scribe.js。文档 docs/faq.md 里有完整说明。坑 2拿手写体测试结果惨不忍睹。Tesseract 的模型假设是印刷体手写识别效果天然很差任何参数都救不回来。想识别手写体请另寻专用方案。坑 3升级到 v6/v7 后识别结果少了东西。从 v6 开始除text外的输出格式如 hocr默认关闭了。需要时得显式打开const ret await worker.recognize(image, {}, { hocr: true });坑 4报Cannot find module或找不到 worker。某些打包工具会打乱文件路径导致主线程找不到 worker 脚本。手动指定workerPath即可修复const worker await createWorker(eng, 1, { workerPath: ./node_modules/tesseract.js/src/worker-script/node/index.js });坑 5把语言数据缓存关了。老版本缓存有 bug导致很多教程教人设置cacheMethod: none。这个 bug 在 v4.0.6 已修复现在保持默认缓存即可。关了缓存等于每次访问都重新下载约 2MB 的语言包纯属自残。要点回顾与行动清单最后把全文压成一张速查卡实践时对照着用Worker 全局一个创建一次、复用到底、最后 terminate永远别在循环里 createWorkerScheduler 管并行批量任务用 4 个 Worker 并行数量别超过 CPU 核心数池内配置要一致语言包会缓存首次加载慢是正常的别关缓存别把首次耗时当成死机调优三件套rectangle限定区域、PSM选对版式、char_whitelist锁死字符集明确边界不支持 PDF、不支持手写体别在这两条路上浪费时间服务端要复位Node 里长跑的服务每几百个任务重建一次 Scheduler现在就可以行动新建一个index.html粘贴第一版的代码从项目 tests/assets/images/ 里挑一张测试图把文字识别跑通。然后给它加上进度条、接上批量上传你的第一个 OCR 小工具就诞生了。等熟练之后再把语言切成chi_simeng去识别你的真实业务单据——相信我财务同事会感谢你的。【免费下载链接】tesseract.jsPure Javascript OCR for more than 100 Languages 项目地址: https://gitcode.com/GitHub_Trending/te/tesseract.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考