java(iText)工具包生成PDF

PDF操做類庫 iText 

iText是一個很是著名的可以快速產生PDF文件的Java類庫。支持文本,表格,圖形的操做,能夠方便的跟 Servlet 進行結合  css

 iText的更新變化很大,早期版本在PDF樣式上可能會有瑕疵,全部我使用的最新的5.5.6包html

1.添加Maven依賴

  itext核心包 和xmlworder字體包java

<dependency>  
    <groupId>com.itextpdf</groupId> 
    <artifactId>itextpdf</artifactId> 
    <version>5.5.6</version>
</dependency>
<dependency>
   <groupId>com.itextpdf.tool</groupId>
   <artifactId>xmlworker</artifactId>
   <version>5.5.6</version>
</dependency>

2.直接生成pdf

   很是簡單,用文字建立段落等便可,設置好字體、間距、對齊方式等等便可,弄個Hello World 的例子。ubuntu

package iText;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPHeaderCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import org.junit.Test;
import java.io.FileOutputStream;
/**
 * author wangnian
 * date 2016/4/1
 */
public class PdfDemo_1 {

    private static void create() throws Exception {

        // 建立一個文檔(默認大小A4,邊距36, 36, 36, 36)
        Document document = new Document();  
        // 設置文檔大小  
        document.setPageSize(PageSize.A4);  
        // 設置邊距,單位都是像素,換算大約1釐米=28.33像素  
        document.setMargins(50, 50, 50, 50);
        // 設置pdf生成的路徑
        FileOutputStream fileOutputStream= new FileOutputStream("D:/demo.pdf");
        // 建立writer,經過writer將文檔寫入磁盤
        PdfWriter writer = PdfWriter.getInstance(document,fileOutputStream);
        // demo
        String title = "打油詩";
        String content = "大學校園真開放,宿舍竟能打麻將。東南西北皆可碰,哪管父母心血濃。";
    
        // 定義字體  
        FontFactoryImp ffi = new FontFactoryImp();  
        // 註冊所有默認字體目錄,windows會自動找fonts文件夾的,返回值爲註冊到了多少字體  
        ffi.registerDirectories();  
        // 獲取字體,其實不用這麼麻煩,後面有簡單方法  
        Font font = ffi.getFont("宋體",BaseFont.IDENTITY_H,BaseFont.EMBEDDED, 12, Font.UNDEFINED, null);  
    
        // 打開文檔,只有打開後才能往裏面加東西  
        document.open();  
    
        // 設置做者  
        document.addAuthor("校園做者");
        // 設置建立者  
        document.addCreator("wangnian");
        // 設置主題  
        document.addSubject("測試");
        // 設置標題  
        document.addTitle("打油詩");
    
        // 增長一個段落  
        document.add(new Paragraph(title, font));  
        document.add(new Paragraph(content, font));  
        document.add(new Paragraph("\n\r", font));  
    
        // 建立表格,5列的表格  
        PdfPTable table = new PdfPTable(4);  
        table.setTotalWidth(PageSize.A4.getWidth()- 100);  
        table.setLockedWidth(true);  
        // 建立頭  
        PdfPHeaderCell header = new PdfPHeaderCell();  
        header.addElement(new Paragraph(title, font));  
        header.setColspan(4);  
        table.addCell(header);  
        // 添加內容  
        table.addCell(new Paragraph("大學校園真開放",font));
        table.addCell(new Paragraph("宿舍竟能打麻將",font));
        table.addCell(new Paragraph("東南西北皆可碰",font));
        table.addCell(new Paragraph("哪管父母心血濃",font));
    
        document.add(table);  
        // 關閉文檔,才能輸出  
        document.close();  
        writer.close();  
   }  
    @Test
   public  void test()  {
       try {
           create();
           System.out.println("生成成功");
       }catch (Exception ex){
           System.out.println("文件路徑錯誤或者權限不夠");
       }

   }
}

