引言
文檔的頁面顯示和打印效果一直是困擾人們的一個大問題。雖然我們可以在一種程序中打開其它程序的輸出文檔,但是顯示效果往往大相徑庭。即使使用同一種軟件,如果操作平臺或打印機不同的話,實際的顯示或打印結果也常常事與愿違。
Adobe公司最早意識到上述問題,并為此專門開發出PDF文檔格式。PDF的全稱為Portable Document Format,即可移植文檔格式,由廣泛應用于專業打印領域的Postscript解釋語言演化而來。為了使PDF迅速得到推廣,Adobe不僅公開了技術規范,而且還免費向用戶提供可以顯示和打印PDF文件的Adobe Acrobat應用軟件。
PDF最大的優勢就在于其良好的一致性。PDF文檔一旦創建之后,無論是在任何系統或打印設備上,都可以完好的保持最初的頁面設計樣式和風格,不會發生任何變化。正是由于PDF文檔在格式上的一貫性,使得越來越多的網站開始提供基于PDF格式的文件和說明,從簡單的宣傳手冊到完整的電子圖書,PDF越來越受到人們的喜愛和重視。
事實上,除了可以用于靜態信息顯示之外,我們還可以通過WEB腳本程序直接直接以PDF文檔形式輸出,不再僅僅局限于傳統的HTML頁面。
舉例來說,我們使用PERL腳本基于數據庫信息生成了一份庫存商品報告?,F在,我們希望將該報告打印出來同時將可打印版本發送給其他100名相關人員。這時,如果我們能夠直接生成PDF文檔,并將PDF格式的報告發送給其他人員打印的話,要比試圖直接通過瀏覽器打印HTML頁面簡單和有效得多。因為如果采用后一種方式,我們將無法確保每個人實際得到的打印頁面的效果到底如何。
再例如,現在許多的新聞或信息站點都提供用戶打印相關內容或頁面的功能。這時,如果我們能夠提供基于PDF格式的文檔打印,就可以保證最終輸出的文檔能夠保持原有的格式,不會出現斷行或分頁等的問題,既方便了用戶,又提高了網站的綜合質量。
實現基礎
從前文中,我們可以看出PDF文檔在網站中的重要作用。不過,使用PERL腳本直接生成PDF文件仍然有幾個問題需要解決。
首先,要求用戶熟悉PDF技術規范?,F有的一些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還是具有相當大的吸引力的。