Java利用IText導出PDF(更新)


我很久以前寫的還是上大學的時候寫的:https://www.cnblogs.com/LUA123/p/5108007.html ,今天心血來潮決定更新一波。

看了下官網(https://itextpdf.com/en),出來個IText 7,但是這個要收費的,怎么收費我也不清楚,為了避免不必要的麻煩,還是用IText5版本玩了。

正文

首先引入依賴:(目前最新版的)

<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf.tool/xmlworker -->
<dependency>
    <groupId>com.itextpdf.tool</groupId>
    <artifactId>xmlworker</artifactId>
    <version>5.5.13.1</version>
</dependency>

示例一:HTML文件轉PDF

web.html

<div style="text-align: center"><b><span style="font-size: large">Terms and Conditions</span></b></div>
<ul>
    <li>Prices are in AED</li>
    <li>All Credit Card transactions are subject to a 3.25% processing fee</li>
    <li>In the event production is required per customer request, 50% of the entire bill will be due prior to start of production, and the balance due upon delivery.</li>
    <li>All furniture will be delivered in A+ condition. In the event that the equipment is damaged, the renter shall be liable for all repair costs to restore the equipment to its state at the beginning of the rental period.</li>
    <li>Equipment shall be utilized for the stated purpose and at the stated location only.</li>
</ul>

<ul class="chinese" style="font-family: SimSun;" >
    <li>價格以迪拉姆為單位</li>
    <li>所有信用卡交易都要支付3.25%的手續費</li>
    <li>如果客戶要求生產,則應支付全部賬單的50%</li>
    <li>在開始生產之前,以及交貨時的余額。所有家具將以+狀態交付。如果設備損壞,承租人應承擔所有維修費用,以將設備恢復至租期。</li>
    <li>設備應僅用於規定用途和規定位置。</li>
</ul>

web.css

ul li {
    color: #0ba79c;
}

.chinese li {
    color: #ccc920;
}

代碼

package com.demo.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Utilities;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.css.CssFile;
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver;
import com.itextpdf.tool.xml.html.CssAppliers;
import com.itextpdf.tool.xml.html.CssAppliersImpl;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;

/**
 * HTML轉PDF
 */
public class HTMLAndPDF {
    public static final String PDF = "pdf/web.pdf";
    public static final String PDF2 = "pdf/web2.pdf";
    public static final String PDF3 = "pdf/web3.pdf";
    public static final String PDF4 = "pdf/web4.pdf";
    public static final String HTML = "pdf/web.html";
    public static final String CSS = "pdf/web.css";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(PDF);
        file.getParentFile().mkdirs();
        new HTMLAndPDF().createPdf(PDF);

        file = new File(PDF2);
        file.getParentFile().mkdirs();
        new HTMLAndPDF().createPdf2(PDF2);

        file = new File(PDF3);
        file.getParentFile().mkdirs();
        new HTMLAndPDF().createPdf3(PDF3);

        file = new File(PDF4);
        file.getParentFile().mkdirs();
        new HTMLAndPDF().createPdf4(PDF4);

    }

    /**
     * 原封不動轉換
     * @param file
     * @throws IOException
     * @throws DocumentException
     */
    public void createPdf(String file) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
        writer.setInitialLeading(12);
        // step 3
        document.open();
        // step 4
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new FileInputStream(HTML), Charset.forName("UTF-8"));
        // step 5
        document.close();
    }

    /**
     * 引入額外的css
     * @param file
     * @throws IOException
     * @throws DocumentException
     */
    public void createPdf2(String file) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
        writer.setInitialLeading(12);
        // step 3
        document.open();
        // step 4
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new FileInputStream(HTML));

        String html = Utilities.readFileToString(HTML);
        String css = "ul { list-style: disc } li { padding: 10px }";
        PdfPTable table = new PdfPTable(1);
        table.setSpacingBefore(20);
        PdfPCell cell = new PdfPCell();
        for (Element e : XMLWorkerHelper.parseToElementList(html, css)) {
            cell.addElement(e);
        }
        table.addCell(cell);
        document.add(table);
        // step 5
        document.close();
    }

    /**
     * 引入外部css
     * @param file
     * @throws IOException
     * @throws DocumentException
     */
    public void createPdf3(String file) throws IOException, DocumentException {
        // step 1
        Document document = new Document();

        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
        writer.setInitialLeading(12.5f);

        // step 3
        document.open();

        // step 4

        // CSS
        CSSResolver cssResolver = new StyleAttrCSSResolver();
        CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream(CSS));
        cssResolver.addCss(cssFile);

        // HTML
        HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
        htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());

        // Pipelines
        PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
        HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
        CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

        // XML Worker
        XMLWorker worker = new XMLWorker(css, true);
        XMLParser p = new XMLParser(worker);
        p.parse(new FileInputStream(HTML));

        // step 5
        document.close();
    }

    /**
     * 處理中文(引入外部字體文件)
     * @param file
     * @throws IOException
     * @throws DocumentException
     */
    public void createPdf4(String file) throws IOException, DocumentException {
        // step 1
        Document document = new Document();

        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
        writer.setInitialLeading(12.5f);

        // step 3
        document.open();

        // step 4

        // CSS
        CSSResolver cssResolver = new StyleAttrCSSResolver();
        CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream(CSS));
        cssResolver.addCss(cssFile);

        // HTML
        XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontProvider.register("pdf/華庚少女字體.ttf", "girl");    // 字體別名,在web.html使用
        CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
        HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
        htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());

        // Pipelines
        PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
        HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
        CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

        // XML Worker
        XMLWorker worker = new XMLWorker(css, true);
        XMLParser p = new XMLParser(worker);
        p.parse(new FileInputStream(HTML), Charset.forName("UTF-8"));
        // step 5
        document.close();
    }
    
}

