PaddleOCR.js 浏览器端 OCR SDK 实战指南:架构、开发与部署全解析
【免费下载链接】PaddleOCR飞桨多语言OCR工具包(实用超轻量OCR系统,支持80+种语言识别,提供数据标注与合成工具,支持服务器、移动端、嵌入式及IoT设备端的训练与部署) Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80+ languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)项目地址: https://gitcode.com/paddlepaddle/PaddleOCR
PaddleOCR.js 是飞桨 PaddleOCR 官方推出的浏览器端 OCR SDK 与演示应用,它将 PaddleOCR 的检测、识别产线以 TypeScript 重写,并基于 ONNX Runtime Web 与 OpenCV.js 实现在浏览器中直接完成文本检测与识别的全流程推理。本文以仓库内 paddleocr-js/README_cn.md 为骨架,结合 架构说明、开发指南、Monorepo 约定 与 SDK 源码,带你掌握项目结构、安装使用、双线程执行模型、自定义模型接入、可视化渲染以及完整的本地开发与发布流程。
项目概览:官方浏览器 OCR SDK 与演示应用
PaddleOCR.js 是 PaddleOCR 仓库下的一个独立 npm workspace,由两个核心部分构成,其目录结构如下表所示:
| 路径 | 作用 |
|---|---|
| packages/core/ | 浏览器 SDK 源码;发布到 npm 时的包名为@paddleocr/paddleocr-js |
| apps/demo/ | 依赖该 SDK 的 Vite 演示应用 |
SDK 与上层应用的分工非常清晰:SDK 负责 OCR 运行时初始化与推理编排(运行时初始化、执行后端选择、模型下载、推理会话创建、OCR 产线执行),而宿主应用仍需要负责部署响应头、静态资源托管与模型 URL 配置、Worker 打包支持,以及应用界面与可视化等职责。apps/demo就是这样一个承载 SDK 的宿主应用示例,可在浏览器中直接体验模型选择、后端切换与 OCR 可视化。
SDK 的运行时依赖集中在 packages/core/package.json 中,主要包括:
onnxruntime-web(^1.22.0):浏览器端 ONNX 推理引擎,负责加载并执行检测/识别模型;@techstark/opencv-js(^4.10.0):浏览器端 OpenCV 实现,负责图像预处理与后处理;clipper-lib:用于检测框多边形裁剪等几何计算;js-yaml:用于解析产线 YAML 配置。
本地开发与演示:五分钟跑起来
安装依赖与启动演示
在paddleocr-js/目录下执行:
npm install npm run dev:demo其中npm run dev:demo会启动依赖 SDK 的 Vite 演示应用(开发服务器)。注意 Node.js 版本要求为>= 20.11(见 paddleocr-js/package.json 的engines字段)。
常用命令一览
根目录提供了一系列常用命令,覆盖构建、测试、类型检查与发布:
npm run build # 先构建 SDK 再构建 demo(显式拓扑顺序) npm run build:sdk # 仅构建 SDK(packages/core) npm run build:demo # 仅构建 demo 应用(apps/demo) npm run lint # ESLint 检查 npm run test # Vitest 单元测试 npm run typecheck # 对所有 workspace 执行类型检查(core + demo) npm run check # format:check → lint → build:sdk → typecheck → test → build:demo npm run clean # 删除所有 dist/ 目录 npm run release # 构建 SDK 并通过 changeset publish 发布按 workspace 作用域执行:
npm run build --workspace packages/core npm run build --workspace apps/demo npm run dev --workspace apps/demo各命令的语义可以在 paddleocr-js/package.json 的scripts字段中逐一确认。npm run check是一条全量质量门禁命令,完整串联了格式化检查、Lint、SDK 构建、类型检查、测试与 demo 构建,适合在提交前或 CI 中执行。
SDK 包布局与高层架构
源码目录结构
SDK 源码位于 packages/core/src/,按职责划分为多个子模块:
src/ ├── runtime/ — 推理运行时初始化(ONNX Runtime Web / OpenCV.js) ├── resources/ — 模型与资源管理(下载、tar 解析、模型资产校验) ├── models/ — 模型接线(检测/识别模型封装) ├── platform/ — 浏览器 / Worker 输入适配 ├── worker/ — Worker 传输层 ├── pipelines/ — 产线实现(OCR 产线、配置解析、运行时参数) ├── viz/ — 可视化(可选子路径) ├── types/ — 外部库类型声明 └── utils/ — 共享工具高层产线入口:PaddleOCR.create()
整个 SDK 的高层产线入口是PaddleOCR.create()(实现见 packages/core/src/pipelines/ocr/index.ts),它负责协调:
- 运行时初始化(OpenCV.js 与 ONNX Runtime Web);
- 执行后端选择(
auto/wasm/webgpu); - 模型下载与资源校验;
- 推理会话创建;
- OCR 产线执行(检测 → 方向分类 → 识别)。
从源码可以看到,PaddleOCR.create(options)默认会自动执行initialize()(除非显式传入initialize: false),并支持传入worker: true或{ worker: { createWorker } }切换执行模式。
双执行模式:主线程与 Worker
PaddleOCR.create()支持两种执行模式,这是 SDK 架构中最重要的设计之一:
- 主线程模式:返回
PaddleOCR,直接在调用线程上执行 OCR; - Worker 模式:返回
WorkerBackedPaddleOCR,将 OCR 生命周期调用(init/predict/dispose)转发到独立 Worker,避免阻塞 UI 线程。
Worker 模式下的运行流程(详见 架构说明):
PaddleOCR.create({ worker: true })解析 OCR 选项并创建WorkerBackedPaddleOCR;WorkerBackedPaddleOCR通过WorkerTransportClient发送init/predict/dispose请求;- OCR 产线层持有默认 Worker 工厂,指向 src/pipelines/ocr/worker-entry.ts;
- Worker 入口将通用 Worker 引导逻辑与 OCR 专用处理逻辑绑定;
OcrPipelineRunner在 Worker 内运行 OpenCV.js、ONNX Runtime Web、模型加载、检测与识别;- 结果和错误被序列化后传回主线程。
输入处理按环境拆分:主线程将浏览器输入(Blob、ImageBitmap、ImageData、HTMLCanvasElement、HTMLImageElement)标准化为可传输的负载;Worker 端再将负载还原为cv.Mat等运行时输入。
Worker 模式有一个关键技术细节:SDK 使用包内的 Worker 路径(worker-entry.ts),并在内部显式关闭 ONNX Runtime Web 的 wasm proxy,避免双层 Worker 叠加,同时让包自身负责并发模型管理。
WASM 路径配置:ortOptions.wasmPaths
ONNX Runtime Web 在运行时需要 WASM 二进制。ortOptions.wasmPaths对两种执行模式统一生效,设置一次即可同时控制主线程和 Worker 两侧的 WASM 加载位置:
PaddleOCR.create({ ortOptions: { wasmPaths: "/assets/" } });设置了wasmPaths时,两种模式都会从指定路径拉取 WASM。未设置时,两种模式的回退行为不同:
- 主线程模式:ORT 通过使用方的打包工具解析 WASM(通常由打包工具把
node_modules/onnxruntime-web/dist/下的.wasm文件拷贝到构建产物并自动改写 URL); - Worker 模式:SDK 回退到与构建时安装的 ORT 版本绑定的 CDN,并在控制台提示建议显式设置
ortOptions.wasmPaths。
因此,在 Worker 模式下建议显式设置ortOptions.wasmPaths,以保证两种模式使用同一套 WASM 版本。演示应用 apps/demo/src/main.ts 即使用了 CDN 路径https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/作为wasmPaths。
快速开始:三行代码跑通 OCR
安装
npm install @paddleocr/paddleocr-js最小示例
import { PaddleOCR } from "@paddleocr/paddleocr-js"; const ocr = await PaddleOCR.create({ lang: "ch", ocrVersion: "PP-OCRv5", ortOptions: { backend: "auto" } }); const [result] = await ocr.predict(fileOrBlob); console.log(result.items);需要注意:predict返回的是OcrResult组成的数组(每张输入图像对应一项)。即使传入单个Blob/File,返回的也是长度为 1 的数组,请使用解构或results[0]取值。
构造方式与模型选择详解
方式一:直接参数
可通过直接参数指定模型,也可配置推理 batch size、ORT 选项等运行参数。
模型选择 —lang+ocrVersion:
await PaddleOCR.create({ lang: "ch", ocrVersion: "PP-OCRv5" });ocrVersion: "PP-OCRv6"会将受支持的lang映射到内置的PP-OCRv6_small检测/识别模型对。若需PP-OCRv6_tiny,请显式指定模型名:
await PaddleOCR.create({ textDetectionModelName: "PP-OCRv6_tiny_det", textRecognitionModelName: "PP-OCRv6_tiny_rec" });模型选择 — 显式模型名:
await PaddleOCR.create({ textDetectionModelName: "PP-OCRv5_mobile_det", textRecognitionModelName: "PP-OCRv5_mobile_rec" });自定义模型— 为检测 / 识别分别指定模型名与资源地址:
await PaddleOCR.create({ textDetectionModelName: "my_det_model", textDetectionModelAsset: { url: "https://example.com/models/my_det_model.tar" }, textRecognitionModelName: "my_rec_model", textRecognitionModelAsset: { url: "https://example.com/models/my_rec_model.tar" } });自定义模型的包格式与校验行为
接入自有模型时必须满足以下约束(SDK 在初始化时会严格校验,不满足即报错,不会静默忽略):
- 资源需为未压缩的标准 tar(
.tar)。SDK 按字节解析 tar,不对 gzip 压缩包解压;若 URL 指向.tar.gz等,通常会解析失败并报错; - tar 内必须包含
inference.onnx与inference.yml(可位于子目录中,按文件名匹配); inference.yml必须能解析出model_name,且须与textDetectionModelName/textRecognitionModelName一致;在initialize加载模型后会进行校验。
初始化阶段的典型失败场景包括:下载失败、tar 中缺少条目、空资源、model_name缺失或不匹配、模型配置不完整、ONNX 会话创建失败等。
batch size 与 ORT 运行参数
await PaddleOCR.create({ lang: "ch", ocrVersion: "PP-OCRv5", textDetectionBatchSize: 2, textRecognitionBatchSize: 8, ortOptions: { backend: "wasm", wasmPaths: "/assets/" } });方式二:产线配置(YAML)
SDK 兼容 PaddleOCR 风格的产线 YAML 配置:
import { PaddleOCR } from "@paddleocr/paddleocr-js"; const pipelineConfig = ` pipeline_name: OCR SubModules: TextDetection: model_name: PP-OCRv5_mobile_det batch_size: 2 TextRecognition: model_name: PP-OCRv5_mobile_rec batch_size: 6 `; const ocr = await PaddleOCR.create({ pipelineConfig });pipelineConfig可以是 YAML 文本,也可以是解析后的对象。如果同时提供直接参数和pipelineConfig,则以直接参数为准。
从源码看(packages/core/src/pipelines/ocr/config.ts),YAML 文本会通过js-yaml解析并规范化为NormalizedPipelineConfig,支持pipeline_name、text_type、SubPipelines、SubModules等结构,并提供两个独立的解析工具函数:parseOcrPipelineConfigText(text)与normalizeOcrPipelineConfig(config)。SDK 内置的默认产线配置(packages/core/src/pipelines/ocr/default-config.ts)展示了完整的字段结构,包括TextDetection的limit_side_len: 64、limit_type: min、max_side_limit: 4000、thresh: 0.3、box_thresh: 0.6、unclip_ratio: 1.5等检测参数,以及TextRecognition的score_thresh等识别参数。
预测 API:参数、输入类型与返回值
参数命名:同时支持 camelCase 与 snake_case
ocr.predict(image | images[], params?)同时接受 camelCase 命名和 PaddleOCR 风格的 snake_case 命名,参数对应关系如下:
| camelCase | snake_case | 作用 |
|---|---|---|
textDetLimitSideLen | text_det_limit_side_len | 检测输入图缩放边长限制 |
textDetLimitType | text_det_limit_type | 限制类型(min/max) |
textDetMaxSideLimit | text_det_max_side_limit | 最大边长限制 |
textDetThresh | text_det_thresh | 检测二值化阈值 |
textDetBoxThresh | text_det_box_thresh | 检测框过滤阈值 |
textDetUnclipRatio | text_det_unclip_ratio | 检测框扩展比例 |
textRecScoreThresh | text_rec_score_thresh | 识别置信度过滤阈值 |
这些字段在 PaddleOCRCreateOptions 中均有定义,且与 PaddleOCR 传统 snake_case 风格保持兼容。演示应用 apps/demo/src/main.ts 中给出的运行默认值可供参考:textDetThresh: 0.3、textDetBoxThresh: 0.6、textDetUnclipRatio: 1.5、textRecScoreThresh: 0.1。
输入类型
支持的image输入包括Blob、ImageBitmap、ImageData、HTMLCanvasElement、HTMLImageElement和cv.Mat。传入上述类型的数组可在一次调用中对多张图像做检测与识别。
⚠️ 注意:在 Worker 模式下,cv.Mat无法跨线程传输,因此不能作为 Worker 输入。
返回值
返回Promise<OcrResult[]>。每个OcrResult包含:
image:该图源的尺寸{ width, height };items:识别行(poly、text、score);metrics:detMs、recMs、totalMs、detectedBoxes、recognizedCount—— 其中detectedBoxes与recognizedCount为每张图统计;detMs、recMs、totalMs表示整次predict()调用的耗时(传入多图时,数组中每一项上的这三个值相同);runtime:请求的后端与各阶段 Provider 等元数据。
演示应用正是利用这些字段渲染识别结果列表(items)与性能指标(metrics),例如detected boxes、recognized lines、各阶段耗时等。
Worker 模式实战
在专用 Worker 中运行 OCR 产线,同时保持相同的高层 API:
import { PaddleOCR } from "@paddleocr/paddleocr-js"; const ocr = await PaddleOCR.create({ lang: "ch", ocrVersion: "PP-OCRv5", worker: true, ortOptions: { backend: "wasm", wasmPaths: "https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/", numThreads: 2, simd: true } });Worker 模式的核心行为:
- 使用包内的 worker 路径(
worker-entry.ts),而不是 ONNX Runtime Web 的env.wasm.proxy; - 启用
worker: true时,包内部会强制关闭 ORT 的 wasm proxy; - 浏览器输入会先在主线程标准化,再传入 Worker 执行推理;
cv.Mat仅支持直接在主线程产线路径中使用;- Worker 模式不支持自定义
fetch实现(worker: true与fetch同时传入会直接抛出错误,见 index.ts)。
可视化:将 OCR 结果渲染为图像
SDK 提供可选的可视化子路径@paddleocr/paddleocr-js/viz,将 OCR 结果渲染为一张左右对比的合成图像:左侧为带有检测框叠加的原始图像,右侧为识别出的文字。
使用OcrVisualizer
import { OcrVisualizer } from "@paddleocr/paddleocr-js/viz"; const viz = new OcrVisualizer({ font: { family: "Noto Sans SC", source: "/fonts/NotoSansSC-Regular.ttf" } }); const blob = await viz.toBlob(imageBitmap, result); // 触发浏览器下载 const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "ocr_result.png"; a.click(); URL.revokeObjectURL(url); viz.dispose();一次性便捷函数
import { renderOcrToBlob } from "@paddleocr/paddleocr-js/viz"; const blob = await renderOcrToBlob(imageBitmap, result, { font: { family: "Noto Sans SC", source: "/fonts/NotoSansSC-Regular.ttf" } });使用注意:
- viz 模块支持加载自定义字体,以正确渲染中日韩等文字(如上面示例中的 Noto Sans SC);
- 可视化需传入单个
OcrResult(单张图时取predict返回数组的首项,例如const [result] = await ocr.predict(image)); deterministicColor(index)同样从 viz 子路径导出,它根据数字索引生成稳定的 RGB 颜色,内部用作检测框和文字标签的默认配色函数;构建自定义可视化并需要与内置渲染器保持一致配色时,可直接调用。
演示应用 apps/demo/src/main.ts 就是利用OcrVisualizer.toBlob()将识别结果渲染成对比图展示在页面上的,其字体配置为远程加载的 PingFang SC 字体。
完整 API 参考
SDK 顶层导出(见 packages/core/src/index.ts)包括:
PaddleOCR.create(options)—— 创建 OCR 实例(默认自动初始化,可传initialize: false延迟初始化)ocr.initialize()—— 手动初始化(下载模型、创建会话)ocr.getInitializationSummary()—— 获取初始化摘要ocr.predict(image | images[], params?)→Promise<OcrResult[]>—— 执行预测ocr.dispose()—— 释放资源parseOcrPipelineConfigText(text)—— 解析产线配置文本normalizeOcrPipelineConfig(config)—— 规范化产线配置OcrVisualizer(来自@paddleocr/paddleocr-js/viz)renderOcrToBlob(来自@paddleocr/paddleocr-js/viz)deterministicColor(来自@paddleocr/paddleocr-js/viz)
从index.ts的导出列表可以看到,SDK 同时导出了大量类型:OcrResult、OcrResultItem、OcrResultMetrics、InitializationSummary、DetModelConfig、RecModelConfig、OrtOptions、PaddleOCRCreateOptions、ModelAsset等,便于 TypeScript 用户获得完整的类型提示。SDK 的exports字段将./viz作为独立子路径导出(见 packages/core/package.json)。
构建产物与发布
SDK 使用 Vite 的库模式构建(在packages/core中执行npm run build)。dist/下的构建产物包括:
index.mjs—— ESM 入口index.d.ts—— 类型声明viz.mjs—— 可视化子路径的 ESM 入口assets/worker-entry-*.js—— 自包含的 Worker bundle(OpenCV.js + ORT JS 运行时)
自定义 Vite 插件libraryWorkerPlugin会对构建产物做后处理,以兼容 npm 分发场景:
- 将 Worker 资源的绝对路径改写为相对路径,使文件相对于 SDK 模块路径解析,而不是站点根路径;
- 将
new Worker(new URL(STRING, import.meta.url))拆成 URL 变量与 Worker 构造,便于下游打包工具复制 Worker 文件,并避免被当作二次打包目标; - 移除 Vite 内联到 Worker 产物中的 base64 WASM 二进制——在 Worker 模式下,ORT 会在运行时通过
ort.env.wasm.wasmPaths加载 WASM(由使用方配置,或回退到与安装 ORT 版本绑定的 CDN),从而显著减小 Worker 文件体积。
开发阶段,demo 通过 Vitealias直接引用 SDK 源码,获得更好的 HMR 体验;生产构建时则通过 workspace 链接使用 SDK 预构建的dist/产物。
发布方面(详见 Monorepo 约定):
- 版本由Changesets管理;demo 包在
.changeset/config.json中被忽略,不作为 npm 发布目标; npm run release会构建 SDK 并通过changeset publish发布;packages/core的prepublishOnly会在npm publish/npm pack前自动执行构建。
工程化与测试策略
TypeScript 严格模式与代码规范
SDK 与 demo 都使用 TypeScript 严格模式,并配置了分级 ESLint 规则(详见 monorepo_cn.md):
packages/**/src/**/*.ts与apps/**/src/**/*.ts使用typescript-eslint的strictTypeChecked规则集,并启用面向浏览器的全局变量;packages/**/test/**/*.ts使用较轻的recommendedTypeChecked规则集(浏览器 + Node 全局),并放宽部分规则(例如no-unsafe-*与no-explicit-any);- 配置文件(
*.config.{js,ts})使用基础 ESLint 规则,同时启用 Node 与浏览器全局。
npm run typecheck会在所有 workspace 上执行tsc --noEmit。demo 在tsconfig.json里通过paths直接引用 SDK 源码,因此类型检查并不严格依赖先执行build:sdk。
测试策略
SDK 使用 Vitest 作为测试框架(测试文件位于 packages/core/test/),测试策略包括:
- 配置解析与注册表行为的单元测试(如
ocr-config-branches.test.ts、model-config.test.ts); - 面向浏览器平台辅助函数的 jsdom 测试(如
platform-browser.test.ts、runtime-ort.test.ts、runtime-opencv.test.ts); - Worker 传输层与产线逻辑测试(如
worker-client.test.ts、worker-protocol.test.ts、ocr-worker-entry.test.ts、worker-backed.test.ts); - 可视化模块测试(如
viz-draw-boxes.test.ts、viz-renderer.test.ts); - 公共 API 导出测试(
public-api.test.ts、browser-source.test.ts等)。
CI 默认不运行大规模真实模型推理,模型加载与真实推理通常依赖本地手动验证(例如通过 demo 应用)。
宿主应用的运行环境要求
使用 SDK 时,宿主应用仍需负责以下运行时环境相关事项:
- 启用多线程 WASM 或 WebGPU 时所需的COOP/COEP 响应头(
Cross-Origin-Opener-Policy/Cross-Origin-Embedder-Policy,用于crossOriginIsolated上下文,例如演示应用根据self.crossOriginIsolated决定是否启用多线程); - ONNX Runtime Web 的环境选项:wasm 资源托管路径(
wasmPaths)、线程数(numThreads)和 SIMD 开关; - 使用
worker: true时,能够产出并加载 module worker 的构建工具或运行时配置; - 静态资源托管与模型 URL 配置。
演示应用 apps/demo/src/main.ts 中展示了线程数选择的参考逻辑:在crossOriginIsolated环境下使用Math.min(4, Math.max(1, hardwareConcurrency - 1))计算线程数,否则回退为单线程。
更多参考文档
- 架构说明(中文) / 英文版
- 开发指南(中文) / 英文版
- Monorepo 约定(中文) / 英文版
- SDK 包 README(中文) / 英文版
SDK 的核心能力建立在 ONNX Runtime Web(浏览器端 ONNX 推理)与 OpenCV.js(浏览器端图像处理)之上,这也是 PaddleOCR.js 能在纯浏览器环境中完成端到端 OCR 的技术基础。
【免费下载链接】PaddleOCR飞桨多语言OCR工具包(实用超轻量OCR系统,支持80+种语言识别,提供数据标注与合成工具,支持服务器、移动端、嵌入式及IoT设备端的训练与部署) Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80+ languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)项目地址: https://gitcode.com/paddlepaddle/PaddleOCR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考