对于几种类别的顶级质量的可显示输出来说,PDF 是公认的标准。尽管大多数程序员把它看作“桌面”技术 ― 内容专家通过“另存为”操作选择的一种格式,但是,通过服务器端 PDF 创建的自动化,您可以使文档管理处理更有效。本月,Cameron 介绍用于 PDF 管理和编程的 ReportLab 库。
您知道 PDF。当推销员想要一本看上去“井井有条”的小册子,或法律人员需要不应该更改的文档时,他们就以可移植文档格式(PDF)发布这些文档。PDF 是由 Adobe Systems 定义的标准,用于以独立于平台和设备的方式生成和显示文档。PDF 建立在 Adobe 的 PostScript(PS)的空前成功之上,后者于 1984 年首次发布,用于提高通过常用硬件可实现的打印精密度。原则上,PDF 有固定的外观,在不同的 Web 浏览器和不同的设备(包括打印机)之间保持不变;PDF 文档的内容被“锁定”。
尽管上面的陈述严格来说没有一条是正确的,但它们基本上能应付大多数用途。而且,PDF 通常很容易打印;只有纯文本文档更容易与任何特定的打印机兼容。
那与您有什么关系吗?作为系统或服务器端程序员,您可能仅仅把 PDF 看成另一种不透明的内容类型。您的桌面用户或文档专家偶尔会更新您服务器上的实例,而您就象提供任何其它文件一样提供这些文件。您会说,那就是您最大限度参与的工作。
程序化的 PDF 生成
但是,那种模型遗漏了几个处理 PDF 的有趣的服务器端可能性。当您使 PDF 的生成自动化时,您可以开始使用软件工程的所有技术:版本控制、抽象、专业质量的备份和回归测试等等。程序化的 PDF 生成意味着您能够以可管理的方式来定制可交付使用的文档。您的组织处理 PDF 的惯例可能是:让熟练掌握特定桌面字处理程序的某个人建立某种类似“邮件合并”的操作,使文档输出参数化。然而,自动化所完成的工作远不止这些。
桌面软件供应商对这一点有部分认识。有些字处理或桌面发布软件包具有脚本编制能力,这些能力至少在部分程度上涉及到 PDF。有些制作室创建 PostScript 图像,并用 Ghostscript 或类似的软件包将它们转换成 PDF。
但是,我喜爱的使 PDF 的生成自动化的方法,是使用三个被积极维护的开放源码库之一:ReportLab、PJ 和 PDFlib。它们都差不多,我已经有了使一些依靠各个库的项目取得极大成功的方法。下面的参考资料中有指向所有三个库以及几个其它工具的链接。
在这些工具中,ReportLab 是我目前用得最多的工具:它可以处理我使用的几兆字节的 PDF,它采用 Python 作为脚本语言,这很适合我,它的库包括我日常工作所需的所有功能,而且这个库背后的 ReportLab 公司看来享有持续增长的业务。此外,可以方便地将它集成到 Python 交互式 shell 中,这有利于形成一个令人愉快的高效开发环境。本月的“服务器诊所”的余下部分将举例说明如何开始对 PDF 编程。
PDF 的“Hello, world”
尽管您可能已经在服务器上有了较好的 Python 安装,但 Python.org 的下载页面可以帮助您确定是否拥有最新版本。Version 2.2.1 是很好的选择。
安装了 Python 之后,在开始 PDF 编程工作以前,您需要访问 ReportLab 下载页面。即使在慢的连接上,下载并安装 Python 和 ReportLab Toolkit 最多不会超过一小时(请参阅参考资料以获得这两个下载的链接)。
您的第一个应用程序的源代码可以象下面的代码那样简单:
“Hello, world”页的源代码
from reportlab.pdfgen import canvas
from reportlab.lib.units import inch
font = "Helvetica"
font_size = 26
text = "Hello, world"
x = 5.0 * inch
y = 8.0 * inch
destination_file = "/tmp/first.pdf"
my_canvas = canvas.Canvas(destination_file)
my_canvas.setFont(font, font_size)
my_canvas.drawRightString(x, y, text)
my_canvas.save()
这段代码仅仅把标题写在一张原本空白的纸上。尽管普通,但它暗示了新的应用领域:字体样式和大小、内容及格式都是可编程的。当您的组织决定以 Times New Roman 而不是 Helvetica 发布时,原则上,您可以更改一个配置赋值,然后重新生成所有内容,而不必逐个打开数千个文档,改变它们,然后把它们写回文档。对于其它效果也是一样:例如,如果您希望把针对老年读者的信息的字体扩大,应用程序可以自动完成这一点。
不过,不要认为您必须开发自己的字处理程序才能完成任何有意义的工作。虽然 ReportLab 库有足够的广度和深度允许这么做,但它也支持几个特定的快捷方式,它们极大地简化了我的 PDF 编程。首先是 import_HTML 方法。它将有效的 HTML 源代码转变成 PDF 页。我发现,对于许多应用程序,可以较方便地以 HTML 格式制作原型,获取样本文档的“客户签字(stakeholder sign-off)”,将 HTML 生成参数化,然后用下面的方法完成实现:
my_document.import_HTML(my_html_source)
这给了我非常快速、易于维护、完全程序化的方法来将内容注入 PDF。ReportLab 的处理效率非常高,以至于我可以轻松地实时生成用于 Web 显示的所有种类的 PDF 文档。这使得我能够在保持适当的视觉外观的同时,使关键的金融或工程报表与最新数据完全保持同步。当然,印刷文档享用了同样的定制选项。
合并 PDF 文档
第二个关键的库函数是 copyPages。它将现有的 PDF 文档附加到一个 Canvas 实例。copyPages 很方便地把几个 PDF 文档连接起来形成一个 PDF 文档。
对于大多数复杂效果,象其它的 PDF 工具供应商一样,ReportLab 发放付费产品许可证。在 ReportLab 的情况中,它的 PageCatcher 产品注释现有的 PDF 文档、重新安排它们的页、并针对不同的打印方法重新格式化、添加背景(包括水印)以及填充 PDF 表单。ReportLab 记录了几个有趣的 PageCatcher 用例。一个示例是对已完成的美国国税局(Internal Revenue Service (IRS))表单的程序化的预处理。
我发现的 ReportLab 的最后一个重要能力是其目录(Tables of Contents)管理。在线文档读者觉得这些导航辅助手段很重要,Adobe 称其为“书签(bookmark)”或“大纲(outline)”。大多数 PDF 查看器将它们显示为左边窗口中的菜单。ReportLab Reference 本身就是书签式文档的好例子。诸如 copyPages 之类的 ReportLab 函数包括了将大纲正确导入到较大的文档的选项或废弃大纲的选项。
结束语
每当计算作业似乎有些单调乏味或容易出错时 ― 例如,“手工”更新文档 ― 您就应该寻找使该过程自动化的方法。如果您不能肯定这种态度能带您走多远,请回过头参阅我对 Limoncelli 和 Hogan 所著书籍的评论(“服务器诊所”,2002 年 5 月)。两位作者甚至将他们书籍的草稿构造成 make 进程的输出。尽管许多系统程序员似乎没有意识到这一点,但 PDF 文档的管理为自动化和抽象提供了大量机会。使用 ReportLab 库或其它可用的支持 PDF 的工具来教服务器做您的 PDF 工作。那样应该可以让您把时间投入到更有价值的研究中。