第一個輸出:

 

第二個輸出:

 

第三個輸出:

第四個輸出:

大家可以看到中文的問題,注意點有兩個:html文件指定 font-family;如果引入外部字體文件,別名要與font-family一致。文件:https://github.com/Mysakura/DataFiles

第四個要想成功,需要將web.html文件里的font-family修改

所以呢,如果你對字體沒啥要求,那font-family就指定常用中文字體即可,宋體,雅黑什么的

這部分涉及的文件

注意!!!如果你外部字體為ttc文件,比如simsun.ttc,在引入的地方就要注意寫法,如下:后面有個[,1]

 

合並PDF文件 & 嵌入外部字體

提示:如果你運行上面的例子,你可以發現我的輸入輸出文件都在工程根目錄的pdf文件夾里。

代碼

package com.demo.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * 合並文檔 & 嵌入字體
 */
public class MergeAndAddFont {
    public static final String FONT = "pdf/華庚少女字體.ttf";
    public static final Integer FILE_NUM = 2;   // 合並兩個文件
    public static final String[] FILE_A = {
            "pdf/testA0.pdf", "pdf/testA1.pdf"
    };
    public static final String[] FILE_B = {
            "pdf/testB0.pdf", "pdf/testB1.pdf"
    };
    public static final String[] FILE_C = {
            "pdf/testC0.pdf", "pdf/testC1.pdf"
    };
    public static final String[] CONTENT = {
            "琪亞娜·卡斯蘭娜", "德麗莎·阿波卡利斯"
    };
    public static final String MERGED_A1 = "pdf/testA_merged1.pdf";
    public static final String MERGED_A2 = "pdf/testA_merged2.pdf";
    public static final String MERGED_B1 = "pdf/testB_merged1.pdf";
    public static final String MERGED_B2 = "pdf/testB_merged2.pdf";
    public static final String MERGED_C1 = "pdf/testC_merged1.pdf";
    public static final String MERGED_C2 = "pdf/testC_merged2.pdf";

    public static void main(String[] args) throws DocumentException, IOException {

        File file = new File(MERGED_A1);
        file.getParentFile().mkdirs();
        MergeAndAddFont app = new MergeAndAddFont();

        // 測試一:嵌入字體;生成的文件僅僅包含用到的字形;智能合並;非智能合並
        for (int i = 0; i < FILE_A.length; i++) {
            app.createPdf(FILE_A[i], CONTENT[i], true, true);
        }
        app.mergeFiles(FILE_A, MERGED_A1,false);
        app.mergeFiles(FILE_A, MERGED_A2, true);

        // 測試二:嵌入字體;生成的文件包含完整字體;智能合並;非智能合並
        for (int i = 0; i < FILE_B.length; i++) {
            app.createPdf(FILE_B[i], CONTENT[i], true, false);
        }
        app.mergeFiles(FILE_B, MERGED_B1,false);
        app.mergeFiles(FILE_B, MERGED_B2, true);

        // 測試三:不嵌入字體;生成的文件包含完整字體;智能合並;手動嵌入字體
        for (int i = 0; i < FILE_C.length; i++) {
            app.createPdf(FILE_C[i], CONTENT[i], false, false);
        }
        app.mergeFiles(FILE_C, MERGED_C1, true);
        app.embedFont(MERGED_C1, FONT, MERGED_C2);
    }

