导读:简述百度文库关于各类文档的转码和展现历程,早期的版式数据满足了PC端的各类文档阅读体验,随着业务发展的需求迭代,无线端的文档阅读体验亟需提升。版式数据转流式数据过程中,简易的内容结构化满足了pdf数据在无线端的重排版。底层解析ooxml数据和细致的内容结构化,则带来了不错的word无线端重排版效果。从chart图片中“从无到有”抽取结构化的元数据,更为用户与文档的互动打开了想象空间
全文3724字,预计阅读时间 9分钟。
一、百度文库中各类文档的展现
文库有数十亿海量文档,包括word,ppt,excel和pdf等十几种常见办公文档,核心基础服务是文档转码和展现。
为了统一十几种文档的转码和展现方案,不依赖于原文件格式的开档软件,技术调研后,最终方案为任意文档转码为pdf格式,解析开源的pdf数据格式,加工后形成文库自有文档格式,在pc端、无线端排版和渲染。
PC端渲染采用源于PDF的xreader版式数据,版式数据指的是每个元素(文字、图片)都有一个坐标信息和元素的宽高信息,以及其他的描述信息。每一个文本片段、图片和其他矢量元素等根据坐标信息在当前版面固定显示。因此,版式数据比较适合用于在PC端等比例展现各类文档,版式排版的还原效果较好。
无线端的屏幕尺寸普遍较小,如果将版式数据等比例缩小后排版,整个版面中的文字、公式较小,给阅读带来不便,如图1所示。虽然可以放大显示,但显然增加了用户的操作成本。
图1 无线端采用版式数据进行等比例缩小的版式排版
比较理想的方案是将版式数据转换成流式数据,根据不同的无线端屏幕尺寸,进行重排版。区别于版式数据中每个元素都有当前版面的坐标信息,流式数据没有坐标信息,有的是章节、栏、段落、公式和表格等结构化信息,大量的数据结构信息将最基础的文本、图片关联起来,形成结构化的文档内容,适合各种屏幕尺寸的自适应重排版。
二、文档内容结构化的技术探索
2.1 Retype流式数据(基于xreader版式数据)
文库早期文档内容“版式转流式”的方案,遍历xreader版式数据中的每个元素,提取坐标信息x,y和元素的宽高w,h信息。比较接近的y认为是同一行数据,y接近的情况下,根据x和w拼接相邻的文本元素、连接相邻的文本和图片。然后就得到当前版面的所有行数据结构line,根据每个line的y和h信息,将相邻line拼接为段落。通过判断当前line的x+w数据小于版面宽度、以特殊标点结尾,以及下一个line的x信息蕴含着段首缩进等情况,从而判定一个段落的结束。
以上是“版式转流式”方案的通用思路,当文档的版面结构较为复杂,比如论文、文献等存在大量多栏、图文绕排、表格脚注尾注的情况时,还需要进行range识别的预处理,将整个版面分析、切割成多个range结构,在每个range内再进行“版式转流式”的通用方案,才能得到较好的效果。
这种方案从版式数据中提取了“段落、行“等结构化信息,有助于流式排版。但一些case显示这些结构化信息的准确率达不到百分百正确,存在“段落被强制换行,inline图片位置错误”等情况,且对“公式、图表chart和表格”等复杂结构化信息的提取能力较弱。
不同于pdf文档中只有元素相对于版面的坐标信息且缺乏内容结构化信息,office文档如word文档,源文档中存在结构化信息,只是在word转pdf的转码过程中丢失了这些信息。因此,对文库占比较多的word文档提取结构化信息和提升无线端流式排版效果,成为阶段性的重要目标。
2.2 BDJson流式数据(基于ooxml数据)
微软office历史悠久,word存在许多版本,简化区分为doc二进制复合文档格式和docx的ooxml文档格式。Doc二进制复合文档格式较为复杂,且是微软的闭源项目,解析和转码的成本较高。为了简化方案,将doc转换成docx,然后核心方案就是解析docx格式,转码,产出BDJson格式流式数据。
OOXML是开源项目,基于zip+xml的格式,普通文本及其字符属性、段落属性的读取和解析较为方便,其自带章节、段落和表格等结构化信息,便于流式排版。基于本次排版需求,以及考虑到将来有word在线编辑的场景,方案设计为语义级别的精确解析文档,抽取内容和属性,组建office数据结构。
章节、段落等数据结构,遵循ooxml标准,从Document.xml中解析数据后即可组装成对应的数据结构。页眉页脚、脚注尾注等数据结构,Document.xml中存储的只是索引和基本信息,具体的区域内容需要从其他的xml文件中获取,按照索引的对应关系进行拼装,并插入到正文中的具体位置。
一些数据结构因office结构与html结构的差异性,需要做一些适配工作。例如常见的项目符号与编号,在word中可以有9层结构,每一层结构都有字符属性、段落属性、tab设置和图片编号等,需要兼容映射到html的ol、ul简易结构。表格中合并单元格的行跨、列跨和隐藏被合并单元格,在office和html中也是有很大差异,需要遍历整个表格,计算转换后进行兼容性转码。
此外,对一些在线编辑场景中涉及的数据结构,也做了提取和转码,例如将word中支持的多套公式数据“域公式、mathtype公式,omath公式”统一转码成LaTex数据格式,不仅便于后续编辑,而且可以适配正文的字体和大小,整体排版效果更统一。
以上技术方案的实施,完美提取了word文档中的结构化信息,优化了现有文档转码和展现的流程,如图2所示。文档内容结构化信息,使得word文档无线端可以实现自适应的流式排版,大为提升了展示效果,如图3所示。
图2 文档转码和展现(版式,流式)
图3 文档无线端流式排版和公式LaTex展现
2.3 chart图片(或pdf数据)中提取结构化数据
在论文、期刊和财经研报等特定类型的pdf文档中,经常会有一些图表chart信息,这些图表一般以“无结构的pdf数据、图片、背景图”的形式出现。提取这些图表信息,将元数据导入到excel中,让用户可以重新编辑、观测和生成新的chart,具有较大的产品价值。
现有的一些工具,一般都是让用户对文档中chart所在的区域range手动截图,然后人工选择坐标轴原点,输入坐标轴刻度等信息,对chart描边等一系列繁琐的操作,且数据提取的正确率不高。
Chart图片或无结构的pdf数据中提取结构化元数据的技术方案可以简化为两大模块:range识别,元数据提取。
2.3.1 Range识别
以pdf文档举例,首先遍历本页所有元素,将文本碎片span、图片等框选起来。原始span按y,x进行相邻merge,得到大一些的fragment, 进而聚合成line。line区域按文本数量和位置等信息,进行有效性判断,有些可消除。
搜索剩余空间内的空白区域,作为range的候选区域。获取页面设置信息,确定页面内容范围。从上往下遍历,先把整行空白的range识别出来。按行遍历,如果line两端尚有空余,加2个两端的range。用当前的line去碰撞已有的range,若相交,将相交部分消去,会把原有range切成多个新的range。至此,得到紫色的range候选区域集合,如图4所示。
图4 range候选区域集合
遍历range候选区域集合,按range的位置、宽高进行相邻range的合并和重新组合,得到新的一组range,如图5所示。
图5 range候选区域集合(合并后)
过滤range(根据矩形大小、位置、前后的文本line,ocr的文本数量等信息),同时对range的边缘进行白边切割,最后得到有效range,如图6所示。
图6 range候选区域集合(过滤后)
2.3.2 元数据提取
通过range识别模块产出的range集合,可以进行下一步的元数据提取。不是所有range里都是chart,可能是个简单图片、流程图等。
首先依据range信息,对当前页面截取range对应的图片,进行图像分析,初步判定是否是chart图片并进行初步的chart分类,例如柱状图、饼图,如图7所示。
图7 以图片形式展现的chart
以柱状图举例,基于像素分析和边缘提取算子的预处理,识别出x轴、y轴的候选线条,并依据长度、位置等信息,进行删选,最后得到xy轴,组成坐标体系。扫描xy轴上的刻度线,此时有较多干扰,可能误差较大,通过像素对比和交叉验证,给轴线补充上刻度线。
完整、正确的坐标体系对于后续的chart元数据提取很重要。基于坐标体系,可将整个图片切割成多个subRange,对subRange中的小图进行ocr,获取其中的文本,即可拼装成chart的数据项、各个数据点,经过一系列的数据矫正和重新组合,从而得到整个chart的元数据,如图8所示。
图8 从chart图片中提取的元数据
===
三、文档内容结构化的后续发展
随着业务的发展,基于文档整页展现的基础上,如何给用户更好的文档展现和互动效果,对文档转码和展现技术提出了更高的要求,而这一切的基础正是提取细粒度的文档元素和对文档内容进一步的结构化识别和提取。
招聘信息
百度-文库研发部,团队致力于建设业界领先的在线互动式文档、音频等知识分享平台,十年来汇集了超9亿份高价值文档资料,拥有近40万认证作者和2万家专业权威机构,已成为中国领先的文档与知识服务平台。百度文库坚持以“让每个人平等地提升自我”为目标,努力将知识尽可能地分享到每一个需要的角落。
诚邀iOS & Android小伙伴。
关注百度Geek说,公众号菜单栏点击内推即可。
推荐阅读
---------- END ----------
百度Geek说
百度官方技术公众号上线啦!
技术干货 · 行业资讯 · 线上沙龙 · 行业大会
招聘信息 · 内推信息 · 技术书籍 · 百度周边
欢迎各位同学关注
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。