3.字體

   咱們項目文書字體比較特殊,好比用到了宋體(99%都這個吧)、華文仿宋(安裝office後自帶)、仿宋_GB2312等,因而就研究了一下pdf字體,網上有不少方法使用中文字體,其實5.0版之後的iText加入字體仍是很方便的。windows

package iText;
import java.io.FileOutputStream;
import com.itextpdf.text.Document;  
import com.itextpdf.text.Font;  
import com.itextpdf.text.FontFactoryImp;  
import com.itextpdf.text.Paragraph;  
import com.itextpdf.text.pdf.PdfWriter;  
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import org.junit.Test;

/** 
 * 字體 
 * 
 * author wangnian
 * date 2016/4/1
 * 
 */  
public class PdfDemo_2 {  
    
    public static void create() throws Exception {  
        Document document = new Document();  
        PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("D:/demo2.pdf"));
        String title = "涼州詞";  
        String content = "黃河遠上白雲間,一片孤城萬仞山。羌笛何必怨楊柳,春風不度玉門關。";  
        document.open();  
        document.add(new Paragraph(title, getFont("方正蘭亭黑簡體")));
        document.add(new Paragraph(content, getFont("迷你簡娃娃篆")));
        document.close();  
        writer.close();  
    }  
    
    private static Font getFont(String fontName) {  
        // xmlworker主要功能是html轉pdf用的,很是好用,也是itext官方的  
    
        // 這個是xmlworker提供的獲取字體方法,很方便,對中文支持很好  
        FontFactoryImp fp = new XMLWorkerFontProvider();
        // 註冊指定的字體目錄,默認構造方法中會註冊所有目錄,我這裏註冊了src/font目錄  
        fp.registerDirectory(PdfDemo_2.class.getClassLoader().getResource("weiruanyahei").getFile(), true);
    
        // 最好的地方是直接支持獲取中文的名字  
        return fp.getFont(fontName);  
    
        // 固然,最好的方法是本身繼承XMLWorkerFontProvider,提供一些經常使用字體,簡單方便  
    }  

    @Test
    public void test() throws Exception {
        create();
        System.out.println("生成成功");
    }  
}

     xmlworker的XMLWorkerFontProvider提供了很方便的獲取字體方法:app

     1.註冊一個文件夾,裏面有哪些字體均可以,好比我demo中的字體ide

     2.使用getFont(字體名)便可得到,不過字體名從哪來的呢測試

4.頁眉頁腳

    iText5中並無以前版本HeaderFooter對象設置頁眉和頁腳,能夠利用PdfPageEvent來完成頁眉頁腳的設置工做。字體

     PdfPageEvent提供了幾個pdf在建立時的事件,頁眉頁腳就是在每頁加載完寫入的。ui

     每一頁加個頁碼仍是很簡單的,可是總頁碼就麻煩了,iText是流模式的寫入內容,只有寫到最後,才能知道有多少頁,那麼顯示總頁數就麻煩了,不過麻煩不表明不可能。

     其實iText僅在調用釋放模板方法後纔將PdfTemplate寫入到OutputStream中,不然對象將一直保存在內存中,直到關閉文檔。

     因此咱們能夠在最後關閉文檔前,使用PdfTemplate寫入總頁碼。能夠理解成先寫個佔位符,而後統一替換。

     仍是HelloWorld例子:

