PDF对企业应用来说是刚需。
 
然而PDF显然不是一种对机器友好的格式,它只是对人类友好,就是说方便阅读打印,但让程序去提取其中的内容却很难。下面简单说说为什么是这样。
 
以前还读书的时候(20+年前了),一个同学跟我展示了PDF文档,他说这种格式不是普通的文本,它是图片,所以比较大。其实他说的并不完全正确,pdf中可以包含图片,也可以包含文字,且其中的文字跟传统的位图还真是不一样。那么PDF中的内容究竟是什么?
以增值税普通发票的电子档为例,相信大家手头都有,对,就这个:

上面的文字究竟是图还是文本?上面的印章是不是位图?

判断是不是位图很简单,就是用一个PDF阅读器打开,Adobe的或者福昕的都行,选择“Select”工具,看看上面的文字能否选中。你很快就发现,不光上面的楷体字、宋体字能选中,印章里的文字居然也能选中,并且能复制下来,你把复制下来的文本贴到记事本里,这就是普通的文本。

这是不是就说明PDF里的文字就是我们常规理解的文本呢?其实没那么简单,PDF的一个特性就是不管处于怎样的环境,PDF都能显示出完整的、一致的内容。这意味着这张发票放到一个完全不支持中文的系统中,它也能显示出上面的汉字,并且效果完全一直,当然也包含了不同的字体,楷体,宋体,都没问题,这就比较厉害了。
 
其实原理也不难,那就是把字体信息直接嵌入到PDF文件内部。也许你觉得不对,我一个中文宋体的字库就有超过10MB了,而我的PDF才几百K,怎么可能?——要做到这点也不难,只嵌入部分即可。用福昕的PDF阅读器打开这张电子档发票,菜单"File" - "Properties" - "Fonts",你会看到这样的信息:

KaiTi,很明显是楷体,SimSun这是宋体,STSong则是华文宋体,而且编码格式都有,上面的UniGB-UCS2-H是什么编码格式我不太清楚,可能是Unicode,UC应该是Unicode的简写。
 
这里顺便提个事情,就是字体的侵权问题,如果在自己生成的PDF中嵌入字体厂商未授权的字体,很可能会造成侵权!而如果你做了一个网页,网页上指定了用未授权的字体(如微软雅黑)显示一段文字,这样则不会造成侵权,原因在于你并没有在网页上嵌入微软雅黑,你只是告诉用户的浏览器,这段文字建议用微软雅黑显示,用户看到的微软雅黑字体还是用户自己电脑提供的,跟你没有关系,所以不会造成侵权,侵不侵权在于你是否二次“发布”了这个字体。其实要避免侵权也不难,对我们来说,用可免费商用的字体即可,目前还不少,如Google的Noto系列,华为鸿蒙Sans、阿里巴巴普惠体以及小米最近发布的MiSans,这些都是可以免费商用的。
 
字体,本质上来说是矢量图,当然过去也曾经有过点阵字体,但现在基本算是淘汰了,矢量图一个特点是无论你放大多少倍,它都不会失真或出现马赛克,所以一定要我说PDF中保存的文字到底是图还是字,那我就说,那是矢量图,这肯定是正确的,因为如今的字体本质上就是矢量图嘛。
 
而PDF中除了字之外,别的你能看到的很多的元素,其实也都是矢量图,如表格的线条,印章的圆圈这些,要证明也很简单,使劲放大,看看有没有失真出现马赛克或者模糊即可。
 
当然了PDF中还可能有位图,判断方法还是上面提到的,放大来看。
 
PDF的文字的组织形式与我们txt,word或是html都不太一样,举个例子,你打开PDF看到的两个挨在一块的文字,如“力量”,这两个字你觉得它是一个连在一起的词,其实未必,很可能它是通过两个不同的坐标来指定的,从文档结构上来说,你读取“力”字,不意味着它的下一个元素就一定是“量”字,尽管视觉上是这样。这就给我们提取PDF的文本信息带来很大的挑战,我们很难通过直接分析PDF的文档结构提取其中的文字,比较稳妥的方法还是得通过显示的结果来获取内容,是的,就是OCR的路线。但即便要使用OCR的路线,也是问题很多,下面这个例子就反映了一个很典型的问题:

阅读器显示的“μ”和“接”中间的这个符号在我看来很像一个竖线,即“|”,而实际上它却是英文字母“l”,用阅读器复制到记事本中可以证实这点,确实是字母“l”,只不过Windows10种的字母“l”显示得跟数值“1”一模一样,真是令人无语,如果使用OCR的方式,字母“l”很可能就被识别为竖线,或者字母“I”(大写的i),还有就是“μ”这种希腊字母,在OCR中直接被识别成了英文字母“u”,这就很明显有问题了,对于需要精确导入信息的企业应用来说,这显然是不行的。
 
另一个问题也在上图中有体现,就是对空格的理解,福昕阅读器复制出来的内容中包含了一个空格,而别的没有,究竟有没有这个空格,这个很难说,就像我在黑板上写了两个字,间隔远点就算有空格,间隔近了就没有空格,可这个远和近如何界定,这个就比较难办了。
 
