通過pdf模板,填充內容,生成pdf檔案---JAVA
阿新 • • 發佈:2022-05-06
1 概述
我們通常會遇到需要生成某些固定格式,但是內容不同的檔案,那麼我們就可以使用⽤Adobe Acrobat DC來建立pdf模組,然後通過程式碼對模板進行填充,生成pdf檔案
2 建立一個pdf模板檔案
2.1 先建立一個word建立我們想要的表單
2.2 把word轉換成pdf,如下圖,建立了這麼一個表單,轉成了pdf
3 使⽤Adobe Acrobat DC開啟PDF⽂件,來建立模板
3.1使用Adobe Acrobat DC開啟檔案
3.2 點選右邊的功能準備表單
3.3 點選上面按鈕-新增文字域
3.4 把文字域放到我們要填充的地方
3.5 填寫域名稱(後面編碼就是根據域名稱來填入內容的)
還可以雙擊這個框框開啟設定,設定其他屬性
3.6 完成所有的文字域
3.7 檔案-另存為-儲存檔案(這個檔案就是我們的模板檔案了)
4 編碼
4.1 pdf-圖片工具類
package com.ruoyi.weixin.user.MyTest.Itext;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import javax.imageio.ImageIO;
import java.io. *;
/**
* @Classname ImageThumbUtil
* @Description TODO
* @Date 2022/5/6 0006 下午 4:34
* @Created by jcc
*/
public class ImageThumbUtils {
/**
* 縮圖⽚,圖⽚質量為源圖的80%
*
* @param originalImgPath 源圖⽚儲存路徑
* @param w 圖⽚壓縮後的寬度
* @param h 圖⽚壓縮後的⾼度
* @param targetImgPath 縮圖的存放路徑
*/
public static void thumbImage(String originalImgPath, int w, int h, String targetImgPath) throws Exception {
thumbImage(new FileInputStream(originalImgPath), w, h, targetImgPath, 0.8);
}
/**
* 縮圖⽚,圖⽚質量為源圖的80%
*
* @param originalImgData 源圖⽚位元組數
* @param w 圖⽚壓縮後的寬度
* @param h 圖⽚壓縮後的⾼度
* @param targetImgPath 縮圖的存放路徑
*/
public static void thumbImage(byte[] originalImgData, int w, int h, String targetImgPath) throws Exception {
thumbImage(new ByteArrayInputStream(originalImgData), w, h, targetImgPath, 0.8);
}
/**
* 按⽐例壓縮⽂件
*
* @param originalImgData 源⽂件
* @param compressQalitiy 壓縮⽐例
* @param targetImgPath ⽬標路徑
*/
public static void thumbImage(byte[] originalImgData, double compressQalitiy, String targetImgPath) throws Exception {
Thumbnails.of(new ByteArrayInputStream(originalImgData)).scale(1f).outputQuality(compressQalitiy).toFile(targetImgPath);
}
/**
* 按⽐例壓縮⽂件
*
* @param originalImgData 源⽂件
* @param compressQalitiy 壓縮⽐例
*/
public static OutputStream thumbImage(byte[] originalImgData, double compressQalitiy) throws Exception {
OutputStream os = new ByteArrayOutputStream();
Thumbnails.of(new ByteArrayInputStream(originalImgData)).scale(1f).outputQuality(compressQalitiy).toOutputStream(os);
return os;
}
/**
* 按尺⼨⽐例縮略
*
* @param originalInputSteam 源圖輸⼊流
* @param w 縮略寬
* @param h 縮略⾼
* @param targetImgPath 縮圖儲存路徑
* @param compressQalitiy 縮略質量⽐例,0~1之間的數
*/
public static void thumbImage(InputStream originalInputSteam, int w, int h, String targetImgPath, double compressQalitiy) throws Exception {
thumbImage(originalInputSteam, w, h, targetImgPath, compressQalitiy, true);
}
/**
* @param originalImgInputSteam 源圖⽚輸⼊流
* @param w 圖⽚壓縮後的寬度
* @param h 圖⽚壓縮後的⾼度
* @param targetImgPath 縮圖的存放路徑
* @param compressQalitiy 壓縮⽐例,0~1之間的double數字
* @param keepAspectRatio 是否保持等⽐例壓縮,是true,不是false
*/
public static void thumbImage(InputStream originalImgInputSteam, int w, int h, String targetImgPath, double compressQalitiy,
boolean keepAspectRatio) throws Exception {
Thumbnails.of(originalImgInputSteam).size(w, h).outputQuality(Double.valueOf(compressQalitiy)).keepAspectRatio(true).toFile(targetImgPath);
}
/**
* 圖⽚裁剪
*
* @param originalImgPath 源圖⽚路徑
* @param targetImgPath 新圖⽚路徑
* @param position 位置 0正中間,1中間左邊,2中間右邊,3底部中間,4底部左邊,5底部右邊,6頂部中間,7頂部左邊,8頂部右邊,
* 其他為預設正中間
* @param w 裁剪寬度
* @param h 裁剪⾼度
* @throws Exception
*/
public static void crop(String originalImgPath, int position, int w, int h, String targetImgPath) throws Exception {
Thumbnails.of(originalImgPath).sourceRegion(getPositions(position), w, h).size(w, h).outputQuality(1).toFile(targetImgPath);
}
/**
* 給圖⽚新增⽔印
*
* @param originalImgPath 將被新增⽔印圖⽚ 路徑
* @param targetImgPath 含有⽔印的新圖⽚路徑
* @param watermarkImgPath ⽔印圖⽚
* @param position 位置 0正中間,1中間左邊,2中間右邊,3底部中間,4底部左邊,5底部右邊,6頂部中間,7頂部左邊,8頂部右邊,
* 其他為預設正中間
* @param opacity 不透明度,取0~1之間的float數字,0完全透明,1完全不透明
* @throws Exception
*/
public static void watermark(String originalImgPath, String watermarkImgPath, int position, float opacity, String targetImgPath)
throws Exception {
Thumbnails.of(originalImgPath).watermark(getPositions(position), ImageIO.read(new File(watermarkImgPath)), opacity).scale(1.0)
.outputQuality(1).toFile(targetImgPath);
}
private static Positions getPositions(int position) {
Positions p = Positions.CENTER;
switch (position) {
case 0: {
p = Positions.CENTER;
break;
}
case 1: {
p = Positions.CENTER_LEFT;
break;
}
case 2: {
p = Positions.CENTER_RIGHT;
break;
}
case 3: {
p = Positions.BOTTOM_CENTER;
break;
}
case 4: {
p = Positions.BOTTOM_LEFT;
break;
}
case 5: {
p = Positions.BOTTOM_RIGHT;
break;
}
case 6: {
p = Positions.TOP_CENTER;
break;
}
case 7: {
p = Positions.TOP_LEFT;
break;
}
case 8: {
p = Positions.TOP_RIGHT;
break;
}
default: {
p = Positions.CENTER;
break;
}
}
return p;
}
public static void main(String[] args) throws Exception {
thumbImage("d:/pdf/1.jpg", 600, 600, "d:/pdf/2.jpg");
crop("d:/pdf/1.jpg", 7, 200, 300, "d:/pdf/2.jpg");
watermark("d:/pdf/1.jpg", "d:/pdf/2.jpg", 7, 1, "d:/pdf/3.jpg");
}
}
4.2 根據模板,填充內容,生成pdf檔案工具類
/**
* @Classname PdfUtils
* @Description TODO
* @Date 2022/5/6 0006 下午 4:40
* @Created by jcc
*/
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;
/**
* Description: PdfUtils <br>
* 依賴的包:itextpdf itext-asian
* commons-io,commons-codec
* @author mk
* @Date 2018-11-2 14:32 <br>
* @Param
* @return
*/
public class PdfUtils {
public static void main(String[] args) throws IOException {
//注意,這裡構建map,key和value都要是String
HashMap map = new HashMap<String, String>();
//姓名
map.put("customerAsex", "陳曉");
// 年齡
map.put("customerAage", "13");
// String path = PdfUtils.class.getResource("/template").getPath();
// System.out.println("path:"+path);
// String sourceFile = path + File.separator + "test.pdf";
//模板檔案
String sourceFile = "C:\\Users\\Administrator\\Desktop\\muban.pdf";
//生成的pdf檔案(自己隨便定義)
String targetFile = "C:\\Users\\Administrator\\Desktop\\test_fill.pdf";
genPdf(map,sourceFile,targetFile);
// System.out.println("獲取pdf表單中的fieldNames:"+getTemplateFileFieldNames(sourceFile));
// System.out.println("讀取⽂件陣列:"+fileBuff(sourceFile));
// System.out.println("pdf轉圖⽚:"+pdf2Img(new File(targetFile),imageFilePath));
}
/*
*
* @Description TOOD
* @param map 我們要填充的內容,key是pdf模板文字域的名稱,value是要填充內容
* @param sourceFile 模板檔案路徑
* @param targetFile 生成的pdf檔案路徑
* @return void
* @date 2022/5/6 0006 下午 5:39
* @author jcc
*/
private static void genPdf(HashMap map, String sourceFile, String targetFile) throws IOException {
File templateFile = new File(sourceFile);
fillParam(map, FileUtils.readFileToByteArray(templateFile), targetFile);
}
/**
* Description: 使⽤map中的引數填充pdf,map中的key和pdf表單中的field對應 <br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static void fillParam(Map<String, String> fieldValueMap, byte[] file, String contractFileName) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(contractFileName);
PdfReader reader = null;
PdfStamper stamper = null;
BaseFont base = null;
try {
reader = new PdfReader(file);
stamper = new PdfStamper(reader, fos);
stamper.setFormFlattening(true);
base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
AcroFields acroFields = stamper.getAcroFields();
for (String key : acroFields.getFields().keySet()) {
acroFields.setFieldProperty(key, "textfont", base, null);
acroFields.setFieldProperty(key, "textsize", new Float(9), null);
}
if (fieldValueMap != null) {
for (String fieldName : fieldValueMap.keySet()) {
acroFields.setField(fieldName, fieldValueMap.get(fieldName));
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stamper != null) {
try {
stamper.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (reader != null) {
reader.close();
}
}
} catch (Exception e) {
System.out.println("填充引數異常");
e.printStackTrace();
} finally {
IOUtils.closeQuietly(fos);
}
}
/**
* Description: 獲取pdf表單中的fieldNames<br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static Set<String> getTemplateFileFieldNames(String pdfFileName) {
Set<String> fieldNames = new TreeSet<String>();
PdfReader reader = null;
try {
reader = new PdfReader(pdfFileName);
Set<String> keys = reader.getAcroFields().getFields().keySet();
for (String key : keys) {
int lastIndexOf = key.lastIndexOf(".");
int lastIndexOf2 = key.lastIndexOf("[");
fieldNames.add(key.substring(lastIndexOf != -1 ? lastIndexOf + 1 : 0, lastIndexOf2 != -1 ? lastIndexOf2 : key.length()));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
}
return fieldNames;
}
/**
* Description: 讀取⽂件陣列<br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static byte[] fileBuff(String filePath) throws IOException {
File file = new File(filePath);
long fileSize = file.length();
if (fileSize > Integer.MAX_VALUE) {
//System.out.println("file too big...");
return null;
}
FileInputStream fi = new FileInputStream(file);
byte[] file_buff = new byte[(int) fileSize];
int offset = 0;
int numRead = 0;
while (offset < file_buff.length && (numRead = fi.read(file_buff, offset, file_buff.length - offset)) >= 0) {
offset += numRead;
}
// 確保所有資料均被讀取
if (offset != file_buff.length) {
throw new IOException("Could not completely read file " + file.getName());
}
fi.close();
return file_buff;
}
/**
* Description: 合併pdf <br>
* @author mk
* @Date 2018-11-2 15:21 <br>
* @Param
* @return
*/
public static void mergePdfFiles(String[] files, String savepath) {
Document document = null;
try {
document = new Document(); //預設A4⼤⼩
PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
document.open();
for (int i = 0; i < files.length; i++) {
PdfReader reader = null;
try {
reader = new PdfReader(files[i]);
int n = reader.getNumberOfPages();
for (int j = 1; j <= n; j++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, j);
copy.addPage(page);
}
} finally {
if (reader != null) {
reader.close();
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//關閉PDF⽂檔流,OutputStream⽂件輸出流也將在PDF⽂檔流關閉⽅法內部關閉
if (document != null) {
document.close();
}
}
}
/**
* pdf轉圖⽚
* @param file pdf
* @return
*/
public static boolean pdf2Img(File file,String imageFilePath) {
try {
//⽣成圖⽚儲存
byte[] data = pdfToPic(PDDocument.load(file));
File imageFile = new File(imageFilePath);
ImageThumbUtils.thumbImage(data, 1, imageFilePath); //按⽐例壓縮圖⽚
System.out.println("pdf轉圖⽚⽂件地址:" + imageFilePath);
return true;
} catch (Exception e) {
System.out.println("pdf轉圖⽚異常:");
e.printStackTrace();
}
return false;
}
/**
* pdf轉圖⽚
* pdf轉圖⽚
*/
private static byte[] pdfToPic(PDDocument pdDocument) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
List<BufferedImage> piclist = new ArrayList<BufferedImage>();
try {
PDFRenderer renderer = new PDFRenderer(pdDocument);
for (int i = 0; i < pdDocument.getNumberOfPages(); i++) {//
// 0 表⽰第⼀頁,300 表⽰轉換 dpi,越⼤轉換後越清晰,相對轉換速度越慢
BufferedImage image = renderer.renderImageWithDPI(i, 108);
piclist.add(image);
}
// 總⾼度 總寬度 臨時的⾼度 , 或儲存偏移⾼度 臨時的⾼度,主要儲存每個⾼度
int height = 0, width = 0, _height = 0, __height = 0,
// 圖⽚的數量
picNum = piclist.size();
// 儲存每個⽂件的⾼度
int[] heightArray = new int[picNum];
// 儲存圖⽚流
BufferedImage buffer = null;
// 儲存所有的圖⽚的RGB
List<int[]> imgRGB = new ArrayList<int[]>();
// 儲存⼀張圖⽚中的RGB資料
int[] _imgRGB;
for (int i = 0; i < picNum; i++) {
buffer = piclist.get(i);
heightArray[i] = _height = buffer.getHeight();// 圖⽚⾼度
if (i == 0) {
// 圖⽚寬度
width = buffer.getWidth();
}
// 獲取總⾼度
height += _height;
// 從圖⽚中讀取RGB
_imgRGB = new int[width * _height];
_imgRGB = buffer.getRGB(0, 0, width, _height, _imgRGB, 0, width);
imgRGB.add(_imgRGB);
}
// 設定偏移⾼度為0
_height = 0;
// ⽣成新圖⽚
BufferedImage imageResult = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] lineRGB = new int[8 * width];
int c = new Color(128, 128, 128).getRGB();
for (int i = 0; i < lineRGB.length; i++) {
lineRGB[i] = c;
}
for (int i = 0; i < picNum; i++) {
__height = heightArray[i];
// 計算偏移⾼度
if (i != 0)
_height += __height;
imageResult.setRGB(0, _height, width, __height, imgRGB.get(i), 0, width); // 寫⼊流中
// 模擬頁分隔
if (i > 0) {
imageResult.setRGB(0, _height + 2, width, 8, lineRGB, 0, width);
}
}
// 寫流
ImageIO.write(imageResult, "jpg", baos);
} catch (Exception e) {
System.out.println("pdf轉圖⽚異常:");
e.printStackTrace();
} finally {
IOUtils.closeQuietly(baos);
try {
pdDocument.close();
} catch (Exception ignore) {
}
}
return baos.toByteArray();
}
}
4.3 測試結果
測試程式碼中,只填了customerAname和customerAage到map中,所以這裡只填入了左邊的某些和年齡