引言
文档的页面显示和打印效果一直是困扰人们的一个大问题。虽然我们可以在一种程序中打开其它程序的输出文档,但是显示效果往往大相径庭。即使使用同一种软件,如果操作平台或打印机不同的话,实际的显示或打印结果也常常事与愿违。
Adobe公司最早意识到上述问题,并为此专门开发出PDF文档格式。PDF的全称为Portable Document Format,即可移植文档格式,由广泛应用于专业打印领域的Postscript解释语言演化而来。为了使PDF迅速得到推广,Adobe不仅公开了技术规范,而且还免费向用户提供可以显示和打印PDF文件的Adobe Acrobat应用软件。
PDF最大的优势就在于其良好的一致性。PDF文档一旦创建之后,无论是在任何系统或打印设备上,都可以完好的保持最初的页面设计样式和风格,不会发生任何变化。正是由于PDF文档在格式上的一贯性,使得越来越多的网站开始提供基于PDF格式的文件和说明,从简单的宣传手册到完整的电子图书,PDF越来越受到人们的喜爱和重视。
事实上,除了可以用于静态信息显示之外,我们还可以通过WEB脚本程序直接直接以PDF文档形式输出,不再仅仅局限于传统的HTML页面。
举例来说,我们使用PERL脚本基于数据库信息生成了一份库存商品报告。现在,我们希望将该报告打印出来同时将可打印版本发送给其他100名相关人员。这时,如果我们能够直接生成PDF文档,并将PDF格式的报告发送给其他人员打印的话,要比试图直接通过浏览器打印HTML页面简单和有效得多。因为如果采用后一种方式,我们将无法确保每个人实际得到的打印页面的效果到底如何。
再例如,现在许多的新闻或信息站点都提供用户打印相关内容或页面的功能。这时,如果我们能够提供基于PDF格式的文档打印,就可以保证最终输出的文档能够保持原有的格式,不会出现断行或分页等的问题,既方便了用户,又提高了网站的综合质量。
实现基础
从前文中,我们可以看出PDF文档在网站中的重要作用。不过,使用PERL脚本直接生成PDF文件仍然有几个问题需要解决。
首先,要求用户熟悉PDF技术规范。现有的一些PERL模块虽然也可以生成PDF数据流,但是要求使用者对PDF文档的结构组成有一定程度的了解。以Text::PDF(说明见:http://search.cpan.org/doc OSKEN/Text-PDF-0.12/readme.txt)和PDF::Create(说明见:http://search.cpan.org/doc/FTASSIN/PDF-Create-0.01/README)为例,如果用户熟悉PDF技术,可以非常灵活的使用这两个模块生成PDF输出。但是,如果用户不了解或者不希望掌握PDF技术的话,使用起来就会有一定的困难。此外,上述两个模块还存在一定的局限,例如PDF::Create无法在所生成的PDF文档中包含图片等。
PDFLib是另外一种可供选择的方案。除了可以直接产生PDF输出之外,还自带了一个PERL接口。虽然PDFLib的功能非常全面,但是作为一种商业软件其售价是广大个人用户所无法承受的,而且,使用PDFLib同样需要对PDF技术有一定的了解。
事实上,相信绝大多数希望在自己的网站中增添PDF支持功能的用户对PDF技术本身都不会有太大的兴趣。如果能够有一种更简单,更直接的实现方式就好了。
可以很高兴的告诉大家,本文将要向大家介绍的HTMLDOC完全可以满足这一要求。作为免费软件产品提供的HTMLDOC事实上就是一种HTML语言的转化工具,可以直接把HTML代码按照用户的需求转换为Postscript或者PDF格式。除了具有图形化接口之外,HTMLDOC还专门集成了一个命令行接口,允许用户在PERL脚本中进行调用,从而使整个PDF的生成过程一气呵成。
首先,我们需要安装HTMLDOC(网址:http://www.easysw.com/htmldoc/)。目前,HTMLDOC可以在包括Linux, Solaris, 以及Windows等在内的多种平台上使用。安装过程很简单,具体的安装指令可以参见http://www.easysw.com/htmldoc/htmldoc.html#2_1_4 处的文档说明。
如果用户准备在Linux平台上安装HTMLDOC的话,有两点需要注意。
1. 下载文件htmldoc-1.version-platform.tar.gz中没有包含目录信息,因此用户在安装前需要首先创建一个子目录,然后把下载文件移到该目录中再进行解压。
2. 如果用户使用telnet登录到远程机器进行安装,由于setup例程需要在X窗口环境下运行,所以无法使用。不过,我们可以运行安装文件中的htmldoc.install脚本程序进行安装。命令如下:
prompt$#@62; cd htmldoc-install
prompt$#@62; ./htmldoc.install
安装过程结束之后,可以使用以下命令进行测试:
prompt$#@62; echo "test" | htmldoc --webpage -t pdf ?
如果安装正确,屏幕上将会显示出一系列文字。具体含义我们不需要知道,只要能够证明HTMLDOC可以正常运行并产生输出就可以了。
使用说明
我们在前文中曾经提到过,HTMLDOC实际上就是一种HTML和PDF之间的转换工具。在命令行中,我们可以使用管道将HTML代码传送给HTMLDOC,然后指定HTMLDOC以标准的格式输出结果。
举例来说,我们可以使用以下命令将一个简单的WEB页面转化为PDF格式:
prompt$#@62;echo"$#@60;H2$#@62;Results$#@60;/H2$#@62;$#@60;TABLE$#@62;$#@60;TR$#@62;$#@60;TD$#@62;Score$#@60;/TD$#@62
;$#@60;TD$#@62;95$#@60;/TD$#@62;$#@60;/TR$#@62;
$#@60;/TABLE$#@62;" | htmldoc --webpage -t pdf - $#@62; resultTable.pdf
说明:
在上述命令中,我们首先使用echo命令输出一段标准的HTML代码,然后通过管道操作符“|”将其以WEB页面的形式传递给HTMLDOC,由后者产生PDF输出,并把结果保存在resultTable.pdf文件中。如果在Adobe Acrobat中打开resultTable.pdf文件,就会看到以下输出:
使用PERL产生PDF输出
为了更好的说明如何将HTMLDOC集成到Perl CGI脚本中,我们假设在WEB服务端编写了一个PERL脚本,可以接收从客户端传来的名为innerHTML的参数(innerHTML可以是一个表单域),然后将innerHTML转化成PDF文件再传回用户端的浏览器。
我们可以把处理后传回的数据流的MIME类型设定为application/pdf。这样,如果用户在客户端安装了Adobe Acrobat阅读程序,浏览器就可以根据接收信息的MIME类型启动Adobe Acrobat。否则,浏览器将会询问用户以何种方式打开该文件或者选择是否保存该文件。
本例所述程序的客户端界面可以如下:
当用户在表单中输入HTML代码之后,点击“Download PDF”键,数据上传到服务端,经过HTMLDOC转化后传回,并最终以PDF格式显示。显示结果可以如下:
在对程序的输入和输出有所了解之后,我们就来看一下到底如何将PERL和HTMLDOC结合起来,实现以上功能。
具体代码如下:
#!/usr/bin/perl
#使用HTMLDOC产生PDF输入
use CGI;
#获取CGI参数
my $cgiobj=new CGI;
my $innerHTML=$cgiobj-$#@62;param("innerHTML");
#处理输入数据中各种可能出现的特殊字符
my %specialChars=(
"’","′",
"\$","\\\$",
"\@","\\\@",
"\!","\\\!",
"\n","",
"\r","");
my $specialCharList=join("",keys %specialChars);
$innerHTML=~s/\\/\\\\\\\\/g;
$innerHTML=~s/([$specialCharList])/$specialChars{$1}/g;
#向浏览器输出PDF标头
print "Content-Type: application/pdf\r\n\r\n";
#创建并向浏览器输出PDF数据流
if ($innerHTML) {
my $command="`echo -e ’".$innerHTML."’ | htmldoc --webpage -t pdf - `";
print eval($command);
}
说明:
在脚本程序的开始,我们首先从CGI环境下接收由客户端传来的输入信息,并保存在innerHTML参数中。用户也可以将该脚本设计成能够接收其它程序输出的HTML代码,而不必非要从客户端或外界输入。
无论我们是以何种方式获取HMTL代码,都需要对其中所包含的可能引发运行错误的特殊字符进行处理。这里,我? 要是通过建立一个哈希表来查找和替换特殊字符。有关PERL中的哈希表以及字符运算的知识我们在这里就不进行详细的说明了,感兴趣的朋友可以参见“学习中心”的相关文章。
在完成对HTML代码的处理之后,我们把数据的MIME类型设置为application/pdf。这样,位于客户端的浏览器在接收到数据之后就知道应该以何种方式对其进行处理。
因为HTMLDOC是一种外部程序,所以我们需要对其进行系统调用。相关命令我们在前文已经进行过介绍,在这里就不重复了。需要提醒大家注意的一点就是使用PERL进行系统调用时,必须将命令包含在“`”符号内。PERL中的eval()函数可以把字符串解释成为PERL代码,这样,$command变量所包含的系统调用命令就可以被执行,最终的PDF数据将会被直接传送到客户端的浏览器。
最后还有一点需要说明,因为每一个页面只能传送一次HTTP标头,所以标头application/pdf必须被放在输出数据的第一行。
小结
对于那些已经在使用PERL脚本生成动态HTML页面的网站来说,借助于外部程序HTMLDOC可以非常方便的实现PDF输出功能,根本不需要对现有程序进行任何大的改动,简单,快速,方便。
虽然在PERL脚本中调用外部HTMLDOC程序从技术和性能角度来说并不一定是一种最佳的选择,但是,对于那些希望丰富网站功能,向用户提供更加友好的访问界面的朋友来说,HTMLDOC还是具有相当大的吸引力的。