DjVu、PDF中的隐藏文本
作者:马健
邮箱:stronghorse_mj@hotmail.com发布:2012.06.11
一、背景
目前对于扫描电子文档,网上比较流行的格式是PDF和DjVu。为了便于对扫描文档进行文字检索、复制,这两种格式均允许在扫描图像层之外,再加一层隐藏文字层,成为通常所说的“双层PDF”和“双层DjVu”。
对于双层PDF和DjVu来说,阅读者所直接看到的都是原汁原味的扫描页面,保留了原始书籍页面的全部内容和版式,但当阅读者用鼠标在页面上拖拽选择时,又能选中、复制人眼看不到的隐藏文字。同时阅读者使用文本搜索功能,也能对隐藏文字进行检索。因此可以说双层PDF和DjVu既保留了扫描文档的原始风味,又兼得文字版的便利。
目前双层PDF和DjVu的隐藏文字均通过OCR技术获得,而在目前的OCR技术条件下,准确率不太可能是100%。就算达到99%的准确率,三千字的短文也有
三十字的错误,因此如果直接去读OCR的内容,估计很多人会读不下去,这也是要把文字隐藏起来,仍然去读图的原因。
换句话说,双层PDF和DjVu人读是没有问题,如果扫描图像的质量、分辨率足够的话,复制、检索问题也不大,但完全相信其中的文本则不太现实,也就是参考吧
,除非人工对文字内容进行校对,校对过程可参见我写的《校对双层PDF中的隐藏文本》。
从使用层面来说,PDF和DjVu中的隐藏文本如上所述,差别不大。但在技术层面上,我感觉二者还是有差异的,下面结合我在开发DjVuToy的相关功能中的一些体会加以说明。
二、DjVu中的隐藏文本
在DjVu中,文本的表示相对简单:
- 每页有一个TXTz或TXTa段,二者内容是一样的,只不过一个经过压缩,另一个没有压缩。
- 段头包含版本信息、字符串、字符串长度。这个字符串就是该页中全部文本的集合,说白了就是把该页中的全部文字拼起来就是这个字符串,采用utf-8编码。
- 段头后面是一个列表,具体说明每个文字在页面上的显示位置、尺寸、内容,称为zone。
zone包含下列内容:
- ZoneType:可以是Page、Colume、Region、Paragraph、Line、Word和Character
- x、y:zone的左上角在页面上的坐标位置(像素)
- width、height:zone的宽度、高度(像素)
- offText:zone所含内容在页面字符串中的起始位置
- lenText:zone所含字符串的长度。offText、lenText合起来决定了zone的文字内容
- nChildren:下级zone的数量,如一个Word下面含几个Character
从DjVu对文字的定义看,DjVu中的隐藏文本在技术上有几个特点:
1、是真正的“隐藏文本”,没法直接显示
DjVu中的文字有utf-8编码,有文字的显示位置、显示尺寸,但是没有字体信息,因此如果想显示出来,还需要指定字体信息。
正是因为文字根本就没打算显示,所以在DjVu浏览器中文字与图像完全不会互相干扰,双层DjVu也就没有双层PDF所需考虑的究竟是“图压字”还是“字压图”的问题。另外也不需要考虑文本究竟是横排还是竖排的问题:反正你也看不见,你
管它是横排还是竖排? 可能是受DjVu文字的影响太深刻,DjVu官方软件Caminova DocumentExpress Enterprise
7.5(简称deent75)在将DjVu转为PDF时,虽然支持隐藏文字的转换,也支持横排的亚洲语言,但就是不支持竖排的亚洲语言。
除竖排的问题外,DjVu中简单的文字表示也造成校对的问题:没办法直接把文字显示出来进行校对,只能把文字导出成XML,校对后再导入DjVu。
DjVuToy的一个德国用户向我介绍过一个校对DjVu中隐藏文本的方法:对同一个DjVu文件,用MODI和ABBYY各OCR一遍,导出纯文本,然后用文本比较工具进行比较,能够较快地发现OCR的错误。按他的说法,至少对于德语来说,MODI和ABBYY各有千秋,所以他用这个方法屡试不爽。有兴趣的不妨也试试。
2、文本信息比较简单,节省存储空间,也容易复制、导出
从定义就可以知道了,没有PDF那么多花狸狐哨的东西,相对比较简洁,有利于减小文件长度。而且DjVu中的文本统一采用utf-8编码,这个是有标准的,做不了什么手脚,转换成Unicode也比较容易,因此理论上说从DjVu复制或导出的文字不可能是乱码,而PDF则不一定。
3、没有平台、语言的问题
utf-8是一种已经标准化的编码,与Unicode完全通用,因此在所有支持Unicode的平台上,都可以检索、复制。而由于没有字体等限制,因此也不存在平台兼容性问题。
4、对文本位置定义比较细致,以便用鼠标选择
从ZoneType的定义就可以看出,对Page、Colume、Region、Paragraph、Line、Word和Character分得比较细,鼠标选择的时候,可以从Character选到Word,再选到Line、Paragragh等。
其实“细致”是比较好听的遮羞说法,在我看来,这种“细致”完全是迫不得已:由于没有字体信息,根本就不知道字符的宽度究竟是多少,因此鼠标拖动的时候,没有办法准确计算用户究竟选中了字符串的哪个部分,因此只能“细致”一点,从Character开始定义了。
换句话说,如果某个DjVu文件的文字定义粒度到Character,那么用户选择的精度就到字母;如果定义粒度到Word,就只能一次选一个词;如果粒度到Line,就只能一次选一行。原因很简单:在没有字体信息的情况下,实在算不出来一个Word或Line中的一部分在屏幕上的宽度究竟是多少,除非知道每个Character的宽度。
这种“细致”不仅会平白增加一些数据量,而且给文本校对带来了麻烦:DjVu的文本校对都是把隐藏文字导出成XML,校对后再导入回去。如果文字粒度到Character,校对时会非常吃力;如果粒度到Line,校对会很省力,但鼠标选择的时候就只能选整行了。这个问题我至今没找到什么解决办法。
三、PDF中的隐藏文本
PDF中的文本定义比较复杂,在《PDF Reference sixth
edition》中用整整一个第5章进行描述,共90页,翻译过来也够出一本书了。这么长的内容我不想写,各位也未必想看,还是直接说其技术特点吧。
1、隐藏文本可以显示出来
按《PDF Reference sixth
edition》的规定,PDF中的隐藏文本只不过是普通文本的一个特例:在页面内容流中,如果Tr参数是3则文本不显示出来,成为隐藏文本,否则就显示出来。
这种情况对校对比较有利:可以通过修改Tr参数把隐藏文字显示出来,则文字位置、内容是否准确一目了然,发现有问题用Foxit Phantom、Foxit
PDF Editor修改起来也很方便。
PDF中隐藏文本的这个特性是靠下面这个特点保证的:
2、文本定义比较完备
PDF中的文本除了编码、显示矩阵(位置、比例)外,还有字体、字号等。
在PDF中,一个字的“编码”与“显示”是分离的,中间连接的桥梁就是“字体”。简单点说,编码是一个字的内部表示方法,但这个字显示出来究竟是这么样子,要看你用的是什么字体。比如说我的姓是“马”,这个字的GB码是C2ED,Unicode码是9A6C,用宋体显示出来的就是宋体的“马”,用
篆体显示出来的就是篆体的“马”,但要用韩文的字体显示呢?根本就显示不出来,因为没有这个字。
这种分离与连接,就产生了下一个特点:
3、文本能不能被复制、检索、保存,由制作者决定
如前所述,一个字“看起来”是什么样子,是由文字编码与字体共同决定的:PDF浏览器显示文字时,根据编码从字体文件中查找到这个字的字形轮廓,然后按照轮廓定义一笔、一笔把这个字“画”出来。
而在复制、检索、保存的时候,是针对文字的编码来的:按照PDF标准的规定,PDF文件中的字体说明部分有义务提供将文字编码转换成Unicode的转换表,所有复制、检索、保存均针对Unicode。
但是“有义务”不等于“一定要”,何况还可以故意提供一个假的转换表。不论是不提供转换表还是提供假的转换表,最终的结果就是阅读者在看的时候是看到正确的“文字”(其实是画出来的字形),但是复制、存盘出来的却是一堆乱码,检索也检索不到什么。这种手脚在采用内嵌字体的时候更容易做,因为内嵌字体的编码本来一般就不会用标准编码。
4、存在平台兼容性问题
PDF中的字体可以是外部字体,也可以是内嵌字体。外部字体即在PDF中只存放字体名称,但不存放字体文件,显示的时候PDF浏览器根据字体名称,从外部字体文件读取字形。内嵌字体则是将所有需要的字形组合成一个字体文件,嵌入到PDF文件中。
毫无疑问,采用外挂字体的PDF的文件长度要比采用内嵌字体的PDF要小,因为不需要存储字形。但是外挂字体存在平台兼容性问题:你怎么保证阅读者在阅读PDF的时候,所处的环境正好就有所需的字体文件?
内嵌字体没有平台兼容性问题,因为所有需要的东西都已经嵌入PDF里了,不必再从外部读取,付出的代价就是文件长度增加。对于字母文字来说,这种代价不算沉重,毕竟字母是有限的。号称有5千年历史的中文则不一样,不同的字太多了。
一个折中的办法是:使用PDF规定的标准外挂字体。虽然花样少了点,但省地方,兼容性也有标准规范做保证。当然PDF浏览器的开发者非要不遵守规范你也没办法。另外标准外挂字体支持的语言是有数的,好在常用的Latin
1(西欧各国)、中文简体、中文繁体、日文、韩文都没有问题,别的就管不了这么多了。
外挂字体除了节省PDF文件长度外,还有一个好处是文字编辑容易:所有的字形都在外挂字体文件里,PDF中加几个字都无所谓。内嵌字体通常是用到的字才嵌入,如果想加入新的字就比较麻烦了。就是考虑到校对的问题,所以在DjVuToy、FreePic2Pdf、Pdg2Pic生成的双层PDF中,才清一色采用外挂字体——没办法,目前的技术条件下OCR准确率100%只能是梦想。
5、鼠标选择文字时,单位精确、细致
由于有字体信息,PDF浏览器可以精确计算一个字符串中的某个部分在屏幕上的显示尺寸,因此即使把整行单词拼成一个长串,用鼠标选择时也可以从字母选到词,再选到行。
这种情况更适合用所见即所得的方式对文件进行编辑,因此带来了校对的便利。
另外对中、日、韩字体,还有横排、竖排的区别。在横排情况下,鼠标光标是竖线;在竖排情况下,鼠标光标是横线。原因是在不同的排版方式下文字的选择方式不同,这个区别找两个文件比划一下就知道了。
6、字压图 or 图压字?This is a question
其实就是说在双层PDF中,究竟是文字层在图像层之上(字压图),还是图像层在文字层之上(图压字)。
理论上说,这两种情况都是允许的,也都有商业实践者:Acrobat生成双层PDF时用的是字压图,而deent75用的是图压字。
我个人更喜欢字压图:对于字压图来说,只要把Tr参数从3改成其他,即可将文字显示出来,便于检查、校对。而对于图压字来说,只改Tr则字会被图盖住,显示不出来,除非
再把图整个隐藏掉。所以在DjVuToy、FreePic2Pdf、Pdg2Pic生成的双层PDF中,全部是“字压图”。
DjVu、PDF中的隐藏文本的更多相关文章
- 校对双层PDF中的隐藏文本
作者:马健邮箱:stronghorse_mj@hotmail.com发布:2012.06.11 目录一.背景二.能够校对的PDF需要满足的条件三.校对工具的选择四.校对过程五.延伸讨论 事先声明:本文 ...
- Js控制显示、隐藏文本框中的密码
Js控制显示.隐藏文本框中的密码,也可称为是一款小型的JavaScript星号密码破解器,点击会显示出密码类型的文本框中的真实信息,再次点击则还原,程序 主要是获取HTML元素对象,然后强制更改元素属 ...
- .net环境下从PDF文档中抽取Text文本的一些方法汇总
1.PDFBox的IKVM版本:据我所知,目前只有PDFBox的IKVM版本能比较好地从PDF中提取文本,PDFBOX更多信息请访问http://www.pdbox.org,关于其应用实例,可以参考C ...
- C#在PDF中如何以不同颜色高亮文本
高亮的文本有助于阅读者快速有效地获取文章关键信息.在PDF文件中,对文章的不同文本,关键词.句等进行不同颜色的文本高亮操作,可以使阅读者在阅读过程中有效地区分不同高亮颜色文本的意义.在下面的示例中,我 ...
- java itext替换PDF中的文本
itext没有提供直接替换PDF文本的接口,我们可以通过在原有的文本区域覆盖一个遮挡层,再在上面加上文本来实现. 所需jar包: 1.先在PDF需要替换的位置覆盖一个白色遮挡层(颜色可根据PDF文字背 ...
- 使用itext直接替换PDF中的文本
直接说问题,itext没有直接提供替换PDF中文本的接口(查看资料得到的结论是PDF不支持这种操作),不过存在解决思路:在需要替换的文本上覆盖新的文本.按照这个思路我们需要解决以下几个问题: itex ...
- C# 设置或验证 PDF中的文本域格式
概述 PDF中的文本域可以通过设置不同格式,用于显示数字.货币.日期.时间.邮政编码.电话号码和社保号等等.Adobe Acrobat提供了许多固定的JavaScripts用来设置和验证文本域的格式, ...
- 用python解析pdf中的文本与表格【pdfplumber的安装与使用】
我们接触到的很多文档资料都是以pdf格式存在的,比如:论文,技术文档,标准文件,书籍等.pdf格式使得用机器从中提取信息格外困难. 为了解决这个问题,我找到了几种解决方案,最后选择了python上的p ...
- (转)原始图像数据和PDF中的图像数据
比较原始图像数据和PDF中的图像数据,结果见表1.1.表1.1中各种“解码器”的解释见本文后续的“PDF支持的图像格式”部分,“PDF中的图像数据”各栏中的数据来自开源的PdfView.如果您有兴趣查 ...
随机推荐
- ASP.net之HttpModel
HttpModule是向实现类提供模块初始化和处置事件.当一个HTTP请求到达HttpModule时,整个ASP.NET Framework系统还并没有对这个HTTP请求做任何处理,也就是说此时对于H ...
- 三、Jmeter--HTTP请求默认值(HTTP Request Defaults)和访问地址参数化
一.HTTP请求默认值(HTTP Request Defaults) 1. 在本地搭建了一个wordpress开源论坛,那么我每次访问论坛的地址(服务器名称或IP)是不变的,端口也是不变的,协议也是不 ...
- MySQL的瑞士军刀(转)
这里主要讲mysql运维中的一些主要工具,这些工具可能大家都用过,特别是系统管理员或者做linux服务器维护的同学可能都知道这些小工具,这 里讲得会比较多一些,除了系统监控的小工具,还包括一些mysq ...
- spring mybatis 多个数据源配置
mybatis生成器:http://blog.csdn.net/tolcf/article/details/50835165 通过命令生成:java -jar mybatis-generator-co ...
- Spring Boot自定义配置与加载
Spring Boot自定义配置与加载 application.properties主要用来配置数据库连接.日志相关配置等.除了这些配置内容之外,还可以自定义一些配置项,如: my.config.ms ...
- 很详细的Nginx配置说明
这篇文章主要为大家分享了一篇很详细的Nginx配置说明,主要内容包括Nginx常用功能.Nginx配置文件结构,想要了解Nginx配置的朋友不要错过,参考一下 Nginx是lgor Sysoev为 ...
- Stun方式的P2P实现原理(转)
转帖地址:http://www.cppblog.com/peakflys/archive/2013/01/25/197562.html 二.STUN方式的P2P实现 STUN是RFC3489规定的 ...
- JAVA基础知识总结13(同步)
好处:解决了线程安全问题. 弊端:相对降低性能,因为判断锁需要消耗资源,还容易产生了死锁. 定义同步是有前提的: 1,必须要有两个或者两个以上的线程,才需要同步. 2,多个线程必须保证使用的是同一个锁 ...
- 为Docker镜像添加SSH服务
一.基于commit命令创建 1. 首先下载镜像 $ docker run -it ubuntu:16.04 /bin/bash 2. 安装SSH服务 #更新apt缓存 root@5ef1d31632 ...
- mt_rand()函数、str_shuffle() 函数、join() 函数
mt_rand() 使用 Mersenne Twister 算法返回随机整数. 语法 mt_rand(min,max) 定义和用法 str_shuffle() 函数随机地打乱字符串中的所有字符. 语法 ...