布局识别(Layout Recognition)
布局识别(Layout Recognition,简称 LR)用于对 PDF 页面执行版面结构分析,并输出可遍历的结构树。开发者可基于该结果识别段落、标题、表格、单元格、图片等版面元素,进一步提取位置信息、文本范围或结构属性。
该能力适合用于页面结构理解、表格区域识别、内容重组、服务端版面分析以及基于布局信息的后续处理。
适用场景
布局识别适合以下场景:
- 在服务端分析 PDF 页面结构,并将版面元素坐标传给前端进行展示、确认和校正
- 对表格类文档进行结构分析,提取表头、单元格和对应数据区域
- 基于布局结构和文本范围实现 PDF 转 HTML、翻译回填或内容审校
- 按段落、标题、单元格等结构读取文档内容,用于比对、抽取和二次加工
前置条件
- 需要使用包含
LayoutRecognition模块权限的授权初始化福昕 PDF SDK - 使用前应先成功加载目标 PDF 文档与页面
- 布局识别以
PDFPage为输入对象;如需处理整份文档,应由业务侧按页循环处理
能力说明
布局识别的核心输出不是“直接提取后的业务结果”,而是一个可遍历的结构树。开发者可在该结构树上继续做业务判断与数据抽取。
LR 输出的信息主要包括:
- 结构类型:如
Document、Sect、P、H1、H2、Table、TR、TH、TD、Figure - 几何信息:如结构元素或内容元素的
BBox - 结构属性:如
WritingMode、RowSpan、ColSpan、TableHeaders - 内容映射:内容元素在图形对象中的范围、矩阵和关联图形对象
对于表格场景,通常可通过遍历 Table、TR、TH、TD 等结构元素定位候选表格区域,再结合 BBox 和属性信息完成业务侧处理。
主要接口
布局识别的主要接口如下:
| 接口类 | 作用 |
|---|---|
LRContext | 以 PDFPage 为输入执行布局识别解析,并返回结构树根节点 |
LRElement | LR 元素基类,用于判断元素类型及元素类别 |
LRStructureElement | 结构树节点,可读取子节点、父节点、边界框和结构属性 |
LRContentElement | 内容元素,可读取内容范围、边界框、矩阵和关联图形对象 |
LRGraphicsObjectElement | 图形对象元素,可读取关联 GraphicsObject、边界框、矩阵和对象索引 |
基本使用流程
布局识别的常见使用流程如下:
- 完成福昕 PDF SDK 初始化
- 加载目标 PDF 文档并获取目标页面
- 创建
LRContext - 调用
StartParse()执行布局识别解析 - 通过
GetRootElement()获取结构树根节点 - 递归遍历结构树,按元素类型和属性读取业务所需信息
完整可运行示例请参阅 SDK 包中的 /examples/simple_demo/layout_recognition/layout_recognition.cpp。以下代码片段展示了页面解析和结构树获取的基本方式:
c++
#include "include/addon/layoutrecognition/fs_layoutrecognition.h"
using namespace foxit;
using namespace foxit::addon::layoutrecognition;
void ParsePageLayout(const wchar_t* input_file) {
// Foxit PDF SDK should have been initialized before LR starts.
PDFDoc doc(input_file);
if (doc.Load() != foxit::e_ErrSuccess) {
return;
}
PDFPage page = doc.GetPage(0);
LRContext context(page);
common::Progressive progressive = context.StartParse(NULL);
while (progressive.GetRateOfProgress() != 100) {
if (progressive.Continue() != common::Progressive::e_ToBeContinued) {
break;
}
}
LRStructureElement root = context.GetRootElement();
if (root.IsEmpty()) {
return;
}
int child_count = root.GetChildCount();
for (int i = 0; i < child_count; ++i) {
LRElement child = root.GetChild(i);
String type_name = child.StringifyType();
// 可按业务需要处理 type_name:例如输出调试信息、按结构类型筛选、映射到业务逻辑等。
}
}
结构树遍历与属性读取
在实际业务中,通常需要递归遍历 LRStructureElement,并按类型筛选目标节点。
常用读取方式包括:
- 通过
GetChildCount()/GetChild()遍历结构树 - 通过
GetElementType()或StringifyType()判断结构类型 - 通过
GetBBox()获取结构区域坐标 - 通过
GetSupportedAttributeCount()/GetSupportedAttribute()枚举结构属性 - 通过
GetAttributeValueType()和对应的GetAttributeValue*()方法读取属性值
如果需要把布局结构映射回页面内容或图形对象,还可以结合:
LRContentElement::GetGraphicsObjectRange()LRContentElement::GetBBox()LRGraphicsObjectElement::GetGraphicsObject()
输出结果说明
布局识别的输出更适合被视为“结构分析结果”,而不是直接可用的最终业务数据。
开发者通常会基于输出结果继续完成:
- 表格候选区域定位
- 标题、段落、单元格等结构分组
- 结构区域坐标提取
- 内容与页面对象的映射
- 业务字段抽取与后处理
SDK 示例会将结构树信息输出到 layout_recognition_info.txt,便于查看结构类型、属性和值的组织方式。
开发建议
在接入布局识别时,建议注意以下事项:
LRContext的输入对象是单页PDFPage,整份文档需要逐页处理StartParse()使用渐进式解析,处理复杂页面时应按Progressive流程继续执行至完成- 复杂页面中的候选表格、段落或标题通常仍需结合业务规则二次确认
- 带边框的规则表格通常更适合作为首批接入场景;无边框或高度复杂布局建议预留人工校正或后处理逻辑
- 若需要前端展示识别结果,建议直接使用结构元素或内容元素的
BBox作为页面坐标基础
何时使用布局识别
如果业务目标是“理解页面结构并基于结构继续处理内容”,适合使用布局识别。
例如:
- 需要识别表格、段落、标题、单元格等版面结构
- 需要将 PDF 页面内容按结构还原到 HTML、翻译、比对或抽取流程
- 需要获取页面元素的坐标、层级和关联关系,而不仅仅是纯文本内容
如果当前目标只是快速查看 SDK 中的调用方式,建议先阅读 SDK 包中的 /examples/simple_demo/layout_recognition/layout_recognition.cpp 示例。