Tesseract.js 图像输入格式全解:recognize/detect 支持哪些图片与数据类型,底层如何加载 Tesseract.js 图像输入格式全解recognize/detect 支持哪些图片与数据类型底层如何加载【免费下载链接】tesseract.jsPure Javascript OCR for more than 100 Languages 项目地址: https://gitcode.com/GitHub_Trending/te/tesseract.js本篇技术指南基于 Tesseract.js 仓库的官方文档 Image Format系统梳理recognize、detect等主函数的image参数支持的全部图片格式bmp、jpg、png、pbm、webp、gif与数据类型base64 字符串、Buffer、File/Blob、DOM 元素、本地路径并结合src/worker与src/worker-script中的实际加载代码讲清每种输入在浏览器和 Node 两种环境下是如何被解析、转换并送入 Tesseract OCR 内核的。读完后你可以针对任意运行环境选择最合适的图像输入方式并在遇到“格式报错”时快速定位问题出在格式层还是数据类型层。一、支持的图片格式总览Tesseract.js 的主入口函数如recognize、detect都接收一个image参数。官方文档明确列出的支持格式为bmp、jpg、png、pbm、webp、gif仅限非动画 GIF这 6 种格式并非只是文档声明而是由测试套件逐一回归验证的。tests/constants.mjs 中定义了测试用的格式列表export const FORMATS [png, jpg, bmp, pbm, webp, gif];tests/recognize.test.mjs 会对每种格式执行完整的识别流程并断言输出文本与预期一致describe(should read bmp, jpg, png and pbm format images, () { FORMATS.forEach((format) ( it(support ${format} format, async () { await worker.reinitialize(eng); const { data: { text } } await worker.recognize(${IMAGE_PATH}/simple.${format}); expect(text).to.be(SIMPLE_TEXT); }) )); });测试图片位于 tests/assets/images/ 目录同名图片simple.*以全部 6 种格式各存一份如 simple.png、simple.bmp、simple.gif 等保证“同一内容、不同编码”下识别结果一致。这从侧面印证了格式声明的可复现性。注意 GIF 的限制文档标注 gif 仅支持非动画GIF。Tesseract.js 只提取单帧图像交给 OCR 内核动画 GIF 的多帧序列并不在支持范围内。二、数据类型支持矩阵环境决定你能传什么格式解决的是“文件编码”问题数据类型解决的是“数据怎么拿进来”的问题。官方文档将二者分开列示并给出了一张按运行环境划分的支持矩阵数据类型浏览器Node说明base64 编码的字符串匹配data:image\/([a-zA-Z]*);base64,([^]*)正则✅✅即 Data URL形如data:image/png;base64,iVBORw0KGgo...Buffer✅✅文档口径Node 侧源码对Buffer有显式分支见下文File或Blob对象✅—浏览器专有img或canvasDOM 元素✅—浏览器专有源码还支持video取 poster与OffscreenCanvas本地图片路径字符串—✅Node 专有如tests/assets/images/cosmic.png两个关键约束格式与数据类型必须同时满足官方文档特别强调“images must be a supported image formatanda supported data type”。例如“一个包含 PNG 的 Buffer”是受支持的而“一个包含原始像素数据的 Buffer”不受支持——Tesseract.js 不接收裸像素数组图像必须携带自身的容器编码或经过 DOM 元素/文件对象间接携带。字符串语义随环境不同而不同同样传入字符串浏览器先判断它是否为 base64 Data URL否则当作 URL 去fetchNode 则先判断是否为 URL其次判断是否为 base64 Data URL最后才当作本地文件路径读取。同一个字符串在两个环境下的解析优先级完全不同跨端移植代码时需留意。三、浏览器侧加载链路src/worker/browser/loadImage.js浏览器环境下image参数的实际处理逻辑集中在 src/worker/browser/loadImage.js。该文件是一个约 70 行的异步函数按输入类型分派处理最终统一返回Uint8Array。逐分支拆解3.1 undefined 与 base64 Data URLif (typeof image undefined) { return undefined; } if (typeof image string) { // Base64 Image if (/data:image\/([a-zA-Z]*);base64,([^]*)/.test(image)) { data atob(image.split(,)[1]) .split() .map((c) c.charCodeAt(0)); } else { const resp await fetch(image); data await resp.arrayBuffer(); } }传入undefined时直接返回字符串undefined供上层判断不会进入 OCR字符串命中 Data URL 正则src/worker/browser/loadImage.js#L38时截取base64,之后的部分用atob解码并逐字符转为 charCode 数值数组字符串未命中正则则被当作 URL通过fetch拉取远程图片再转为ArrayBuffer。这意味着在浏览器中传一个本地文件路径字符串是不会生效的——那属于 Node 专有行为。3.2 DOM 元素IMG、VIDEO、CANVAS} else if (typeof HTMLElement ! undefined image instanceof HTMLElement) { if (image.tagName IMG) { data await loadImage(image.src); } if (image.tagName VIDEO) { data await loadImage(image.poster); } if (image.tagName CANVAS) { await new Promise((resolve) { image.toBlob(async (blob) { data await readFromBlobOrFile(blob); resolve(); }); }); } }img递归调用自身去加载image.src因此 img 的 src 可以是 URL 或 Data URL复用同一套解析逻辑src/worker/browser/loadImage.js#L47-L49video官方文档只提到img与canvas但从源码看video元素同样被支持——取其poster属性指向的静态图进行识别src/worker/browser/loadImage.js#L50-L52canvas通过canvas.toBlob将画布内容编码为 Blob再交给下面的readFromBlobOrFile读取。这实际上是对文档“img or canvas element”声明的落地实现也解释了为何测试里 canvas 用例要先用drawImage把图画上见 tests/recognize.test.mjs#L216-L246。3.3 OffscreenCanvas、File 与 Blob} else if (typeof OffscreenCanvas ! undefined image instanceof OffscreenCanvas) { const blob await image.convertToBlob(); data await readFromBlobOrFile(blob); } else if (image instanceof File || image instanceof Blob) { data await readFromBlobOrFile(image); }File/Blob走统一的readFromBlobOrFilesrc/worker/browser/loadImage.js#L10-L21内部使用FileReader.readAsArrayBuffer并在onerror中抛出File could not be read! Code${code}。这是文件选择框input typefile场景的入口——examples/browser/basic-scheduler.html 中evt.target.files得到的就是File对象直接喂给scheduler.addJob(recognize, files[i])。OffscreenCanvas支持则主要服务于 Web Worker 内部环境无 DOM 的画布通过convertToBlob转码。最终函数以return new Uint8Array(data)收口src/worker/browser/loadImage.js#L68保证进入 worker 脚本的永远是纯字节序列。四、Node 侧加载链路src/worker/node/loadImage.jsNode 环境的实现位于 src/worker/node/loadImage.js分派顺序与浏览器不同这是跨端行为差异的根源if (typeof image string) { if (isURL(image) || image.startsWith(moz-extension://) || image.startsWith(chrome-extension://) || image.startsWith(file://)) { const resp await fetch(image); data await resp.arrayBuffer(); } else if (/data:image\/([a-zA-Z]*);base64,([^]*)/.test(image)) { data Buffer.from(image.split(,)[1], base64); } else { data await readFile(image); } } else if (Buffer.isBuffer(image)) { data image; }要点字符串的三级判定src/worker/node/loadImage.js#L24-L32先按 URL 判断含moz-extension://、chrome-extension://、file://前缀说明其亦考虑了扩展类运行场景再按 base64 Data URL 判断最后兜底为本地文件路径用util.promisify(fs.readFile)读取。这就是文档所说“For Node only: string containing a path to local image”的实现Buffer 直通src/worker/node/loadImage.js#L33-L35Buffer.isBuffer命中后不做任何转换最终统一转Uint8Array返回依赖内置fetch或回退node-fetchsrc/worker/node/loadImage.js#L5-L6与 Node 版本相关。Node 端的典型用法可参考 examples/node/recognize.jsconst [,, imagePath] process.argv; const image path.resolve(__dirname, (imagePath || ../../tests/assets/images/cosmic.png)); (async () { const worker await createWorker(eng, 1, { logger: (m) console.log(m), }); const { data: { text } } await worker.recognize(image); // 直接传本地路径 console.log(text); await worker.terminate(); })();五、字节进入 OCR 内核前的最后一环setImage.jsloadImage只是把输入归一化为Uint8Array真正把这些字节交给 Tesseract 内核tesseract.js-core基于 Leptonica 读图的是 src/worker-script/utils/setImage.js。这一小段代码解释了若干格式上的“为什么”// Check for bmp magic numbers (42 and 4D in hex) const isBmp (image[0] 66 image[1] 77) || (image[1] 66 image[0] 77); const exif parseInt(image.slice(0, 500).join( ).match(/1 18 0 3 0 0 0 1 0 (\d)/)?.[1], 10) || 1; if (isBmp) { const buf Buffer.from(Array.from({ ...image, length: Object.keys(image).length })); const bmpBuf bmp.decode(buf); TessModule.FS.writeFile(/input, bmp.encode(bmpBuf).data); } else { TessModule.FS.writeFile(/input, image); } const res api.SetImageFile(exif, angle); if (res 1) throw Error(Error attempting to read image.);从这段源码可以读出三个实现事实BMP 有专门的重编码路径Leptonica 只支持“部分” BMP 文件源码注释引用了上游问题讨论因此 Tesseract.js 用 bmp-js 先把 BMP 解码再重新编码转换为核心可稳定处理的 BMP 形态后才写入虚拟文件系统src/worker-script/utils/setImage.js#L13-L30。这解释了为何测试必须覆盖simple.bmp——BMP 是六格式中最需要特殊处理的一个EXIF 方向被主动读取setImage从图像头部前 500 字节中匹配 JPEG EXIF 方向标签解析出exif角度后传给api.SetImageFile(exif, angle)。这与 tests/recognize.test.mjs#L53-L65 中simple-90.jpg、simple-180.jpg、simple-270.jpg三组旋转图片测试相互印证——手机照片携带旋转元数据时识别结果仍然正确读图失败的显式报错SetImageFile返回 1 时抛出Error attempting to read image.src/worker-script/utils/setImage.js#L32-L33。如果你在recognize时看到该错误说明字节流不是内核能解析的图像容器——通常正是“原始像素数据”一类不满足“格式 数据类型”双重要求的输入。六、简化接口与完整接口共用同一套输入规则除了createWorker后调用worker.recognize(image)之外Tesseract.js 还保留了一组一次性接口src/Tesseract.js 导出的recognize(image, langs, options)与detect(image, options)内部创建临时 worker、执行识别后自动terminate()const recognize async (image, langs, options) { const worker await createWorker(langs, 1, options); return worker.recognize(image) .finally(async () { await worker.terminate(); }); }; const detect async (image, options) { const worker await createWorker(osd, 0, options); return worker.detect(image) .finally(async () { await worker.terminate(); }); };两者接受的image与worker.recognize完全同源同样受本文第一、二节所列格式与数据类型矩阵约束。tests/recognize.test.mjs#L67-L77 中即有用 base64 Data URL 调用简化接口Tesseract.recognize(image, undefined, OPTIONS)的回归用例验证了文档中“main Tesseract.js functions (ex. recognize, detect) take an image parameter”的说法。七、常见踩坑与排查清单结合文档声明与源码实现把容易出错的场景整理成一张排查表现象根因依据浏览器里传本地路径字符串识别失败浏览器侧非 Data URL 的字符串一律走fetch(image)本地路径不是合法 URLsrc/worker/browser/loadImage.js#L42-L45Node 里传img元素或 Buffer 之外的对象报错DOM 元素分支只存在于浏览器版 loadImageNode 版只识别字符串与 Buffersrc/worker/node/loadImage.js#L24-L35传入裸像素数组/RGBA 数据报Error attempting to read image.原始像素数据不携带容器编码不满足“受支持格式”要求内核SetImageFile返回 1src/worker-script/utils/setImage.js#L32-L33、docs/image-format.md动画 GIF 识别结果不符合预期仅支持非动画 GIF文档明确标注 [non-animated]docs/image-format.md某些 BMP 文件读图失败Leptonica 对 BMP 支持不完整需经 bmp-js 重编码路径处理若仍失败属内核读图失败src/worker-script/utils/setImage.js#L18-L30canvas 用例识别不到内容测试中 canvas 需先drawImage绘入图像再传入空画布自然无文字tests/recognize.test.mjs#L222-L232想从video抽帧识别源码实际取video.poster静态图而非任意帧src/worker/browser/loadImage.js#L50-L52八、格式与数据类型速查将全部结论浓缩为一张速查表环境列与 docs/image-format.md 保持一致源码补充列标注了实现出处输入浏览器Node实现位置data:image/*;base64,...字符串✅✅browser/loadImage.js#L36-L41、node/loadImage.js#L28-L29图片 URL 字符串✅fetch✅含扩展/file:// 前缀browser/loadImage.js#L43-L45、node/loadImage.js#L25-L27本地路径字符串✗✅node/loadImage.js#L30-L32Buffer✅文档口径✅node/loadImage.js#L33-L35File/Blob✅✗browser/loadImage.js#L64-L66img/canvas✅✗browser/loadImage.js#L46-L60video取 poster/OffscreenCanvas✅源码扩展支持✗browser/loadImage.js#L50-L63支持的容器格式统一为bmp、jpg、png、pbm、webp、gif非动画并有 tests/constants.mjs#L17 的FORMATS列表与 tests/recognize.test.mjs 的多组回归用例各格式、base64、Buffer、DOM 元素、旋转 EXIF 图片作为可执行验证。九、小结Tesseract.js 对image参数的契约可以概括为一句话容器格式六选一数据通道看运行环境且两者缺一不可。浏览器端的优势是输入形态多样Data URL、Blob、DOM 画布Node 端的优势是可直接吃本地路径与 Buffer两条链路最终都归一为Uint8Array经 src/worker-script/utils/setImage.js 做 BMP 重编码与 EXIF 方向解析后写入内核虚拟文件系统完成识别。开发时只要对照本文的速查表确认“我的数据是什么类型、我在哪个环境跑”再配合Error attempting to read image.等错误信号基本可以覆盖所有图像输入相关的排障场景。【免费下载链接】tesseract.jsPure Javascript OCR for more than 100 Languages 项目地址: https://gitcode.com/GitHub_Trending/te/tesseract.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考