    /**
     *
     * @param filename
     * @param text
     * @param embedded  true在PDF中嵌入字體,false不嵌入
     * @param subset    true僅僅包含用到的字形,false包含完整字體
     * @throws DocumentException
     * @throws IOException
     */
    public void createPdf(String filename, String text, boolean embedded, boolean subset) throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        BaseFont bf = BaseFont.createFont(FONT, BaseFont.IDENTITY_H, embedded); // 生成文件大小與編碼有關,如果你沒有中文,那么編碼用BaseFont.WINANSI就節約很多資源了。
        bf.setSubset(subset);
        Font font = new Font(bf, 12);
        document.add(new Paragraph(text, font));
        // step 5
        document.close();
    }

    /**
     * 合並文件
     * @param files
     * @param result
     * @param smart 智能Copy
     * @throws IOException
     * @throws DocumentException
     */
    public void mergeFiles(String[] files, String result, boolean smart) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy;
        if (smart)
            copy = new PdfSmartCopy(document, new FileOutputStream(result));
        else
            copy = new PdfCopy(document, new FileOutputStream(result));
        document.open();
        PdfReader[] reader = new PdfReader[FILE_NUM];
        for (int i = 0; i < files.length; i++) {
            reader[i] = new PdfReader(files[i]);
            copy.addDocument(reader[i]);
            copy.freeReader(reader[i]);
            reader[i].close();
        }
        document.close();
    }

    /**
     * 嵌入字體
     * @param merged
     * @param fontfile
     * @param result
     * @throws IOException
     * @throws DocumentException
     */
    private void embedFont(String merged, String fontfile, String result) throws IOException, DocumentException {
        // the font file
        RandomAccessFile raf = new RandomAccessFile(fontfile, "r");
        byte fontbytes[] = new byte[(int)raf.length()];
        raf.readFully(fontbytes);
        raf.close();
        // create a new stream for the font file
        PdfStream stream = new PdfStream(fontbytes);
        stream.flateCompress();
        stream.put(PdfName.LENGTH1, new PdfNumber(fontbytes.length));
        // create a reader object
        PdfReader reader = new PdfReader(merged);
        int n = reader.getXrefSize();
        PdfObject object;
        PdfDictionary font;
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(result));
        PdfName fontname = new PdfName(BaseFont.createFont(fontfile, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED).getPostscriptFontName());
        for (int i = 0; i < n; i++) {
            object = reader.getPdfObject(i);
            if (object == null || !object.isDictionary())
                continue;
            font = (PdfDictionary)object;
            if (PdfName.FONTDESCRIPTOR.equals(font.get(PdfName.TYPE))
                    && fontname.equals(font.get(PdfName.FONTNAME))) {
                PdfIndirectObject objref = stamper.getWriter().addToBody(stream);
                font.put(PdfName.FONTFILE2, objref.getIndirectReference());
            }
        }
        stamper.close();
        reader.close();
    }
}

運行之后會生成12個文件。

直觀一點的(看文件體積)

首先看A系列,因為它在創建文件的時候就指定包含用到的字形,所以獨立文件的文件屬性都是

合並文件都是

再來看B系列,因為它指定包含完整字體,所以體積很大。不同的是,合並1是非智能的,所以體積是智能的2倍。獨立文件和合並文件的文件屬性都是(已嵌入)

最后看C系列【這里中英文的出入比較大】,如果你是中文PDF,那么文檔屬性都是已嵌入並且手動嵌入的體積是其它的2倍。

如果你是英文文檔,代碼如下,只需要改動兩處(1. 輸入英文,中文不顯示 2. 更改字體編碼),生成的文件C系列大不一樣。

package com.demo.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * 合並文檔 & 嵌入字體
 */
public class MergeAndAddFont3 {
    public static final String FONT = "pdf/華庚少女字體.ttf";
    public static final Integer FILE_NUM = 2;   // 合並兩個文件
    public static final String[] FILE_A = {
            "pdf/en/testA0.pdf", "pdf/en/testA1.pdf"
    };
    public static final String[] FILE_B = {
            "pdf/en/testB0.pdf", "pdf/en/testB1.pdf"
    };
    public static final String[] FILE_C = {
            "pdf/en/testC0.pdf", "pdf/en/testC1.pdf"
    };
    // 英文PDF內容
    public static final String[] CONTENT = {
            "ABCD", "EFGK"
    };
    public static final String MERGED_A1 = "pdf/en/testA_merged1.pdf";
    public static final String MERGED_A2 = "pdf/en/testA_merged2.pdf";
    public static final String MERGED_B1 = "pdf/en/testB_merged1.pdf";
    public static final String MERGED_B2 = "pdf/en/testB_merged2.pdf";
    public static final String MERGED_C1 = "pdf/en/testC_merged1.pdf";
    public static final String MERGED_C2 = "pdf/en/testC_merged2.pdf";

    public static void main(String[] args) throws DocumentException, IOException {

        File file = new File(MERGED_A1);
        file.getParentFile().mkdirs();
        MergeAndAddFont3 app = new MergeAndAddFont3();

        // 測試一:嵌入字體;生成的文件僅僅包含用到的字形;智能合並;非智能合並
        for (int i = 0; i < FILE_A.length; i++) {
            app.createPdf(FILE_A[i], CONTENT[i], true, true);
        }
        app.mergeFiles(FILE_A, MERGED_A1,false);
        app.mergeFiles(FILE_A, MERGED_A2, true);

        // 測試二:嵌入字體;生成的文件包含完整字體;智能合並;非智能合並
        for (int i = 0; i < FILE_B.length; i++) {
            app.createPdf(FILE_B[i], CONTENT[i], true, false);
        }
        app.mergeFiles(FILE_B, MERGED_B1,false);
        app.mergeFiles(FILE_B, MERGED_B2, true);

        // 測試三:不嵌入字體;生成的文件包含完整字體;智能合並;手動嵌入字體
        for (int i = 0; i < FILE_C.length; i++) {
            app.createPdf(FILE_C[i], CONTENT[i], false, false);
        }
        app.mergeFiles(FILE_C, MERGED_C1, true);
        app.embedFont(MERGED_C1, FONT, MERGED_C2);
    }

