一、前言
项目以前签字都是由C端那边进行合成操作,最近项目要求把那块功能,由后端进行实现,其中包含坐标、关键字、任意位置进行签字操作,坐标是最容易实现的,曾经也写过类似的功能在(添加图片印章到PDF)直接复用就可以了
为了实现关键字位置签字,在网上查找了挺多资料的,感觉能满足功能的代码参考地址:Itext7获取关键字在文件中的坐标
在他这基础上我进行了优化
二、使用JAR包
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.0</version>
<type>pom</type>
</dependency>
三、实现代码
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
public class PDFKeywordFinder {
public static Map<String, Object> getKeywordLocation(ByteArrayInputStream bytes, String keyword) {
Map<String, Object> result = new HashMap<>();
//使用这种方式,无需再关闭了,处理完自动关闭
try (PdfReader reader = new PdfReader(bytes); PdfDocument pdfDocument = new PdfDocument(reader)) {
for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
PdfPage page = pdfDocument.getPage(i);
RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(keyword);
PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
canvasProcessor.processPageContent(page);
Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();
// 自定义结果处理
if (!resultantLocations.isEmpty()) {
List<Map<String, Object>> locationList = new ArrayList<>();
for (IPdfTextLocation item : resultantLocations) {
Map<String, Object> map = new HashMap<>();
Rectangle rectangle = item.getRectangle();
map.put("page", item.getPageNumber());
map.put("absoluteX", rectangle.getX());
map.put("absoluteY", rectangle.getY());
map.put("width", rectangle.getWidth());
map.put("height", rectangle.getHeight());
map.put("keyword", item.getText());
map.put("top", rectangle.getTop());
map.put("bottom", rectangle.getBottom());
map.put("left", rectangle.getLeft());
map.put("right", rectangle.getRight()); // 右坐标
map.put("count", locationList.size() + 1); // 出现次数
locationList.add(map);
}
result.put(String.valueOf(i), locationList);
}
}
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
四、测试用例
本地测试用了文件转内存流方式,如果需要加盖电子印章,可以把签字图片替换成电子印章图片
我这没用到签名密钥,如果需要可以自行添加,或者找其它的处理方式
//引入包信息
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfStamper;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
public static void main(String[] args) throws IOException, DocumentException {
String filePath = "E:\\test.pdf";
String keyword = "签收人"; // 要查找的关键字
ByteArrayOutputStream memoryStream = readFileToMemoryStream(filePath);
Map<String, Object> map = getKeywordLocation(new ByteArrayInputStream(memoryStream.toByteArray()), keyword);
com.itextpdf.text.pdf.PdfReader pdfReader = new com.itextpdf.text.pdf.PdfReader(memoryStream.toByteArray());
PdfStamper pdfStamper = new PdfStamper(pdfReader, Files.newOutputStream(Paths.get("E:\\文书.pdf")));
com.itextpdf.text.Image image = Image.getInstance("E:\\sign.png");
//设置签字图片宽高
image.scaleAbsolute(100, 50);
//我直接在第一页操作,也可以根据返回的数据进行操作
JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(map.get("1")));
JSONObject jsonObject = jsonArray.getJSONObject(0);
//这个位置主要是插入签名图片位置坐标,也可以根据情况自行调整取值
float absoluteX = Float.parseFloat(jsonObject.getString("absoluteX")) - Float.parseFloat(jsonObject.getString("width"));
float absoluteY = Float.parseFloat(jsonObject.getString("absoluteY")) - (Float.parseFloat(jsonObject.getString("width")) + Float.parseFloat(jsonObject.getString("height")));
image.setAbsolutePosition(absoluteX, absoluteY);
PdfContentByte content = pdfStamper.getUnderContent(1);
content.addImage(image);
pdfStamper.close();
}
private static ByteArrayOutputStream readFileToMemoryStream(String filePath) throws IOException {
ByteArrayOutputStream memoryStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024]; // 缓冲区大小
try (FileInputStream fis = new FileInputStream(filePath)) {
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
memoryStream.write(buffer, 0, bytesRead);
}
}
return memoryStream;
}