package iText;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
/**
 * iText5中並無以前版本HeaderFooter對象設置頁眉和頁腳<br> 
 * 不過,能夠利用PdfPageEventHelper來完成頁眉頁腳的設置工做。<br> 
 * 就是在頁面完成但寫入內容以前觸發事件,插入頁眉、頁腳、水印等。<br> 
 * 
 * author wangnian
 * date 2016/4/1
 * 
 */  
   public class MyHeaderFooter extends PdfPageEventHelper {
    Font font = new XMLWorkerFontProvider().getFont("宋體", 12, BaseColor.RED);
    // 總頁數  
    PdfTemplate totalPage;
    // 打開文檔時,建立一個總頁數的模版  
    public void onOpenDocument(PdfWriter writer, Document document) {
        PdfContentByte cb =writer.getDirectContent();
        totalPage = cb.createTemplate(30, 16);  
    }  
    // 一頁加載完成觸發,寫入頁眉和頁腳  
    public void onEndPage(PdfWriter writer, Document document) {
        PdfPTable table = new PdfPTable(3);
        try {  
            table.setTotalWidth(PageSize.A4.getWidth() - 100);
            table.setWidths(new int[] { 24, 24, 3});  
            table.setLockedWidth(true);  
           table.getDefaultCell().setFixedHeight(-10);  
           table.getDefaultCell().setBorder(Rectangle.BOTTOM);
   
            table.addCell(new Paragraph("我是文字", font));// 能夠直接使用addCell(str),不過不能指定字體,中文沒法顯示
           table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);  
            table.addCell(new Paragraph("第" + writer.getPageNumber() + "頁/", font));  
            // 總頁數  
            PdfPCell cell = new PdfPCell(Image.getInstance(totalPage));  
            cell.setBorder(Rectangle.BOTTOM);  
            table.addCell(cell);  
            // 將頁眉寫到document中,位置能夠指定,指定到下面就是頁腳  
            table.writeSelectedRows(0, -1, 50,PageSize.A4.getHeight() - 20, writer.getDirectContent());  
        } catch (Exception de) {  
            throw new ExceptionConverter(de);  
        }  
    }  
   
    // 所有完成後,將總頁數的pdf模版寫到指定位置  
    public void onCloseDocument(PdfWriter writer,Document document) {  
        String text = "總" + (writer.getPageNumber() - 1) + "頁";  
        ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text,font), 2, 2, 0);  
    }  
}
package iText;
import java.io.FileOutputStream;
import com.itextpdf.text.BaseColor;  
import com.itextpdf.text.Document;  
import com.itextpdf.text.Element;  
import com.itextpdf.text.ExceptionConverter;  
import com.itextpdf.text.Font;  
import com.itextpdf.text.Image;  
import com.itextpdf.text.PageSize;  
import com.itextpdf.text.Paragraph;  
import com.itextpdf.text.Rectangle;  
import com.itextpdf.text.pdf.ColumnText;  
import com.itextpdf.text.pdf.PdfContentByte;  
import com.itextpdf.text.pdf.PdfPCell;  
import com.itextpdf.text.pdf.PdfPTable;  
import com.itextpdf.text.pdf.PdfPageEventHelper;  
import com.itextpdf.text.pdf.PdfTemplate;  
import com.itextpdf.text.pdf.PdfWriter;  
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import org.junit.Test;

/** 
 * 頁眉、頁腳 
 * author wangnian
 * date 2016/4/1
 */
public class PdfDemo_3 {  
   
    public static void create() throws Exception {  
        Document document = new Document(PageSize.A4, 50, 50, 50, 50);
        PdfWriter writer = PdfWriter.getInstance(document,new FileOutputStream("d:/demo3.pdf"));
   
        // 增長頁眉頁腳  
        writer.setPageEvent(new MyHeaderFooter());
   
        String title = "涼州詞";  
        String content = "黃河遠上白雲間,一片孤城萬仞山。羌笛何必怨楊柳,春風不度玉門關。";  
        document.open();  
   
        Font font = new XMLWorkerFontProvider().getFont("宋體");
        for (int i = 0; i <100; i++) {  
            document.add(new Paragraph(title, font));
            document.add(new Paragraph(content,font));  
            document.add(new Paragraph("\n"));  
        }  
        document.close();  
        writer.close();  
    }  

    @Test
    public  void test() throws Exception {
        create();
        System.out.println("生成成功");
    }  
}