    /**
     *
     * @param filename
     * @param text
     * @param embedded  true在PDF中嵌入字體,false不嵌入
     * @param subset    true僅僅包含用到的字形,false包含完整字體
     * @throws DocumentException
     * @throws IOException
     */
    public void createPdf(String filename, String text, boolean embedded, boolean subset) throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // 英文編碼
        BaseFont bf = BaseFont.createFont(FONT, BaseFont.WINANSI, embedded); // 生成文件大小與編碼有關,如果你沒有中文,那么編碼用BaseFont.WINANSI就節約很多資源了。
        bf.setSubset(subset);
        Font font = new Font(bf, 12);
        document.add(new Paragraph(text, font));
        // step 5
        document.close();
    }

    /**
     * 合並文件
     * @param files
     * @param result
     * @param smart 智能Copy
     * @throws IOException
     * @throws DocumentException
     */
    public void mergeFiles(String[] files, String result, boolean smart) throws IOException, DocumentException {
        Document document = new Document();
        PdfCopy copy;
        if (smart)
            copy = new PdfSmartCopy(document, new FileOutputStream(result));
        else
            copy = new PdfCopy(document, new FileOutputStream(result));
        document.open();
        PdfReader[] reader = new PdfReader[FILE_NUM];
        for (int i = 0; i < files.length; i++) {
            reader[i] = new PdfReader(files[i]);
            copy.addDocument(reader[i]);
            copy.freeReader(reader[i]);
            reader[i].close();
        }
        document.close();
    }

    /**
     * 嵌入字體
     * @param merged
     * @param fontfile
     * @param result
     * @throws IOException
     * @throws DocumentException
     */
    private void embedFont(String merged, String fontfile, String result) throws IOException, DocumentException {
        // the font file
        RandomAccessFile raf = new RandomAccessFile(fontfile, "r");
        byte fontbytes[] = new byte[(int)raf.length()];
        raf.readFully(fontbytes);
        raf.close();
        // create a new stream for the font file
        PdfStream stream = new PdfStream(fontbytes);
        stream.flateCompress();
        stream.put(PdfName.LENGTH1, new PdfNumber(fontbytes.length));
        // create a reader object
        PdfReader reader = new PdfReader(merged);
        int n = reader.getXrefSize();
        PdfObject object;
        PdfDictionary font;
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(result));
        PdfName fontname = new PdfName(BaseFont.createFont(fontfile, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED).getPostscriptFontName());
        for (int i = 0; i < n; i++) {
            object = reader.getPdfObject(i);
            if (object == null || !object.isDictionary())
                continue;
            font = (PdfDictionary)object;
            if (PdfName.FONTDESCRIPTOR.equals(font.get(PdfName.TYPE))
                    && fontname.equals(font.get(PdfName.FONTNAME))) {
                PdfIndirectObject objref = stamper.getWriter().addToBody(stream);
                font.put(PdfName.FONTFILE2, objref.getIndirectReference());
            }
        }
        stamper.close();
        reader.close();
    }
}
View Code

英文C系列,獨立文件和智能合並的文件屬性都是

而手動嵌入字體的則是

所以得出結論:

A系列相當於正常使用,基本都是默認值。對於嵌入字體需求的:

無論你是中文文檔還是英文文檔,就選擇B系列,因為無論生成的獨立文件還是合並文件都已嵌入字體。並且大小已是極限了。

C系列的話,注意除了手動嵌入方法,其它情況都不嵌入的。這意味着什么呢?【已嵌入子集】【已嵌入】,則表示你的字體不會發生變化。如果不帶這個,就會造成:如果你換了個沒有這種字體的系統,字體會顯示為當前系統的默認字體。如下是我打開的

 

中文系列則應該是

 

 

這僅僅對於有嵌入字體需求的,正常輸出PDF的話不用考慮這么多,因為默認subset=true,PDF僅僅包含用到的字形。

還有一點,重復試驗之后,發現只有你已使用的字體,才可以嵌入。PDF中未用到的字體是無法嵌入的。

package com.demo.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * 合並文檔 & 嵌入字體
 */
public class MergeAndAddFont2 {
    public static final String FONT = "pdf/華庚少女字體.ttf";
    public static final String FONT_FILE = "pdf/simsun.ttc";

    public static final String SRC_PDF = "pdf/testD0.pdf";

    public static void main(String[] args) throws DocumentException, IOException {

        File file = new File(SRC_PDF);
        file.getParentFile().mkdirs();
        MergeAndAddFont2 app = new MergeAndAddFont2();

        app.createPdf(SRC_PDF, "琪亞娜·卡斯蘭娜", true, false);

        app.embedFont(SRC_PDF, FONT_FILE, "pdf/testD_embedded.pdf");
    }

