news 2026/9/25 5:33:38

xberg C FFI 实战:用 force_ocr 强制对每一页 PDF 执行 OCR

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
xberg C FFI 实战:用 force_ocr 强制对每一页 PDF 执行 OCR
  • 后端
  • AI 应用
  • NLP

【免费下载链接】xberg

Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.

项目地址:https://gitcode.com/gh_mirrors/kr/xberg
点击查看免费下载

本篇技术指南基于仓库中的 C 语言示例 ocr_force_all_pages.md,讲解如何通过 xberg 的 C FFI 接口启用force_ocr,让已经带有原生文本层的 PDF 页面也逐页走 OCR 识别。读完本文,你将掌握 xberg C 绑定中"输入句柄 → 配置句柄 → 提取 → 释放"的完整调用链,理解force_ocr与ocr、ocr_strategy、force_ocr_pages、disable_ocr等配置项之间的语义关系,并能结合 e2e 契约测试验证该配置的实际效果。

场景与完整示例

该示例要解决的问题是:默认情况下,xberg 对已有可用文本层的 PDF 页面直接使用原生文本提取,不跑 OCR;而某些 PDF 的文本层质量差(例如扫描仪生成的"隐形文本层"),需要强制用 OCR 引擎重新识别每一页。为此,xberg 在提取配置顶层提供了force_ocr开关。

下面是文档中给出的完整 C 示例,它通过 JSON 字符串构造输入与配置,再调用xberg_extract完成提取:

#include <assert.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "xberg.h" int main(void) { // 1. 构造提取输入:从 JSON 反序列化为 ExtractInput 句柄 // kind=uri 表示按 URI 拉取文档;mime_type 显式指定为 application/pdf XBERGAlefHandle input_handle = xberg_extract_input_from_json("{\"kind\":\"uri\",\"mime_type\":\"application/pdf\",\"uri\":\"https://example.com/pdf/fake_memo.pdf\"}"); // 2. 构造提取配置:force_ocr=true 强制 OCR 每一页; // ocr 子配置指定启用 OCR、后端为 tesseract、语言为英文 XBERGAlefHandle config_handle = xberg_extraction_config_from_json("{\"force_ocr\":true,\"ocr\":{\"backend\":\"tesseract\",\"enabled\":true,\"language\":[\"eng\"]}}"); // 3. 执行提取,返回提取结果句柄 XBERGAlefHandle result = xberg_extract(input_handle, config_handle); // 4. 逐个释放句柄,避免内存泄漏 xberg_extract_input_free(input_handle); xberg_extraction_config_free(config_handle); xberg_extraction_result_free(result); return EXIT_SUCCESS; }

示例中有两个关键 JSON:

JSON作用关键字段
输入 JSON描述"从哪里取文档"kind: "uri"、mime_type: "application/pdf"、uri
配置 JSON描述"如何提取"force_ocr: true、ocr.enabled、ocr.backend、ocr.language

其中uri指向的fake_memo.pdf在 e2e 环境中由 mock 服务器提供——见下文"契约测试如何验证"一节。

C FFI 调用链解析

该示例体现了 xberg C 绑定的标准调用范式,所有跨语言对象都以不透明句柄XBERGAlefHandle传递:

  1. xberg_extract_input_from_json(json):把 JSON 反序列化为一个提取输入(支持uri与bytes两种 kind),返回输入句柄。
  2. xberg_extraction_config_from_json(json):把 JSON 反序列化为ExtractionConfig,返回配置句柄。
  3. xberg_extract(input, config):执行提取管线,返回结果句柄。
  4. xberg_extract_input_free/xberg_extraction_config_free/xberg_extraction_result_free:三者必须分别调用,负责释放 Rust 侧堆内存。

这些函数由 FFI 头文件xberg.h声明,该头文件位于 crates/xberg-ffi 子 crate 中,并配合 cbindgen.toml 从 Rust 源码生成,保证声明与实现一致。因此 C 侧使用者不需要了解 Rust 类型系统,只需 include 头文件并按句柄模型管理生命周期。