5.html轉pdf

   結果還不錯,雖然能夠知足咱們的要求,可是比較複雜,動態建立一個個的表格和內容過於繁瑣,方法太粗暴了,用戶    的文檔內容或格式變化,就要修改程序了。

   先建立html,而後轉換成pdf,demo以下:

package iText;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;  
import java.io.InputStream;  
import java.io.OutputStream;  
import com.itextpdf.text.Document;  
import com.itextpdf.text.pdf.PdfWriter;  
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.junit.Test;

/** 
 * html轉pdf
 * author wangnian
 * date 2016/4/1
 * 
 */  
public class PdfDemo_4 {  
    
    public static void create() throws Exception {  
    
        // html中字體很是鬱悶  
        // 1. html中不指定字體,則默認使用英文字體,中文會不顯示。  
        // 2. html中指定的字體必須是英文名稱,如宋體:font-family:SimSun;  
        // 3. html中不能指定自定義字體,必須指定itext支持的字體,還好itext支持字體比較多,常見操做系統帶的都支持  
        // 4. 暫沒有找到如何html中支持自定義字體方法,網上都是修改源碼實現默認字體中文,也很重要  
    
        StringBuilder html = new StringBuilder();
        html.append("<html>");  
        html.append("<body style='font-size:20px;font-family:SimSun;'>");
        html.append("<table width='19cm'border='1' cellpadding='0' cellspacing='0'>");  
        html.append("<tr>");  
        html.append("<td colspan='2'>涼州詞</td>");  
        html.append("</tr>");  
        html.append("<tr>");  
        html.append("<td>黃河遠上白雲間,一片孤城萬仞山。</td>");  
        html.append("<td>羌笛何必怨楊柳,春風不度玉門關。</td>");  
        html.append("</tr>");  
        html.append("</table>");  
        html.append("</body>");  
        html.append("</html>");  
    
        InputStream is = new ByteArrayInputStream(html.toString().getBytes());
    
        OutputStream os = new FileOutputStream("D:/demo4.pdf");
        Document document = new Document();  
    
        PdfWriter writer = PdfWriter.getInstance(document,os);  
    
        document.open();  
    
        // 將html轉pdf  
        XMLWorkerHelper.getInstance().parseXHtml(writer,document, is);  
    
        document.close();  
    }  

    @Test
    public  void test() throws Exception {
        create();
        System.out.println("生成成功");
    }  
}

      此處使用了XmlWorker,XmlWorker也是iText官方的,目前和iText版本一塊兒更新,能夠講XHTML轉換成pdf,支持大部分樣式和標籤,是大部分哦,不是所有。      

  目前咱們就用的這個方式,寫好html文檔,使用時動態替換html中的標記位,而後生成pdf。    

 

 使用XHTML轉pdf要注意的地方:     

     1. html中不指定字體,則默認使用英文字體,中文會不顯示;

     2. html中指定的字體必須是英文名稱;如宋體:font-family:SimSun;正確 font-family:宋體;則錯誤,居然unicode也不行。    

     3. html中不能指定自定義字體(好比上文中的方正蘭亭黑),可是itext通常操做系統的字體都支持,若是ubuntu上沒有微軟雅 黑,能夠從windows下拷貝雅黑字體Yahei.ttf 放進來ubuntu上/usr/share/fonts/路徑。     

     4. pdf中添加圖片也很是簡單,例如:<img src='d:/1.jpg'/>,就能夠了。  

    5. XHTML不是HTML,因此任何標籤都要完整結束,好比<br>錯誤,必須<br/>才行。    

   寫一個html模版很簡單,須要對html和css熟練,調生成的樣式部分比較麻煩(好比文字多了會切掉,不切會影響總體樣式,表格線有粗有細,xmlworker不支持所有css等),通常A4紙都是釐米單位的,html中最好也使用釐米,處理簡單點。

本文地址(防爬蟲不標註來源):http://my.oschina.net/wangnian/blog/661389

相關文章
相關標籤/搜索