先利用Adobe acrobat pro DC对pdf进行表单制作,再通过利用java对模板数据进行填充,并生成新的pdf
下载地址参考:Adobe acrobat pro DC2018解决方案
com.itextpdf
itextpdf
5.5.10
com.itextpdf
itext-asian
5.2.0
import cn.hutool.core.collection.CollUtil;
import com.intellsite.digital.dto.SealPosition;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
/**
* desc: pdf 生成工具
*
* @author qts
* @date 2022/3/18 0018
*/
@Slf4j
public class PdfGenerateUtil {
private PdfGenerateUtil() {
}
/**
* 获取字段对应的坐标信息
* {@link com.intellsite.digital.dto.SealPosition}
中只返回了:页码和x,y坐标
*
* @param templatePdfByteArray 模板pdf字节数组
* @param paramsName 参数名称
* @return 映射 key:字段名 value:坐标信息
*/
public static Map getPositions(byte[] templatePdfByteArray, Set paramsName) {
PdfReader reader = null;
ByteArrayOutputStream bos = null;
try {
Map sealMap = new HashMap();
//创建书写器,用于往document中书写信息
// 通过本地文件路径获取资源
reader = new PdfReader(templatePdfByteArray);
bos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, bos);
// pdf表单字段
AcroFields form = stamper.getAcroFields();
// 通过名字获取位置
SealPosition sealPosition;
for (String name : paramsName) {
List positions = form.getFieldPositions(name);
if (CollUtil.isEmpty(positions)) {
sealMap.put(name, null);
continue;
}
// 页码
int pageNo = positions.get(0).page;
// 矩形
Rectangle rectangle = positions.get(0).position;
// x/y坐标
BigDecimal right = new BigDecimal(String.valueOf(rectangle.getRight()));
BigDecimal left = new BigDecimal(String.valueOf(rectangle.getLeft()));
BigDecimal top = new BigDecimal(String.valueOf(rectangle.getTop()));
BigDecimal bottom = new BigDecimal(String.valueOf(rectangle.getBottom()));
float x = right.subtract(left).divide(new BigDecimal("2"),3,BigDecimal.ROUND_HALF_UP).floatValue();
float y = top.subtract(bottom).divide(new BigDecimal("2"),3,BigDecimal.ROUND_HALF_UP).floatValue();
sealPosition = new SealPosition().setPageNum(pageNo).setPosX(x).setPosY(y);
sealMap.put(name, sealPosition);
}
stamper.setFormFlattening(false);
stamper.close();
return sealMap;
} catch (Exception e) {
log.error("通过模板生成PDF失败", e.getMessage());
return null;
} finally {
try {
if (null != reader) {
reader.close();
}
if (null != bos) {
bos.close();
}
} catch (IOException e) {
log.error("close resource error", e.getMessage());
}
}
}
/**
* 生成填充了模板参数的pdf
*
* @param templatePdfInputStream 模板pdf流
* @param paramsMap 填充参数
* @return
*/
public static byte[] generatePdf(InputStream templatePdfInputStream,Map paramsMap) throws IOException {
byte[] templatePdfByteArray = readBytes(templatePdfInputStream);
return generatePdf(templatePdfByteArray, paramsMap);
}
/**
* 生成填充了模板参数的pdf
*
* @param templatePdfByteArray 模板pdf字节数组
* @param paramsMap 填充参数
* @return
*/
public static byte[] generatePdf(byte[] templatePdfByteArray, Map paramsMap) {
PdfReader reader = null;
ByteArrayOutputStream bos = null;
try {
//创建书写器,用于往document中书写信息
// 通过本地文件路径获取资源
reader = new PdfReader(templatePdfByteArray);
bos = new ByteArrayOutputStream();
PdfStamper stamper = new PdfStamper(reader, bos);
//使用中文字体
BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
ArrayList fontList = new ArrayList<>();
fontList.add(baseFont);
AcroFields form = stamper.getAcroFields();
form.setSubstitutionFonts(fontList);
for (String fieldName : paramsMap.keySet()) {
if (paramsMap.get(fieldName) == null) {
continue;
}
if (fieldName.indexOf("Image") > 0) {
String imgPath = paramsMap.get(fieldName).toString();
int pageNo = form.getFieldPositions(fieldName).get(0).page;
Rectangle rectangle = form.getFieldPositions(fieldName).get(0).position;
float x = rectangle.getLeft();
float y = rectangle.getTop();
//根据路径读取图片
Image image = Image.getInstance(imgPath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
//添加图片
image.setAbsolutePosition(x, y - rectangle.getHeight());
under.addImage(image);
} else {
// 设置占位字段
form.setField(fieldName, paramsMap.get(fieldName).toString());
}
}
stamper.setFormFlattening(false);
stamper.close();
} catch (Exception e) {
log.error("通过模板生成PDF失败", e.getMessage());
return null;
} finally {
try {
if (null != reader) {
reader.close();
}
if (null != bos) {
bos.close();
}
} catch (IOException e) {
log.error("close resource error", e.getMessage());
}
}
return bos.toByteArray();
}
/**
* 读取输入流到字节数组
*
* @param in
* @return
* @throws IOException
*/
private static byte[] readBytes(InputStream in) throws IOException {
//读取字节的缓冲
byte[] buffer = new byte[1024];
//最终的数据
byte[] result = new byte[0];
int size = 0;
while ((size = in.read(buffer)) != -1) {
int oldLen = result.length;
byte[] tmp = new byte[oldLen + size];
if (oldLen > 0) {//copy 旧字节
System.arraycopy(result, 0, tmp, 0, oldLen);
}
//copy 新字节
System.arraycopy(buffer, 0, tmp, oldLen, size);
result = tmp;
}
return result;
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @description: 签章位置信息
* @author: wkh
* @create: 2022-03-17 11:29
*/
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SealPosition {
/**
* 签章id
*/
private Long sealId;
/**
* x
*/
private Float posX;
/**
* y
*/
private Float posY;
/**
* 关键字
*/
private String keyword;
/**
* 页码
*/
private int pageNum;
}
InputStream pdfInputStream = null;
try {
// pdf模板
pdfInputStream = new FileInputStream("D:\\监理日志模板.pdf");
// 设置pdf模板参数 engineeringLog为实体类,其中的字段对应pdf表单中的字段名称
JSONObject paramsMap = JSONObject.parseObject(JSON.toJSONString(engineeringLog));
paramsMap.put("dairyDate", DateUtil.format(engineeringLog.getDairyDate(),"yyyy年MM月dd日"));
// 生成pdf字节数组
byte[] pdf = PdfGenerateUtil.generatePdf(pdfInputStream, paramsMap);
// 准换成MultipartFile
MultipartFile multipartFile = new MockMultipartFile("file","模板.pdf","text/plain", pdf);
// todo 后续处理 ,可以上传到文件服务器或其他操作
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (null != pdfInputStream) {
pdfInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}