force_ocr 的配置语义(源码级说明)

force_ocr定义在核心提取配置结构体 ExtractionConfig 中,与它同属一组的还有几个 OCR 相关配置项,理解它们的组合关系才能正确使用:

/// Force OCR even for searchable PDFs #[serde(default)] pub force_ocr: bool, // 默认 false /// Force OCR on specific pages only (1-indexed page numbers, must be >= 1). #[serde(default)] pub force_ocr_pages: Option<Vec<u32>>, // 仅对指定页强制 OCR /// Disable OCR entirely, even for images. #[serde(default)] pub disable_ocr: bool, // 与 force_ocr 互斥

各配置项的语义如下:

  • force_ocr: bool(默认false):置为true时,即使是可检索 PDF(已有文本层),每一页也都会走渲染 + OCR 流程。这是本文示例采用的方式,适合"整份文档的文本层都不可信"的场景。
  • force_ocr_pages: Option<Vec<u32>>:按 1 起始页码只对列出的页面强制 OCR,未列出的页面走原生文本提取。从源码注释看,当force_ocr为true时该字段被忽略;重复页码会自动去重。适合"只有个别页质量差"的局部修正场景。
  • ocr: Option<OcrConfig>:OCR 子配置(后端、语言、Tesseract 参数等)。注意源码文档明确说明:None表示对已有可用文本的文档不跑 OCR;但在默认的OcrStrategy::Auto下,完全没有文本层的扫描件仍会以默认设置走 OCR,避免返回空结果。因此示例中在force_ocr之外同时给出ocr配置,是为了显式指定后端为tesseract、语言为eng。
  • disable_ocr: bool(默认false):彻底禁用 OCR(图片只返回元数据,PDF 只用原生文本)。源码注释指出它与force_ocr不能同时为true,配置校验会拒绝这种冲突组合。

与 ocr_strategy 的关系:三种"哪些页被 OCR"的模式

当force_ocr与force_ocr_pages都不生效时,决定页面级 OCR 行为的是ocr_strategy字段,其类型为 OcrStrategy:

pub enum OcrStrategy { /// OCR only when the native text layer fails a quality check (default). #[default] Auto, /// Additionally OCR every page that looks like a scan. ScannedPages { min_confidence: f64 }, }
  • Auto(默认):仅当某页原生文本层未通过质量检查时才 OCR。源码注释特别指出:扫描仪附带的"隐形 OCR 副层"通常能通过质量检查,因此这类页面在Auto下会被原生提取,而不是重跑 OCR——这正是force_ocr存在的动机之一。
  • ScannedPages { min_confidence }:额外识别"看起来像扫描件"的页面(依据栅格覆盖度、文本层是否隐形/缺失、图像编解码器与文档生成者等信号打分),达到置信度阈值(默认0.70,见 ocr.rs 中的DEFAULT_SCANNED_MIN_CONFIDENCE)的页面走 OCR,其余页面仍保留原生文本并参与Auto质量检查。它识别的是"文本层是否来自扫描仪",而不是文本层是否准确。

三种模式的定位可以概括为:Auto保守兜底、ScannedPages按扫描概率选择性重识别、force_ocr无差别全量重识别。若只需局部修复个别页,force_ocr_pages是成本最低的选择。

配置 JSON 的解析细节

示例中的配置 JSON{"force_ocr":true,"ocr":{"backend":"tesseract","enabled":true,"language":["eng"]}}在 Rust 侧反序列化为ExtractionConfig与OcrConfig,有几个值得注意的解析规则(实现见 crates/xberg/src/core/config/ocr.rs):