    public void createPdf(String filename, String text, boolean embedded, boolean subset) throws DocumentException, IOException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        // step 3
        document.open();
        // step 4
        BaseFont bf = BaseFont.createFont(FONT, BaseFont.IDENTITY_H, embedded);
        bf.setSubset(subset);
        Font font = new Font(bf, 12);
        document.add(new Paragraph(text, font));
        // step 5
        document.close();
    }



    /**
     * 嵌入字體
     * @param src
     * @param fontfile  ttc文件地址(pdf/simsun.ttc)
     * @param result
     * @throws IOException
     * @throws DocumentException
     */
    private void embedFont(String src, String fontfile, String result) throws IOException, DocumentException {
        // 讀取字體文件
        RandomAccessFile raf = new RandomAccessFile(fontfile, "r");
        byte fontbytes[] = new byte[(int)raf.length()];
        raf.readFully(fontbytes);
        raf.close();
        // 創建一個字體文件流
        PdfStream stream = new PdfStream(fontbytes);
        stream.flateCompress();
        stream.put(PdfName.LENGTH1, new PdfNumber(fontbytes.length));
        // 讀取已有的PDF
        PdfReader reader = new PdfReader(src);
        int n = reader.getXrefSize();
        PdfObject object;
        PdfDictionary font;
        // 添加額外的內容到已有的PDF中
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(result));
        // 這里的字體文件應該是PDF中已有的字體【正常來講,這里聲明的字體應該和待嵌入的一致】
        PdfName fontname = new PdfName(BaseFont.createFont(FONT, BaseFont.WINANSI, BaseFont.NOT_EMBEDDED).getPostscriptFontName());
        // 遍歷源文件,找到 /FontDescriptor,以及對應的字體。嵌入字體
        for (int i = 0; i < n; i++) {
            object = reader.getPdfObject(i);
            // 為空或者不是目錄,跳過
            if (object == null || !object.isDictionary())
                continue;
            font = (PdfDictionary)object;
            // 目錄類型和名稱
            System.out.println(font.get(PdfName.TYPE) + "\t" + font.get(PdfName.FONTNAME));
            if (PdfName.FONTDESCRIPTOR.equals(font.get(PdfName.TYPE)) && fontname.equals(font.get(PdfName.FONTNAME))) {
                PdfIndirectObject objref = stamper.getWriter().addToBody(stream);
                font.put(PdfName.FONTFILE2, objref.getIndirectReference());
            }
        }
        stamper.close();
        reader.close();
    }
}

打印輸出:

 

 可以看到,源文件只有一種字體,就是 少女字體。而我們也成功的把宋體文件寫進入了,至少表面上看是這樣的。如下:

 

 我們打開源文件

 

 再來看我們期望的PDF文件,到底宋體進沒進去呢。

 可以看到,雖然PDF體積增加了,但是字體文件並沒有進去,還造成了亂碼。所以,手動嵌入字體僅僅針對那些,已使用了某個字體,但是沒有嵌入的情況。

BaseFont bf = BaseFont.createFont(FONT, BaseFont.IDENTITY_H, embedded);    // 正常使用的話,embedded為true就能滿足日常需求,subset使用默認值即可,不需設置。

條形碼

package com.demo.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 條形碼
 */
public class SmallTable {
    public static final String FONT = "pdf/華庚少女字體.ttf";
    public static final String DEST = "pdf/small_table.pdf";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new SmallTable().createPdf(DEST);
    }
    public void createPdf(String dest) throws IOException, DocumentException {
        Rectangle small = new Rectangle(290,100);
        BaseFont bf = BaseFont.createFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        Font font = new Font(bf, 12);
        Document document = new Document(small, 5, 5, 5, 5);
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
        document.open();
        PdfPTable table = new PdfPTable(2);
        table.setTotalWidth(new float[]{ 160, 120 });
        table.setLockedWidth(true);
        PdfContentByte cb = writer.getDirectContent();
        // first row
        PdfPCell cell = new PdfPCell(new Phrase("條形碼", font));
        cell.setFixedHeight(30);
        cell.setBorder(Rectangle.NO_BORDER);
        cell.setColspan(2);
        cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
        table.addCell(cell);
        // second row
        Barcode128 code128 = new Barcode128();
        code128.setCode("14785236987541");
        code128.setCodeType(Barcode128.CODE128);
        Image code128Image = code128.createImageWithBarcode(cb, null, null);
        cell = new PdfPCell(code128Image, true);
        cell.setColspan(2);
        cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
        cell.setBorder(Rectangle.NO_BORDER);
        cell.setFixedHeight(30);
        table.addCell(cell);

        document.add(table);
        document.close();
    }
}

輸出:

 

單元格以圖片為背景

package com.demo.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 單元格圖片背景
 */
public class ImageBackground {
    class ImageBackgroundEvent implements PdfPCellEvent {

        protected Image image;

        public ImageBackgroundEvent(Image image) {
            this.image = image;
        }

        public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) {
            try {
                PdfContentByte cb = canvases[PdfPTable.BACKGROUNDCANVAS];
                image.scaleAbsolute(position);
                image.setAbsolutePosition(position.getLeft(), position.getBottom());
                cb.addImage(image);
            } catch (DocumentException e) {
                throw new ExceptionConverter(e);
            }
        }
    }

    public static final String DEST = "pdf/image_background.pdf";
    public static final String IMG1 = "pdf/bruno.jpg";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new ImageBackground().createPdf(DEST);
    }

    public void createPdf(String dest) throws IOException, DocumentException {
        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream(dest));
        document.open();
        PdfPTable table = new PdfPTable(1);
        table.setTotalWidth(400);
        table.setLockedWidth(true);
        PdfPCell cell = new PdfPCell();
        Font font = new Font(Font.FontFamily.HELVETICA, 12, Font.NORMAL, GrayColor.GRAYWHITE);
        Paragraph p = new Paragraph("A cell with an image as background.", font);
        cell.addElement(p);
        Image image = Image.getInstance(IMG1);
        cell.setCellEvent(new ImageBackgroundEvent(image));
        cell.setFixedHeight(600 * image.getScaledHeight() / image.getScaledWidth());
        table.addCell(cell);
        document.add(table);
        document.close();
    }
}

輸出:

小示例(本人不才,簡單畫了個表格)

package com.demo.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 一些示例
 */
