Itext5生成PDF


Itext

官網

Java操作pdf方法

  1. 通過Adobe Acrobat生成pdf form,通過Java設置form表單中的元素值進行數據填充。
  2. 讀取pdf通過坐標進行填充數據,繪制成結果pdf。
  3. 通過itext代碼繪制pdf。

Acrobat制作模板

先用Excel制作一個Excel模板,另存為PDF文件。

制作Excel模板

Excel另存為PDF

用Adobe Acrobat Pro DC打開PDF模板文件,打開表單功能,在指定地方添加文字域,模板即可制作完成。

Java代碼填充AcroField

Java代碼對Acrobat制作的PDF中的Form進行填充。

Maven坐標

<properties>
    <itextpdf.version>5.5.6</itextpdf.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>${itextpdf.version}</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf.tool</groupId>
        <artifactId>xmlworker</artifactId>
        <version>${itextpdf.version}</version>
    </dependency>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext-asian</artifactId>
        <version>5.2.0</version>
    </dependency>
</dependencies>

Java代碼

//設置字體
//BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
/*模板*/
PdfReader reader = new PdfReader("發票模板.pdf");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PdfStamper ps = new PdfStamper(reader, bos);
/*使用中文字體 使用 AcroFields填充值的不需要在程序中設置字體,在模板文件中設置字體為中文字體 Adobe 宋體 std L*/
AcroFields s = ps.getAcroFields();
//設置表單的key-value值
//通過s.setFieldProperty("字段名", "textfont", BaseFont , null); 設置字段的字體格式或者在模板中修改樣式
//s.setFieldProperty("checkNo","textfont",bfChinese,null); //只有第一個字段是變量,其他的都固定死,這樣可以解決Acro默認字段時中文只顯示最后一位的問題。
s.setField("checkNo", "20210204");
s.setField("$info$", "測試單位");
s.setField("$projectName_1$", "測試項目");
s.setField("$num_1$", "2");
s.setField("$bw_1$", "1");
s.setField("$amount_1$", "100000000");
s.setField("$total$", "壹佰萬整");
s.setField("$bz_1$", "個");
s.setField("$SKR$", "測試人");
s.setField("$SKDW$", "測試單位");
s.setField("$year$", "2021");
s.setField("$month$", "11");
s.setField("$day$", "08");
// 設為true,設置為false后生成的pdf依然可編輯
ps.setFormFlattening(true);
ps.close();

/*輸出到指定位置*/
FileOutputStream fos = new FileOutputStream("d:\\發票.pdf");
fos.write(bos.toByteArray());

輸出展示

可能遇到的問題

批量設置字體

使用默認表單域中文字段一定要s.setFieldProperty("字段名", "textfont", BaseFont , null)設置中文字體,否則顯示可能出問題。
居中顯示等樣式需要在adobe acrobat中顯示。

給每個表單域都添加代碼

s.getFields().forEach((k, v) -> {
	s.setFieldProperty(k, "textfont", BaseFont, null);
        s.setFieldProperty(k, "textsize", Float.valueOf("14"), null);
});

文字超出表單域

換行法

換行法就是增加單元格高度,先在adobe acrobat中設置表單文字域屬性->選項->勾選多行,然后判斷文字寬度是否大於表單域,如果大於,則展示的表單域高度增加。

/**
 * 判斷字體是否超出文本域長度
 * @param filedVal 表單域的值
 * @param filedName 表單域的key
 * @param form 表單域實例
 * @return 文本超過表單域的返回true
 * @throws IOException
 * @throws DocumentException
 */
public static boolean checkLength(String filedVal, String filedName, AcroFields form) throws IOException, DocumentException {
    float fontSize = 12f;
    boolean flag = false;
    BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    float textWidth = baseFont.getWidthPoint(filedVal, fontSize);
    Rectangle position = form.getFieldPositions(filedName).get(0).position;
    float textBoxWidth = position.getWidth();
    if (textWidth > textBoxWidth) {
        flag = true;
    }
    return flag;
}


/*使用,首先在adobe acrobat中設置表單文字域屬性->選項->勾選多行*/
boolean b = checkLength("超出表單域寬度的金額.........","$amount_1$",s);
if (b){  //如果超過了,則修改表單域的大小,使其顯示的高度+16
    /*獲取當前文本框的尺寸,返回的數據依次為左上右下(0,1,2,3)*/
    PdfArray rect1 = s.getFieldItem("$amount_1$").getValue(0).getAsArray(PdfName.RECT);
    rect1.set(1, new PdfNumber(rect1.getAsNumber(1).intValue() - 16));
}
s.setField("$amount_1$", "超出表單域寬度的金額.........");

縮小字體

單行,用縮小字體方法單行顯示字體。

/**
 * 判斷字體是否超出文本域長度
 * @param fieldVal 表單域的值
 * @param filedName 表單域的key
 * @param form 表單域實例
 * @return 字體大小
 * @throws IOException
 * @throws DocumentException
 */
public static float checkLengthFront(String fieldVal, String filedName, AcroFields form) throws IOException, DocumentException {
    BaseFont baseFont = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    float fontSize = 12f;
    Rectangle position = form.getFieldPositions(filedName).get(0).position;
    float textBoxWidth = position.getWidth();
    /*文本框高度*/
    float textBoxHeight = position.getHeight();
    /*文本單行行高*/
    float ascent = baseFont.getFontDescriptor(baseFont.ASCENT, fontSize);
    /*baseFont渲染后的文字寬度*/
    float textWidth = baseFont.getWidthPoint(fieldVal, fontSize);

    /*文本框高度只夠寫一行,並且文字寬度大於文本框寬度,則縮小字體*/
    if (textBoxHeight < ascent * 1.6) {
        while (textWidth > textBoxWidth) {
            fontSize--;
            textWidth = baseFont.getWidthPoint(fieldVal, fontSize);
        }
    }
    return fontSize;
}

/*使用*/
float fsize= checkLengthFront("超出表單域寬度的金額.........", "$amount_1$",s);  //計算字體大小並返回
s.setFieldProperty("$amount_1$", "textsize", fsize , null);  //設置字體大小
s.setField("$amount_1$", "超出表單域寬度的金額.........");

選框樣式差號BUG

在制作模板時,放入一組Radio或者CheckBox,無論樣式選擇成什么,結果都是顯示一個x號。

解決辦法:把com.itextpdf.itextpdf核心包從5.5.6降到5.2.1/5.3.0/5.5.0/5.5.1/5.5.2/5.5.3/5.5.4,經過多次測試,發現就是不能超過5.5.5,一旦超過5.5.5就會出現差,到5.5.7時Radio會變成圓點樣式但是CheckBox依然是差,所以我選擇最接近5.5.6的5.5.4。

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.4</version>
</dependency>
<dependency>
    <groupId>com.itextpdf.tool</groupId>
    <artifactId>xmlworker</artifactId>
    <version>5.5.6</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>

通過選擇框的名稱和值來打勾

s.setField("RadioGroup", "1");
s.setField("CheckBox", "1");

最終樣式

參考:

https://blog.csdn.net/u011391773/article/details/53084231

https://blog.csdn.net/sand_clock/article/details/85328849


免責聲明!

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



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