向PDF写入签名日期
前言
需求是要在pdf上进行签字,生成签字日期。签字是使用的第三方信手书工具,但是不会自动生成日期,需要后端在签好字的pdf上将日期填上。
一、导入所需的jar
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.11</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
二、定位日期的位置
定位日期的位置
读取pdf内容,通过方法processContent传入自定义的监听器CustomRenderListener,然后通过监听器获取关键字的位置信息,因为关键字会在多个位置出现,所以存入pdfKeyWordLocationList中,然后将List里面先通过page页码排序,定位到最后一页,再通过Y轴排序,选出最小值(即最下面位置)
import cn.gtmap.estateplat.olcommon.model.PdfKeyWordLocation;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @ClassName : PdfHelper
* @Description :
*/
public class PdfHelper {
/**
* @Description 用于供外部类调用获取关键字所在PDF文件坐标
* @param filepath
* @param keyWords
* @return float[]
*/
public static float[] getKeyWordsByPath(String filepath, String keyWords) {
float[] coordinate = null;
try{
PdfReader pdfReader = new PdfReader(filepath);
coordinate = getKeyWords(pdfReader, keyWords);
} catch (IOException e) {
e.printStackTrace();
}
return coordinate;
}
/**
* @Description 获取关键字所在PDF坐标
* @param pdfReader
* @param keyWords
* @return float[]
*/
public static float[] getKeyWords(PdfReader pdfReader, String keyWords) {
float[] coordinate = new float[3];
List<PdfKeyWordLocation> pdfKeyWordLocationList = new ArrayList<>();
int page = 0;
try{
int pageNum = pdfReader.getNumberOfPages();
PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
CustomRenderListener renderListener = new CustomRenderListener();
renderListener.setKeyWord(keyWords);
for (page = 1; page <= pageNum; page++) {
renderListener.setPage(page);
pdfReaderContentParser.processContent(page, renderListener);
pdfKeyWordLocationList.addAll(renderListener.getPdfKeyWordLocationList());
}
Collections.sort(pdfKeyWordLocationList, (o1, o2) -> {
int num = o2.getPage() - o1.getPage();
if (num == 0) {
return (int) (o1.getY() - o2.getY());
} else {
return num;
}
});
coordinate[0] = pdfKeyWordLocationList.get(0).getX();
coordinate[1] = pdfKeyWordLocationList.get(0).getY();
coordinate[2] = pdfKeyWordLocationList.get(0).getPage();
} catch (IOException e) {
e.printStackTrace();
}
return coordinate;
}
}
实现RenderListener接口,通过方法renderText去获取关键字位置信息
import cn.gtmap.estateplat.olcommon.model.PdfKeyWordLocation;
import com.itextpdf.awt.geom.Rectangle2D.Float;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName : CustomRenderListener
* @Description :
*/
public class CustomRenderListener implements RenderListener {
private List<PdfKeyWordLocation> pdfKeyWordLocationList = new ArrayList<>();
private float[] pcoordinate = null;
private String keyWord;
private int page;
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public float[] getPcoordinate(){
return pcoordinate;
}
public String getKeyWord() {
return keyWord;
}
public void setKeyWord(String keyWord) {
this.keyWord = keyWord;
}
public List<PdfKeyWordLocation> getPdfKeyWordLocationList() {
return pdfKeyWordLocationList;
}
public void setPdfKeyWordLocationList(List<PdfKeyWordLocation> pdfKeyWordLocationList) {
this.pdfKeyWordLocationList = pdfKeyWordLocationList;
}
@Override
public void beginTextBlock() {}
@Override
public void endTextBlock() {}
@Override
public void renderImage(ImageRenderInfo arg0) {}
@Override
public void renderText(TextRenderInfo textRenderInfo) {
String text = textRenderInfo.getText();
if (null != text && text.contains(keyWord)) {
Float boundingRectange = textRenderInfo.getBaseline().getBoundingRectange();
PdfKeyWordLocation pdfKeyWordLocation = new PdfKeyWordLocation();
pdfKeyWordLocation.setX(boundingRectange.x);
pdfKeyWordLocation.setY(boundingRectange.y);
pdfKeyWordLocation.setPage(page);
pdfKeyWordLocationList.add(pdfKeyWordLocation);
}
}
}
根据关键字位置计算出日期位置
private void setFontPosition(PdfContentByte over, String type, float[] f) {
if (StringUtils.equals("hebmmht", type)) {
//设置字体的输出位置
over.setTextMatrix(f[0] + 54.5F, f[1] - 85.0F);
//要输出的text
over.showText(DateTimeFormatter.ofPattern("yyyy年MM月dd日").format(LocalDate.now()));
} else if (StringUtils.equals("hebwxblgy", type)) {
//设置字体的输出位置
over.setTextMatrix(f[0] + 52.5F, f[1] - 23.1F);
//要输出的text
over.showText(DateTimeFormatter.ofPattern("yyyy年MM月dd日").format(LocalDate.now()));
} else if (StringUtils.equals("hebwxbldd", type)) {
//设置字体的输出位置
over.setTextMatrix(f[0] + 52.5F, f[1] - 23.1F);
//要输出的text
over.showText(DateTimeFormatter.ofPattern("yyyy年MM月dd日").format(LocalDate.now()));
} else if (StringUtils.equals("hebsqs", type)) {
LocalDate localDate = LocalDate.now();
//设置字体的输出位置
over.setTextMatrix(f[0], f[1] - 46.2F);
//要输出的text
over.showText(DateTimeFormatter.ofPattern("yyyy").format(localDate));
//设置字体的输出位置
over.setTextMatrix(f[0] + 60.5F, f[1] - 46.2F);
//要输出的text
over.showText(DateTimeFormatter.ofPattern("MM").format(localDate));
//设置字体的输出位置
over.setTextMatrix(f[0] + 115.0F, f[1] - 46.2F);
//要输出的text
over.showText(DateTimeFormatter.ofPattern("dd").format(localDate));
}
}
向pdf中写入日期
private void writePdfDate(String fileName, String userName, String type) {
PdfReader reader = null;
try {
reader = new PdfReader(fileName);
fileName = fileName.substring(0, fileName.lastIndexOf("_")) + "_" + DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()) + ".pdf";
//根据一个pdfreader创建一个pdfStamper.用来生成新的pdf.
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(fileName));
//这个字体是itext-asian.jar中自带的 所以不用考虑操作系统环境问题.
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); // set font
//baseFont不支持字体样式设定.但是font字体要求操作系统支持此字体会带来移植问题.
Font font = new Font(bf,10);
font.setStyle(Font.BOLD);
font.getBaseFont();
float[] f = PdfHelper.getKeyWords(reader, userName);
int page = (int) f[2];
//获得pdfstamper在当前页的上层打印内容.也就是说 这些内容会覆盖在原先的pdf内容之上.
PdfContentByte over = stamper.getOverContent(page);
//开始写入文本
over.beginText();
//设置字体和大小
over.setFontAndSize(font.getBaseFont(), 10);
//设置字体颜色
over.setColorFill(BaseColor.RED);
//设置文字的位置
setFontPosition(over, type, f);
over.endText();
stamper.close();
} catch (IOException | DocumentException e) {
e.printStackTrace();
}
}