public class Tables {
    public static final String FONT = "pdf/華庚少女字體.ttf";
    public static final String DEST = "pdf/tables.pdf";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new Tables().createPdf(DEST);
    }
    public void createPdf(String dest) throws IOException, DocumentException {
        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream(dest));
        document.open();

        // 使用語言包字體
        BaseFont abf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
        // 外部字體
        BaseFont bf = BaseFont.createFont(FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        Font titleFont = new Font(bf, 12, Font.BOLD);
        titleFont.setColor(new BaseColor(76,175,80));
        Font font = new Font(bf, 10);

        Paragraph p = new Paragraph("個人簡歷表", new Font(abf, 12, Font.BOLD));
        p.setAlignment(Paragraph.ALIGN_CENTER);
        document.add(p);

        PdfPTable table = new PdfPTable(8);
        table.setSpacingBefore(16f);

        PdfPCell cell = new PdfPCell(new Phrase("姓名", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("德麗莎", font));
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("性別", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("女", font));
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("出生年月", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("3月28日", font));
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("民族", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("天命→休伯利安", font));
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("個人簡歷", titleFont));
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        table.addCell(cell);
        cell = new PdfPCell();
        cell.setColspan(7);
        cell.addElement(new Paragraph("卡斯蘭娜家族一貫的白發藍眸,長發扎成馬尾披於左肩。常穿天命早期使用的女武神統一制服。德麗莎所穿的制服是特別定制款,由主教奧托親手縫制,在衣服胸口處別着阿波卡利斯家族的家徽。", font));
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("家庭成員", titleFont));
        cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
        cell.setRowspan(3);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("稱呼", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("姓名", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("關系", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setColspan(5);
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("爺爺", font));
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("奧托·阿波卡利斯", font));
        table.addCell(cell);
        cell = new PdfPCell();
        cell.addElement(new Paragraph("德麗莎的造物主,奧托賜予了德麗莎名字,認其為孫女。因為德麗莎溫柔而又堅強的性格,讓奧托多次產生德麗莎是卡蓮的轉世的想法", font));
        cell.setColspan(5);
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("侄女", font));
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("琪亞娜·卡斯蘭娜", font));
        table.addCell(cell);
        cell = new PdfPCell();
        cell.addElement(new Paragraph("塞西莉亞和齊格飛的女兒,兩人讓德麗莎當琪亞娜的教母,琪亞娜這個名字也是德麗莎起的。齊格飛逃離天命的行動中,本想一起逃離天命的德麗莎為保護備天命回收的琪亞娜,回到天命。", font));
        cell.setColspan(5);
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("他人評價", titleFont));
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        table.addCell(cell);
        cell = new PdfPCell();
        cell.setColspan(7);
        cell.setPaddingLeft(8f);
        cell.setPaddingRight(8f);
        cell.setPaddingBottom(16f);
        // 配置行間距
        cell.addElement(new Paragraph(24, "“即使離開了天命,您也依然是我們所尊敬的學園長。”——雷電芽衣\n" +
                "“雖然看起來很小,倒也有點本事。”——西琳 \n" +
                "“誒~德麗莎看起來小小的,意外地很能干嘛。”——蘿莎莉婭·阿琳", font));
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("其它", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("···"));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setFixedHeight(32f);
        cell.setColspan(7);
        table.addCell(cell);
        document.add(table);

        // ------------------------------------------------

        table = new PdfPTable(4);
        table.setSpacingBefore(32f);

        Font titleFont2 = new Font(bf, 14, Font.BOLD);
        titleFont2.setColor(new BaseColor(255,255,255));

        cell = new PdfPCell(new Phrase("賬單", titleFont2));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        cell.setColspan(4);
        cell.setFixedHeight(32f);
        cell.setBackgroundColor(new BaseColor(96, 125, 139));
        cell.setBorder(Rectangle.NO_BORDER);
        table.addCell(cell);

        cell = new PdfPCell(new Phrase("日期", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("項目", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("金額", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("說明", titleFont));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        table.addCell(cell);

        LocalDateTime dt = LocalDateTime.now();
        for (int i = 0; i < 10; i++){
            dt = dt.plusDays(1L);
            cell = new PdfPCell(new Phrase(dt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")), font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("花唄還款", font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("$100.0", font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("——", font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
        }
        document.add(table);

        // ------------------------------------------------

        document.newPage();
        document.add(new Paragraph("芒種\n\n" +
                "一想到你我就\n" +
                "wu~~~~\n" +
                "空恨別夢久\n" +
                "wu~~~~\n" +
                "燒去紙灰埋煙柳\n" +
                "\n" +
                "於鮮活的枝丫\n" +
                "凋零下的無暇\n" +
                "是收獲謎底的代價\n" +
                "\n" +
                "余暉沾上 遠行人的發\n" +
                "他灑下手中牽掛\n" +
                "於橋下\n" +
                "前世遲來者~~~(擦肩而過)\n" +
                "掌心刻~~~~~(來生記得)\n" +
                "你眼中煙波滴落一滴墨 wo~~~\n" +
                "若佛說~~~~~(無牽無掛)\n" +
                "放下執着~~~~~(無相無色)\n" +
                "我怎能 波瀾不驚 去附和\n" +
                "\n" +
                "一想到你我就\n" +
                "wu~~~~~\n" +
                "恨情不壽 總於苦海囚\n" +
                "wu~~~~~\n" +
                "新翠徒留 落花影中游\n" +
                "wu~~~~~\n" +
                "相思無用 才笑山盟舊\n" +
                "wu~~~~~\n" +
                "謂我何求\n" +
                "\n" +
                "種一萬朵蓮花\n" +
                "在眾生中發芽\n" +
                "等紅塵一萬種解答\n" +
                "\n" +
                "念珠落進 時間的泥沙\n" +
                "待 割舍詮釋慈悲\n" +
                "的讀法\n" +
                "\n" +
                "前世遲來者~~~(擦肩而過)\n" +
                "掌心刻~~~~~(來生記得)\n" +
                "你眼中煙波滴落一滴墨 wo~~~\n" +
                "若佛說~~~~~(無牽無掛)\n" +
                "放下執着~~~~~(無相無色)\n" +
                "我怎能 波瀾不驚 去附和", font));


        document.close();
    }
}

輸出

 

頁眉頁腳 

package com.demo.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;

/**
 * 頁眉頁腳
 */
public class PageNumber {
    class Header extends PdfPageEventHelper {

        @Override
        public void onStartPage(PdfWriter writer, Document document) {
            PdfPTable table = new PdfPTable(1);
            try {
                Font font = new Font(BaseFont.createFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED), 10);
                table.setTotalWidth(PageSize.A4.getWidth());    // A4大小
                table.getDefaultCell().setFixedHeight(20);
                PdfPCell cell = new PdfPCell(new Phrase("XXX生活支出明細", font));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                cell.setBorder(Rectangle.BOTTOM);
                cell.setPaddingBottom(6f);
                table.addCell(cell);

                PdfContentByte canvas = writer.getDirectContent();
                table.writeSelectedRows(0, -1, ((document.right() + document.rightMargin())-PageSize.A4.getWidth())/2, document.top()+25, canvas);
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            PdfPTable table = new PdfPTable(1);
            try {
                Font font = new Font(Font.FontFamily.SYMBOL, 10);
                table.setTotalWidth(PageSize.A4.getWidth());    // A4大小
                table.getDefaultCell().setFixedHeight(20);
                table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
                table.getDefaultCell().setBorder(Rectangle.NO_BORDER);
                table.addCell(new Phrase(writer.getPageNumber()+"", font));

                PdfContentByte canvas = writer.getDirectContent();
                table.writeSelectedRows(0, -1, ((document.right() + document.rightMargin())-PageSize.A4.getWidth())/2, document.bottom(), canvas);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static final String DEST = "pdf/pdf_with_head_foot.pdf";
    public static final String FONT = "pdf/華庚少女字體.ttf";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new PageNumber().createPdf(DEST);
    }

    public void createPdf(String dest) throws IOException, DocumentException {
        Font font = new Font(BaseFont.createFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED), 10);
        Document document = new Document(PageSize.A4.rotate());
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
        writer.setPageEvent(new Header());
        document.open();
        PdfDictionary parameters = new PdfDictionary();
        parameters.put(PdfName.MODDATE, new PdfDate());
        PdfPTable table = new PdfPTable(3);
        table.setTotalWidth(PageSize.A4.getWidth());
        // 鎖定寬度
        table.setLockedWidth(true);
        table.setWidths(new int[]{4, 4, 2});
        PdfPCell cell = new PdfPCell(new Phrase("去向", font));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setPadding(8f);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("金額", font));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setPadding(8f);
        table.addCell(cell);
        cell = new PdfPCell(new Phrase("備注", font));
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setPadding(8f);
        table.addCell(cell);

        Random random = new Random();
        for (int i = 0; i < 30; i++){
            cell = new PdfPCell(new Phrase("花唄還款", font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("$" + random.nextInt(500), font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
            cell = new PdfPCell(new Phrase("——", font));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            cell.setPadding(8f);
            table.addCell(cell);
        }
        document.add(table);
        document.close();
    }

}

輸出:

 

每一頁具有相同的標題行或者頁腳行

package com.demo.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.GrayColor;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 *  跨頁表格,每一頁都有相同的頁腳頁眉行。
 */
public class HeaderRowsTable {
    public static final String DEST = "pdf/header_row_table.pdf";

    public static void main(String[] args) throws IOException, DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new HeaderRowsTable().createPdf(DEST);
    }
    public void createPdf(String dest) throws IOException, DocumentException {
        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream(dest));
        document.open();
        Font f = new Font(Font.FontFamily.HELVETICA, 13, Font.NORMAL, BaseColor.YELLOW);


        float[] columnWidths = {1, 5, 5};
        PdfPTable table = new PdfPTable(columnWidths);
        table.setWidthPercentage(100);
        table.getDefaultCell().setUseAscender(true);
        table.getDefaultCell().setUseDescender(true);
        PdfPCell cell = new PdfPCell(new Phrase("Header Row And Footer Row", f));
        cell.setBackgroundColor(GrayColor.GRAYBLACK);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setColspan(3);
        table.addCell(cell);
        table.getDefaultCell().setBackgroundColor(new GrayColor(0.75f));
        // 每個頁面出現的頁眉+頁腳行數
        for (int i = 0; i < 2; i++) {
            table.addCell("#");
            table.addCell("Key");
            table.addCell("Value");
        }
        // 設置標題行數。只有將表添加到文檔並且表跨頁時,此配置才有意義。
        table.setHeaderRows(3);
        // 設置頁腳行數。頁眉行數 = 標題行數 - 頁腳行數。比如此例子:每一頁表格都有兩行頁眉行(3-1=2)和一行頁腳行。
        table.setFooterRows(1);
        table.getDefaultCell().setBackgroundColor(GrayColor.GRAYWHITE);
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
        for (int counter = 1; counter < 51; counter++) {
            table.addCell(String.valueOf(counter));
            table.addCell("—— ");
            table.addCell("—— ");
        }
        document.add(table);


        document.newPage();
        table = new PdfPTable(columnWidths);
        table.setSpacingBefore(32f);
        table.setWidthPercentage(100);
        table.getDefaultCell().setUseAscender(true);
        table.getDefaultCell().setUseDescender(true);
        cell = new PdfPCell(new Phrase("Only Have Header Row", f));
        cell.setBackgroundColor(GrayColor.GRAYBLACK);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        cell.setColspan(3);
        table.addCell(cell);
        table.getDefaultCell().setBackgroundColor(new GrayColor(0.75f));
        // 每個頁面出現的頁眉+頁腳行數
        for (int i = 0; i < 1; i++) {
            table.addCell("#");
            table.addCell("Key");
            table.addCell("Value");
        }
        // 也可以僅僅設置頁眉行
        table.setHeaderRows(2);
        table.getDefaultCell().setBackgroundColor(GrayColor.GRAYWHITE);
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
        for (int counter = 1; counter < 51; counter++) {
            table.addCell(String.valueOf(counter));
            table.addCell("—— ");
            table.addCell("—— ");
        }
        document.add(table);


        document.newPage();
        table = new PdfPTable(columnWidths);
        table.setSpacingBefore(32f);
        table.setWidthPercentage(100);
        table.getDefaultCell().setUseAscender(true);
        table.getDefaultCell().setUseDescender(true);
        table.getDefaultCell().setBackgroundColor(new BaseColor(133,148,6));
        // 每個頁面出現的頁眉+頁腳行數(數量與setHeaderRows(2)一致。為什么前面示例都是少1呢?因為前面示例已經單獨添加了一行主標題)
        for (int i = 0; i < 2; i++) {
            table.addCell(new Phrase("#", f));
            table.addCell(new Phrase("Key", f));
            table.addCell(new Phrase("Value", f));
        }
        table.setHeaderRows(2);
        table.setFooterRows(1);
        table.getDefaultCell().setBackgroundColor(GrayColor.GRAYWHITE);
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
        for (int counter = 1; counter < 51; counter++) {
            table.addCell(String.valueOf(counter));
            table.addCell("—— ");
            table.addCell("—— ");
        }
        document.add(table);

        document.close();
    }
}

結果:(一共三種示例,自行去比較)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM