本文转自http://www.blogjava.net/sean/archive/2008/10/05/232577.html由于工作需要,今天简单的看了一下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 } 效果: 中文支持有默认的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 > 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 > 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 > 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 } 效果: FOP 的中文支持(其实是自定义字体支持),在0.94版本之前,十分有限,对每一个需要使用的TrueType字体,都需要生成一个metrics文件,在 0.94和之后的版本,则没有这个要求,且可以自动扫描系统字体和指定文件夹中的TTF字体。如果不配置中文字体,默认情况下,中文字符在PDF中将被处 理成"#"。 上面的示例代码虽然简单,但展示了FOP真正强大的地方,那就是控制力。这里篇幅有限,不可能全部特性都一一涉及,这个简单 的例子至少可以让我们看到从原始的XML格式的数据,通过XSLT按照自定义的规则转换成XSL-FO,最后输出到PDF的过程,每一步都可以在Java 代码之外进行严格控制。 以上是我对iText和FOP一些基本特点和用法的整理,它们各有特点,大家可以根据各自需要继续深入研究,FOP和iText相结合也未尝不可。希望能够帮助到有需要的朋友。