  • language字段同时接受字符串和数组:"language":"eng"与"language":["eng"]均可;形如"eng+deu"的字符串会按+拆分为多语言列表(兼容 Tesseract 传统写法)。这也是多语言 OCR 的标准写法。
  • ExtractionConfig启用#[serde(deny_unknown_fields)]:JSON 中出现未定义字段(例如拼错force_ocr为force_ocr_all)会直接报反序列化错误,而不是静默忽略,这对排查配置问题非常友好。
  • 配置校验:force_ocr与disable_ocr同真、ScannedPages.min_confidence超出[0.0, 1.0]或为非有限值等组合,会被配置校验逻辑拒绝。

契约测试如何验证这条链路

该 C 示例对应的契约夹具 ocr_force_all_pages.json 完整描述了一次可复现的端到端验证:

{ "id": "ocr_force_all_pages", "description": "Forces OCR on every PDF page even when a text layer exists", "call": "extract", "input": { "mock_responses": [ { "path": "/pdf/fake_memo.pdf", "status_code": 200, "headers": { "content-type": "application/pdf" }, "body_file": "../test_documents/pdf/fake_memo.pdf" } ] }, "assertions": [ { "type": "equals", "field": "results[0].mime_type", "value": "application/pdf" }, { "type": "contains_all", "field": "results[0].content", "values": ["bottles", "blankets", "laptops"] } ], "config": { "force_ocr": true, "ocr": { "enabled": true, "backend": "tesseract", "language": ["eng"] } } }

夹具的工作方式:

  1. mock 服务器(side_effects: server)在/pdf/fake_memo.pdf路径上返回测试 PDFfake_memo.pdf,使 C 示例中的https://example.com/...类 URI 可被本地拦截。
  2. 断言要求结果 MIME 类型为application/pdf,且提取内容包含bottles、blankets、laptops三个词——这些词只能由 OCR 从扫描件页面中识别出来,从而证明force_ocr确实覆盖了"已有文本层"的判定逻辑。
  3. 文档站的 C 示例标注level: typecheck,即生成代码会随 e2e 体系做编译级校验,保证 FFI 签名持续可用。

实用建议

  • 何时用force_ocr:整份 PDF 的文本层来自早期扫描仪、乱码比例高,或你希望用更强的后端(如示例中的 tesseract 英文识别)统一重识别时,使用force_ocr: true。
  • 何时不该用:文本层质量正常的文档上全量 OCR 会额外承担逐页渲染与识别开销;此时优先考虑ocr_strategy的ScannedPages模式,或用force_ocr_pages只处理已知有问题的页码。
  • C 侧生命周期纪律:每个*_from_json创建的句柄和xberg_extract返回的结果句柄都必须调用对应的*_free释放;示例中先执行xberg_extract再依次释放输入与配置句柄,是可复制的标准写法。

延伸阅读

  • 手写 C 示例(手工维护、非自动生成):ocr_extraction.md、basic_usage.md
  • C 示例的自动生成源:snippets-generated/c 目录,文件头部注明由 alef 生成,可用alef e2e generate再生
  • FFI 实现与头文件生成配置:crates/xberg-ffi
  • 相关契约夹具:ocr_basic_config.json、ocr_dpi_config
  • 后端
  • AI 应用
  • NLP

【免费下载链接】xberg

Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.

项目地址:https://gitcode.com/gh_mirrors/kr/xberg
点击查看免费下载
上一篇:MulimgViewer未来路线图:即将推出的7大实用功能预览
下一篇:HackRF-Treasure-Chest中的信号捕获与分析:从理论到实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 5:33:32

Docker快速入门:从环境一致性到生产就绪的实战路径

1. 为什么“Docker快速入门”不是一句空话&#xff0c;而是你今天必须动手的起点 我带过三届校招新人&#xff0c;也帮二十多家中小团队做过技术基建梳理。每次聊到容器化落地&#xff0c;总有人先叹气&#xff1a;“Docker太重了&#xff0c;学完还得配环境、调网络、写Docke…

作者头像 李华
网站建设 2026/9/25 5:32:50

2026企业SD-WAN组网怎么选?12个选型要点与5种主流组网模式

本文面向负责多分支网络的 IT 负责人与网络架构师。厂商与产品信息为公开资料整理&#xff1b;文中案例均已脱敏&#xff0c;数字为参考值&#xff1b;技术估算基于公开模型&#xff0c;以实测为准。SD-WAN 已经过了"要不要上"的阶段。十年前它以"用互联网替代昂…

作者头像 李华