Skip to content

布局识别(Layout Recognition)

布局识别(Layout Recognition,简称 LR)用于对 PDF 页面执行版面结构分析,并输出可遍历的结构树。开发者可基于该结果识别段落、标题、表格、单元格、图片等版面元素,进一步提取位置信息、文本范围或结构属性。

该能力适合用于页面结构理解、表格区域识别、内容重组、服务端版面分析以及基于布局信息的后续处理。

适用场景

布局识别适合以下场景:

  • 在服务端分析 PDF 页面结构,并将版面元素坐标传给前端进行展示、确认和校正
  • 对表格类文档进行结构分析,提取表头、单元格和对应数据区域
  • 基于布局结构和文本范围实现 PDF 转 HTML、翻译回填或内容审校
  • 按段落、标题、单元格等结构读取文档内容,用于比对、抽取和二次加工

前置条件

  • 需要使用包含 LayoutRecognition 模块权限的授权初始化福昕 PDF SDK
  • 使用前应先成功加载目标 PDF 文档与页面
  • 布局识别以 PDFPage 为输入对象;如需处理整份文档,应由业务侧按页循环处理

能力说明

布局识别的核心输出不是“直接提取后的业务结果”,而是一个可遍历的结构树。开发者可在该结构树上继续做业务判断与数据抽取。

LR 输出的信息主要包括:

  • 结构类型:如 DocumentSectPH1H2TableTRTHTDFigure
  • 几何信息:如结构元素或内容元素的 BBox
  • 结构属性:如 WritingModeRowSpanColSpanTableHeaders
  • 内容映射:内容元素在图形对象中的范围、矩阵和关联图形对象

对于表格场景,通常可通过遍历 TableTRTHTD 等结构元素定位候选表格区域,再结合 BBox 和属性信息完成业务侧处理。

主要接口

布局识别的主要接口如下:

接口类作用
LRContextPDFPage 为输入执行布局识别解析,并返回结构树根节点
LRElementLR 元素基类,用于判断元素类型及元素类别
LRStructureElement结构树节点,可读取子节点、父节点、边界框和结构属性
LRContentElement内容元素,可读取内容范围、边界框、矩阵和关联图形对象
LRGraphicsObjectElement图形对象元素,可读取关联 GraphicsObject、边界框、矩阵和对象索引

基本使用流程

布局识别的常见使用流程如下:

  1. 完成福昕 PDF SDK 初始化
  2. 加载目标 PDF 文档并获取目标页面
  3. 创建 LRContext
  4. 调用 StartParse() 执行布局识别解析
  5. 通过 GetRootElement() 获取结构树根节点
  6. 递归遍历结构树,按元素类型和属性读取业务所需信息

完整可运行示例请参阅 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 示例。