95

PDF开发+电子签章,如何实现真正地脱离硬件的无纸化办公体验(实战篇)? - 恒生技术...

 6 years ago
source link: http://rdc.hundsun.com/portal/article/837.html?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

PDF开发+电子签章,如何实现真正地脱离硬件的无纸化办公体验(实战篇)?

上一篇中我们主要介绍了PDF的一些基本格式,让大家入门有一个初步的了解,接下来我们进行PDF的开发和电子签章的实战。

【PDF文档修改】

上篇文章中了解了PDF的基本格式,我们要实现无纸化办公,势必要修改现有的PDF文档,往里面填写具体的数据。那如果我们要对去解析修改PDF的具体内容,那只有上面的基本了解,是远远不够的,就算借助第三方开发包要去解析修改,也是一个庞大复杂的工程。那我们怎么样可以最方便快捷的实现对PDF文档的修改呢?

这里我们可以借助PDF自身的特性,因为它是由很多对象组成的结构化的格式,所以我们不需要去解析现有的数据内容,只要往里面增加一个新的数据对象就可以,至于排版描述信息,也是现成支持的可覆盖模式。简单的说就是增加一个对象,告诉它排版位置,来覆盖原来的内容就可以达到我们的目的。当然还是要借助开源的第三方开发包来实现,可以更加的方便,现在比较成功的开源免费的开发包有itext和PDFbox,基本功能大概都可以实现,这里我们选取itext来使用和说明。

Itext有java和C#版,本文档说明都使用java版,以下用到的功能已经在研发中心的SDK中都已实现,包括java和C#版的。

根据上面的思路,我们会碰到和需要解决的几个问题如下:

1、找到区域先覆盖白色背景色

f_4d36b5045309caffb4cb5e5c08cb28f6.png

为了让我们的修改不至于和原来的内容一起显示出来,造成混杂难看的效果,所以我们在覆盖新内容之前,先对修改区域内做一层白色背景色的覆盖,以确保我们填充的内容可以正常清晰的显示。

那如何简单方便的可视化的确定我们要填充覆盖的区域。最简单的方法就是我们打开现有的PDF文件,在里面直接用光标画出我们要修改填充的区域,这里涉及到屏幕视图坐标和PDF的自己的坐标系之间的转换问题需要解决。pdf页面的位置坐标,一般原点为pdf页面左下角,水平为x轴,高度为y轴,所以在屏幕上选取区域得到的坐标和PDF修改使用的坐标之间需要做对应的转换。当然在这之前,我们要先确定要修改的页码是第几页。

2、填充手写签名图片或者文字内容
新建一个段落Paragraph,往Paragraph里面设置手写签名图片,或者文字内容,再设置相应的边框属性(border),边距属性(margin)和间隙属性(padding)来调整显示效果即可。但是这里如果是图片不需要特殊处理,如果是文字内容的话,还需要涉及到换行显示的效果问题。

因为PDF的排版需求都会比较美观,所以在控制文字排版时,而如果采用简单共通的处理,在面对多种多样的情况时,势必会影响排版美观,而无法达到要求。所以很多时候我们都需要对单行文本,多行文本,左右上下对齐格式,当文本超出显示范围时,使用缩小字体加换行显示来达到更好的效果等等情况做出区分处理。

处理方式为,先做字体由大到小的循环,在循环判断本区域里能否显示得下这么多字。判断逻辑有两种,第一种为使用itext提供的函数判断如下:

f_91465b85dbe2f047c9a1bc843a2019f6.png

LayoutResult的值有FULL(填满状态),PARTIAL(部分填充状态),NOTHING(无填充状态)。这个是itext带的可以拿来判断区域填充状态的方法,使用起来比较方便,不过可能会由于itext的版本不同,它的使用方法也会发生改变。然后如果有什么特殊的格式需求的话,可能需要分情况另加处理来实现。

第二种根据字体,自己计算显示文本所需的宽度,计算字体的高度,然后再跟显示区域的宽度和高度对比,计算每一行合适的字数,填入每行的内容。这个方法可以自己控制里面更多的显示格式,但是相对来说计算起来比较复杂。主要几个地方说明一下:

f_475e2bcc7079c418dc86270b1edc05c0.png

具体的计算和处理方式,需要根据各个项目要求自己进行循环比对,和显示控制。

3、中文字体显示
PDF在支持中文显示上,需要导入中文字体库,如果没有的话,中文的地方会显示空白。在导入中文字体库上,一般有三种方法:

f_f8c1a50f1ab6758763a6b3cc9976af89.png

三种方法的优缺点如下:
▪ 第一种方法,适合Windows操作系统,如果要夸平台使用,就需要加入不同的平台判断,引入不同的路径来适配。

▪ 第二种方法,使用起来比较简单方便,导入iTextAsian.jar包就可以,不需要再去考虑其它的,不过现在iTextAsian.jar里面的宋体,不支持制表符(\t),如果有内容中有制表符(\t)的话,还是要导入Windows自带的宋体才可以解决。

▪ 第三种方法,自己带上了字体,能解决有什么特殊要求的情况,也不需要考虑系统平台相关性,不过就是发包里面需要带入字体库文件。

4、字体颜色可能的问题
在我们对原有内容进行覆盖时,需要注意的是,最好对我们填充内容的字体颜色进行显式的设置。如果我们没有显式的设置的话,itext去覆盖的时候会使用默认匹配的颜色,这样在对不同PDF文档进行填充时,可能会使用不同的颜色,如果恰好使用了白色的话,那有时候就会发生看不见文字内容的情况,因为虽然文字是填充进去了,背景和字体都使用了白色,就什么都看不见了,所以最好还是要自己显式的设置好颜色为好。

