iText vs FOP - Java動態生成PDF的兩個選擇
Posted on 2008-10-05 23:28 laogao 閱讀(13769) 評論(11) 編輯 收藏 所屬分類: On Java由于工作需要,今天簡單的看了一下Java生成PDF的相關資料。綜合看下來,除了使用報表平臺和OOo的附帶工具,目前使用較為普遍的有兩個途徑:iText和Apache的FOP。從實際出發,我們分別看看兩者處理帶有中文的PDF的具體用法吧。
[iText] (link)
iText我想大概不少人都有所耳聞,JasperReports默認的PDF支持就來自這個軟件包,它處理速度快,支持很多PDF"高級"特性,如:Annotations、AcroForms、數字簽名、加密等,支持對已有PDF的處理,通過iTextAsian.jar和iTextAsianCmaps.jar,它對中文的支持也不錯。缺點是較為依賴Java代碼,需要學習不少的專有API,當輸入/輸出格式有變化時,需要修改代碼(除非手工寫一些wrapper),不夠靈活。目前的版本是2.1.3。具體代碼:
Formatter.java
?1?import?java.io.FileOutputStream;
?2?
?3?import?com.lowagie.text.Document;
?4?import?com.lowagie.text.Font;
?5?import?com.lowagie.text.PageSize;
?6?import?com.lowagie.text.Paragraph;
?7?import?com.lowagie.text.pdf.BaseFont;
?8?import?com.lowagie.text.pdf.PdfWriter;
?9?
10?public?class?Formatter?{
11?
12?????public?static?void?main(String[]?args)?throws?Exception?{
13?????????Document?document?=?new?Document(PageSize.A4);
14?????????try?{
15?????????????System.out.print("Generating?PDF
");
16?????????????PdfWriter.getInstance(document,?new?FileOutputStream("test.pdf"));
17?????????????document.open();
18?????????????//iText自帶的中文字體
19?????????????BaseFont?bf1?=?BaseFont.createFont("STSong-Light",?"UniGB-UCS2-H",?BaseFont.NOT_EMBEDDED);
20?????????????//自定義字體
21?????????????BaseFont?bf2?=?BaseFont.createFont("wqy-zenhei.ttf",?BaseFont.IDENTITY_H,?BaseFont.NOT_EMBEDDED);
22?????????????Font?font?=?new?Font(bf2,?12,?Font.NORMAL);
23?????????????Paragraph?p?=?new?Paragraph("測試abc中文123",?font);
24?????????????document.add(p);
25?????????????System.out.println("Done.");
26?????????}?finally?{
27?????????????document.close();
28?????????}
29?????}
30?
31?}
?2?
?3?import?com.lowagie.text.Document;
?4?import?com.lowagie.text.Font;
?5?import?com.lowagie.text.PageSize;
?6?import?com.lowagie.text.Paragraph;
?7?import?com.lowagie.text.pdf.BaseFont;
?8?import?com.lowagie.text.pdf.PdfWriter;
?9?
10?public?class?Formatter?{
11?
12?????public?static?void?main(String[]?args)?throws?Exception?{
13?????????Document?document?=?new?Document(PageSize.A4);
14?????????try?{
15?????????????System.out.print("Generating?PDF

16?????????????PdfWriter.getInstance(document,?new?FileOutputStream("test.pdf"));
17?????????????document.open();
18?????????????//iText自帶的中文字體
19?????????????BaseFont?bf1?=?BaseFont.createFont("STSong-Light",?"UniGB-UCS2-H",?BaseFont.NOT_EMBEDDED);
20?????????????//自定義字體
21?????????????BaseFont?bf2?=?BaseFont.createFont("wqy-zenhei.ttf",?BaseFont.IDENTITY_H,?BaseFont.NOT_EMBEDDED);
22?????????????Font?font?=?new?Font(bf2,?12,?Font.NORMAL);
23?????????????Paragraph?p?=?new?Paragraph("測試abc中文123",?font);
24?????????????document.add(p);
25?????????????System.out.println("Done.");
26?????????}?finally?{
27?????????????document.close();
28?????????}
29?????}
30?
31?}
效果:

中文支持有默認的STSong-Light等字體,但為了優化輸出效果,這里使用了文泉驛正黑字體。如果不指定中文字體,默認情況下中文字符不會顯示。
[FOP] (link)
FOP出自Apache,在各大Java網站、論壇出現相對較低,我也是從DocBook這條線摸進來的,DocBook主要提供了一個現成的、符合一般技術書籍要求的數據結構,而展現效果(如PDF),則是通過預定義好的XSL-FO來實現的。XSL-FO是W3C的標準,正式的名稱是XSL,是XSL相關的三大組件/語言中的一個,另外兩個是XSLT和XPath。Apache的FOP是處理FO的眾多proecessor之一,相比iText,支持的輸出格式更多,對W3C相關標準支持度高,格式定義可以完全脫離具體的Java代碼,十分靈活,且控制力很強。缺點是大數據量時性能較差,默認中文支持不好。目前的版本是0.95。具體代碼:
test.xml
?1?<?xml?version="1.0"?encoding="UTF-8"?>
?2?<source>
?3?????<title>
?4?????????FOP?Sample
?5?????</title>
?6?????<paragraph>
?7?????????測試abc中文123
?8?????</paragraph>
?9?</source>
?2?<source>
?3?????<title>
?4?????????FOP?Sample
?5?????</title>
?6?????<paragraph>
?7?????????測試abc中文123
?8?????</paragraph>
?9?</source>
test.xsl
?1?<?xml?version="1.0"?encoding="UTF-8"?>
?2?<xsl:transform?version="1.0"
?3?????xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
?4?????xmlns:fo="http://www.w3.org/1999/XSL/Format">
?5?
?6?<xsl:template?match="/">
?7?????<fo:root>
?8???????<fo:layout-master-set>
?9?????????<fo:simple-page-master?master-name="A4-portrait"
10???????????????page-height="29.7cm"?page-width="21.0cm"?margin="2cm">
11???????????<fo:region-body/>
12?????????</fo:simple-page-master>
13???????</fo:layout-master-set>
14???????<fo:page-sequence?master-reference="A4-portrait">
15?????????<fo:flow?flow-name="xsl-region-body">
16???????????<fo:block?font-family="WenQuanYi?Zen?Hei"?font-size="24pt">
17?????????????<xsl:value-of?select="source/title"/>
18???????????</fo:block>
19???????????<fo:block?font-family="WenQuanYi?Zen?Hei"?text-indent="1cm">
20?????????????<xsl:value-of?select="source/paragraph"/>
21???????????</fo:block>
22?????????</fo:flow>
23???????</fo:page-sequence>
24?????</fo:root>
25?</xsl:template>
26?
27?</xsl:transform>
?2?<xsl:transform?version="1.0"
?3?????xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
?4?????xmlns:fo="http://www.w3.org/1999/XSL/Format">
?5?
?6?<xsl:template?match="/">
?7?????<fo:root>
?8???????<fo:layout-master-set>
?9?????????<fo:simple-page-master?master-name="A4-portrait"
10???????????????page-height="29.7cm"?page-width="21.0cm"?margin="2cm">
11???????????<fo:region-body/>
12?????????</fo:simple-page-master>
13???????</fo:layout-master-set>
14???????<fo:page-sequence?master-reference="A4-portrait">
15?????????<fo:flow?flow-name="xsl-region-body">
16???????????<fo:block?font-family="WenQuanYi?Zen?Hei"?font-size="24pt">
17?????????????<xsl:value-of?select="source/title"/>
18???????????</fo:block>
19???????????<fo:block?font-family="WenQuanYi?Zen?Hei"?text-indent="1cm">
20?????????????<xsl:value-of?select="source/paragraph"/>
21???????????</fo:block>
22?????????</fo:flow>
23???????</fo:page-sequence>
24?????</fo:root>
25?</xsl:template>
26?
27?</xsl:transform>
fop-config.xml
?1?<?xml?version="1.0"?>
?2?<fop?version="1.0">
?3???<base>.</base>
?4???<source-resolution>72</source-resolution>
?5???<target-resolution>72</target-resolution>
?6???<default-page-settings?height="29.7cm"?width="21.0cm"/>
?7???<renderers>
?8?????<renderer?mime="application/pdf">
?9???????<filterList>
10??????????<value>flate</value>
11??????</filterList>
12???????<fonts>??
13?????????<directory>.</directory>
14?????????<auto-detect/>
15???????</fonts>
16?????</renderer>
17???</renderers>
18?</fop>
?2?<fop?version="1.0">
?3???<base>.</base>
?4???<source-resolution>72</source-resolution>
?5???<target-resolution>72</target-resolution>
?6???<default-page-settings?height="29.7cm"?width="21.0cm"/>
?7???<renderers>
?8?????<renderer?mime="application/pdf">
?9???????<filterList>
10??????????<value>flate</value>
11??????</filterList>
12???????<fonts>??
13?????????<directory>.</directory>
14?????????<auto-detect/>
15???????</fonts>
16?????</renderer>
17???</renderers>
18?</fop>
Formatter.java
?1?import?java.io.File;
?2?import?java.io.FileOutputStream;
?3?import?java.io.OutputStream;
?4?
?5?import?javax.xml.transform.Result;
?6?import?javax.xml.transform.Source;
?7?import?javax.xml.transform.Transformer;
?8?import?javax.xml.transform.TransformerFactory;
?9?import?javax.xml.transform.sax.SAXResult;
10?import?javax.xml.transform.stream.StreamSource;
11?
12?import?org.apache.fop.apps.FOUserAgent;
13?import?org.apache.fop.apps.Fop;
14?import?org.apache.fop.apps.FopFactory;
15?import?org.apache.fop.apps.MimeConstants;
16?
17?public?class?Formatter?{
18?
19?????public?static?void?main(String[]?args)?throws?Exception?{
20?????????File?source?=?new?File("test.xml");
21?????????File?specs?=?new?File("test.xsl");
22?????????File?target?=?new?File("test.pdf");
23?????????FopFactory?fopFactory?=?FopFactory.newInstance();
24?????????fopFactory.setUserConfig("fop-config.xml");?//?讀取自定義配置
25?????????FOUserAgent?foUserAgent?=?fopFactory.newFOUserAgent();
26?????????OutputStream?out?=?new?FileOutputStream(target);
27?????????out?=?new?java.io.BufferedOutputStream(out);
28?????????try?{
29?????????????System.out.print("Generating?PDF
");
30?????????????Fop?fop?=?fopFactory.newFop(MimeConstants.MIME_PDF,?foUserAgent,?out);
31?????????????TransformerFactory?factory?=?TransformerFactory.newInstance();
32?????????????Transformer?transformer?=?factory.newTransformer(new?StreamSource(specs));
33?????????????Source?src?=?new?StreamSource(source);
34?????????????Result?res?=?new?SAXResult(fop.getDefaultHandler());
35?????????????transformer.transform(src,?res);
36?????????????System.out.println("Done.");
37?????????}?finally?{
38?????????????out.close();
39?????????}
40?????}
41?
42?}
?2?import?java.io.FileOutputStream;
?3?import?java.io.OutputStream;
?4?
?5?import?javax.xml.transform.Result;
?6?import?javax.xml.transform.Source;
?7?import?javax.xml.transform.Transformer;
?8?import?javax.xml.transform.TransformerFactory;
?9?import?javax.xml.transform.sax.SAXResult;
10?import?javax.xml.transform.stream.StreamSource;
11?
12?import?org.apache.fop.apps.FOUserAgent;
13?import?org.apache.fop.apps.Fop;
14?import?org.apache.fop.apps.FopFactory;
15?import?org.apache.fop.apps.MimeConstants;
16?
17?public?class?Formatter?{
18?
19?????public?static?void?main(String[]?args)?throws?Exception?{
20?????????File?source?=?new?File("test.xml");
21?????????File?specs?=?new?File("test.xsl");
22?????????File?target?=?new?File("test.pdf");
23?????????FopFactory?fopFactory?=?FopFactory.newInstance();
24?????????fopFactory.setUserConfig("fop-config.xml");?//?讀取自定義配置
25?????????FOUserAgent?foUserAgent?=?fopFactory.newFOUserAgent();
26?????????OutputStream?out?=?new?FileOutputStream(target);
27?????????out?=?new?java.io.BufferedOutputStream(out);
28?????????try?{
29?????????????System.out.print("Generating?PDF

30?????????????Fop?fop?=?fopFactory.newFop(MimeConstants.MIME_PDF,?foUserAgent,?out);
31?????????????TransformerFactory?factory?=?TransformerFactory.newInstance();
32?????????????Transformer?transformer?=?factory.newTransformer(new?StreamSource(specs));
33?????????????Source?src?=?new?StreamSource(source);
34?????????????Result?res?=?new?SAXResult(fop.getDefaultHandler());
35?????????????transformer.transform(src,?res);
36?????????????System.out.println("Done.");
37?????????}?finally?{
38?????????????out.close();
39?????????}
40?????}
41?
42?}
效果:

FOP的中文支持(其實是自定義字體支持),在0.94版本之前,十分有限,對每一個需要使用的TrueType字體,都需要生成一個metrics文件,在0.94和之后的版本,則沒有這個要求,且可以自動掃描系統字體和指定文件夾中的TTF字體。如果不配置中文字體,默認情況下,中文字符在PDF中將被處理成"#"。
上面的示例代碼雖然簡單,但展示了FOP真正強大的地方,那就是控制力。這里篇幅有限,不可能全部特性都一一涉及,這個簡單的例子至少可以讓我們看到從原始的XML格式的數據,通過XSLT按照自定義的規則轉換成XSL-FO,最后輸出到PDF的過程,每一步都可以在Java代碼之外進行嚴格控制。
以上是我對iText和FOP一些基本特點和用法的整理,它們各有特點,大家可以根據各自需要繼續深入研究,FOP和iText相結合也未嘗不可。希望能夠幫助到有需要的朋友。