我曾经做过一套PDF内容提取的框架,能通过一些配置信息尝试从PDF中提取文本内容,但遇到了很大的麻烦,就如上面提到的那样,两个看上去连贯的文字,读出来的先后顺序是没法保证的,绕来绕去还绕回了OCR的路子,但OCR也是问题不少,总得来说,对于需要精准信息提取的应用来说,真是最好别用PDF了。——但话虽然这么说,客户可不一定能理解,做和不做也不完全由得技术说了算,现实如此也……

PDF的信息提取的问题的更多相关文章

  1. Beta版本发布说明

    发布地址 https://github.com/LongWerLingShi/DataObtainingAndHandling/tree/beta 版本开发背景 首先,应软件工程课程要求,我们小组针对 ...

  2. 数据获取以及处理系统 --- 功能规格说明书V2.0

    产品规格说明书: 版本号: V2.0 版本说明: Version 1.0 简单得需求分析以及构思,初稿形成 Version 2.0 细化beta阶段设计,增加典型用户尝尽以及功能罗列 1. 引言 1. ...

  3. Scrum Meeting 11 -2014.11.17

    今天和其他两个小组讨论了关于整合问题,在数据库连接等具体方面上还需要继续商讨. 我们小组内部讨论了,这周还是需要在处理整合的同时做项目整体的测试与改进的. Member Today’s task Ne ...

  4. Scrum Meeting 10 -2014.11.16

    开始进入大项目的整合阶段,平时和其他两个小组交流较少,整合难度还是存在的. 在具体整合前,让开发人员添加了些必要的注释,优化代码结构,方便阅读. Member Today’s task Next ta ...

  5. Scrum Meeting 9 -2014.11.15

    项目开发测试要进入尾声了.大家加把劲,这周末能整合完成就最好了. 服务器方面已经能运行我们的程序了.还需要研究如何与其他两小组整合. Member Today’s task Next task 林豪森 ...

  6. Scrum Meeting 8 -2014.11.14

    给开发加了个pdf信息提取优化任务. 弄了半天发现服务器也是个好东西.这周末可以和爬虫讨论整合的问题了. Member Today’s task Next task 林豪森 协助测试及服务器部署 协助 ...

  7. Scrum Meeting 7 -2014.11.13

    之前srcum没写好是我的错.以后会每天更新的. 老师反映之前项目小组从pdf中提取作者效果不好,我们讨论决定进行一定的优化.在整合测试的同时开始服务器程序部署. Member Today’s tas ...

  8. 会务准备期间材料准备工作具体实施总结 ----(vim技巧应用, python信息提取与整合, microsoft word格式调整批量化)

    会务准备期间材料准备工作具体实施总结(vim, python, microsoft word) span.kw { color: #007020; font-weight: bold; } code ...

  9. C#给PDF文档添加文本和图片页眉

    页眉常用于显示文档的附加信息,我们可以在页眉中插入文本或者图形,例如,页码.日期.公司徽标.文档标题.文件名或作者名等等.那么我们如何以编程的方式添加页眉呢?今天,这篇文章向大家分享如何使用了免费组件 ...

随机推荐

  1. freeswitch APR库线程读写锁

    概述 freeswitch的核心源代码是基于apr库开发的,在不同的系统上有很好的移植性. 线程读写锁在多线程服务中有重要的作用.对于读数据比写数据频繁的服务,用读写锁代替互斥锁可以提高效率. 由于A ...

  2. Linux 目录结构及详细操作

    目录 Linux 目录结构及详细操作 目录结构 目录结构的特点 目录结构挂载 目录结构发展 关闭selinux(了解) 重要目录说明(etc目录说明) 1.网卡配置文件 2.解析配置文件 3.主机名称 ...

  3. 4、Redis基础

    redis性能 1.关于测试性能 官方自带的测试性能的工具 redis-benchmark 压力测试工具 #进行压力测试.需求:测试:100个并发连接,100000个请求 #redis-benchma ...

  4. pyecharts简介

    一.概况 Echarts 是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可. 而 Python 是一门富有表达力的语言,很适合用于数据处理.当数据分析遇上数据可 ...

  5. CF616B Dinner with Emma 题解

    Content 翻译很明白,或者你也可以看我的简化版题意: 求一个 \(n\times m\) 的矩阵中每行的最小值的最大值. 数据范围:\(1\leqslant n,m\leqslant 100\) ...

  6. LuoguB2035 判断数正负 题解

    Content 给定一个数 \(n\),判断这个数的正负. 数据范围:\(-10^9\leqslant n\leqslant 10^9\). Solution 一个基础的分支结构题. if-else ...

  7. Uni-app原生插件入门使用教程「2」:如何离线使用原生插件

    当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力. 如使用Uniapp开发直播功能时,需要调用 ...

  8. Learning to Sample

    此处主要提出几个疑问和想法: 疑问: 为什么需要这个匹配过程?虽然G可能不是P的子集,但是为什么一定需要他是子集呢? 如果一定要匹配的话,匹配过程是没法反向传播的,所以只可以在推理阶段使用,那么这个推 ...

  9. 【LeetCode】1418. 点菜展示表 Display Table of Food Orders in a Restaurant

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典统计边的次数 日期 题目地址:https://le ...

  10. 【LeetCode】361. Bomb Enemy 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力搜索 日期 题目地址:https://leetco ...