5、PDF的各种页面视图框
当我们用PDF的各种阅读器,打开一个PDF文档的时候,我们看到的页面内容,与实际文件里面包括的内容是不一样的。换句话说,也就是我们看到的只是这个PDF创建者想给我们看到的东西,其实里面还可能隐藏了很多内容,只是没显示出来。

这里涉及到几个PDF上面的视图框的概念:
▪ MediaBox:媒体框,是页面上最大的一个框,包含一个页面的全部对象,包括页面上的文本、图片和标记等。媒体框定义了页面上需要印刷的物理介质的范围,除图文内容外,还包括裁切标记、色控条等。▪ MediaBox是一个页面中最大的box。其他的box可以和它一样大,但绝不可以比它大。

▪ CropBox:裁取框,定义了页面在显示或打印出来以后,要裁取的部分。Adobe Acrobat软件使用这个来显示和打印页面。

▪ BleedBox:出血框,定义了当用于生产环境时页面内容将被裁剪到的区域。通常BleedBox比TrimBox大3到5毫米。默认情况下,BleedBox与CropBox相等。

TrimBox:成品裁切框,成品裁切框确定页面在印刷和裁切之后的最终有效尺寸。成品裁切框对应着页面的实际尺寸(成品尺寸),如果一个PDF文档包含一个裁切框,那么裁切框的尺寸与最终成品尺寸相等。

ArtBox:内容框,有点特殊。它定义了某些特殊用途的页面中的区域。它很少被程序用到。有一种情况会使用到它是在控制页面广告。如果一个页面有广告,那么ArtBox定义了广告区域的大小。

    初看到上面五个框,可能大家会疑惑,为什么要这么复杂,这就跟PDF一开始定义的作用有关,PDF是为内容的初版和发布准备的,也是为它服务的,所以里面用到很多出版印刷届的一些术语。作为程序处理,我们要知道的是,这五个框的定义会影响到我们实际看到的PDF页面的大小,自然也就会影响到位置坐标的计算。

作为电子文档来说我们需要多关注的应该是MediaBox和CropBox。MediaBox是包含整个页面所有的内容,我们程序控制位置的坐标原点,也以MediaBox的左下角为原点。但是我们通过PDF阅读器看到的页面大小,是经过CropBox裁剪后的内容,这就涉及到你眼睛看到的视图坐标和程序操作的视图坐标之间的转换计算了。之前碰到过有几个PDF文档,我们通过阅读器看到的都是几页规则的A4纸,但是实际上它中间有几页的大小可能是两张A4纸那么大,也就是他的MediaBox的大小是有两张A4纸,而通过CropBox来裁剪出一半显示出来给我们看。这种情况在我们做内容填充渲染的时候,势必要知道CropBox的具体坐标,不然我们就有可能填充到CropBox之外隐藏的内容上面,而再打开PDF上面确实什么更改都没有显示。

【PDF电子签章】

PDF电子签章的作用为,可以验证PDF在盖章后内容有没有做修改,保证内容真实性和完整性,可以验证签章人信息,保证签章人不可否认性。那它是如何做到的呢?

首先数字证书可以是一本个人或企业证书,里面包含签章人的身份信息、签章人的公钥和私钥。我们使用PDF的签章对象,将数字证书里面的身份信息设置进签章对象,然后使用签章人的私钥对PDF文档进行算法签名,再设置签章对象的显示信息为签章人的印章图片,即可实现我们想要的效果。

至于内容有无修改的验证的话,一般的PDF阅读器都可以做到,验证的功能,所以这个签章效果可以是通用的,当然它的签名算法需采用国际流行的SHA和RSA等,如果使用国密算法的话,那验签工具就也得自己实现了(PDF阅读器),因为adobe 的PDF标准里没有国密算法。

这里itext使用的签名接口主要有下面几步(itext5.5.0):

f_8b55a3f9ef3800f7459d155d823ed0ae.png

相当于先对PDF文档进行取摘要,再对摘要进行签名,这主要也是为了提高签名效率。
使用PDF阅读器打开后的验签效果如下图:

f_a4089f4c0f5304459466ef03ad53e06f.png

上面说的使用的证书都是pfx文件证书,自带签章人的私钥的证书,不过现在很多都是要求使用UsbKey来实现里面的签名过程,更安全的保护用户的私钥信息。那如果是使用UsbKey该如何实现呢?这时候我们需要实现上面的签名算法接口:

f_9bd471fe9f7bc7d14d8acd829d4cfa77.png

可以参考PrivateKeySignature类,将里面的成员变量私钥不要,然后sign()函数调用UsbKey里面的签名算法就可以。

由于签章对象显示时,印章图片的宽高格式和签章区域不一定能完美匹配,如果想对印章区域后面的内容进行覆盖的话,可以给印章区域设置背景图片来覆盖。

f_322fd033e6a3b801593fe5569fcf86e9.png

签章使用图片,为了更好的贴合现实情况,在使用前最好对印章图片进行背景色透明的处理。如果要盖多个印章,需要注意印章的名字不能重名,否则签章会失败。在多个印章的情况下,先盖的印章能够验证文档里面的内容有没有被修改,也能够知道整个PDF文档其实是被修改过,因为加了后面的签章对象。

此处使用的数字证书,如果是正式面向外部的文档,那肯定要是第三方CA发放的正式数字证书,需要花钱申请购买,每个证书都有其有效期。如果是内部资料,倒是可以使用内部认可的自签名证书。

以上几个部分结合,基本上可以实现无纸化电子文档(PDF)格式的修改,以及文档的防伪造,还能记录有谁授权同意的这个文档,这样就和实际纸质文档具有了相同的效果,随着信息化,自动化技术的提高,相信这将是办公环境升级的必经之路。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK