Java实现pdf中动态插入图片
今天接到一个需求,需要在pdf中的签名处,插入签名照片,但签名位置不固定,话不多说上代码:
1、首先引入itextpdf依赖包:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
2、具体实现逻辑如下:
/**
* description PDF插入图片(根据关键字位置动态插入)
*
* @author yanzy
* @version 1.0
* @date 2025/3/27 17:26
*/
public static void imgToPdf2(String pdfPath, String imagePath, String outputPath, String keyword) {
try {
// 读取原始PDF
PdfReader reader = new PdfReader(pdfPath);
FileOutputStream fos = new FileOutputStream(outputPath);
PdfStamper stamper = new PdfStamper(reader, fos);
// 遍历PDF每一页,查找关键字并插入签名图片
Boolean keyBool = true;
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
// 获取当前页面的文本和坐标信息
List<Position> positions = getPositions(reader, i);
// 合并连续文本块
StringBuilder combinedText = new StringBuilder();
List<Position> textChunks = new ArrayList<>();
for (Position pos : positions) {
combinedText.append(pos.getText());
textChunks.add(pos);
}
// 查找关键字在整个文本中的位置
String fullText = combinedText.toString();
int index = fullText.indexOf(keyword);
if (index != -1) {
// 获取关键字起始位置
Position endPos = findPositionByIndex(textChunks, index + keyword.length() - 1);
// 计算插入坐标(取结束位置右侧)
float imgX = endPos.getX() + 20; // 横纵标,右侧偏移20单位
float imgY = endPos.getY() - 20; // 纵坐标,向下移动20单位
log.info("关键字位置 -> X:{} Y: {} | 图片位置 -> X: {} Y:{}", endPos.getX(), endPos.getY(), imgX, imgY);
// 添加图片
Image img = Image.getInstance(imagePath);
// 图片尺寸
img.scaleToFit(100, 50);
// 设置图片的插入位置(X,Y坐标)
img.setAbsolutePosition(imgX, imgY);
// PdfStamper:直接修改原始PDF,避免图层顺序问题
PdfContentByte canvas = stamper.getOverContent(i);
canvas.addImage(img);
keyBool = false;
}
}
if (keyBool) {
throw new Exception("未找到关键字位置!");
}
stamper.close();
reader.close();
log.info("图片插入成功!");
} catch (Exception e) {
e.printStackTrace();
log.error("pdf插入图片失败! errMsg: {}", e.getMessage());
}
}
/**
* description 根据文本索引找到对应位置
*
* @author yanzy
* @version 1.0
* @date 2025/3/27 17:26
*/
private static Position findPositionByIndex(List<Position> chunks, int targetIndex) {
int currentIndex = 0;
for (Position chunk : chunks) {
int chunkLength = chunk.getText().length();
if (currentIndex + chunkLength > targetIndex) {
return chunk;
}
currentIndex += chunkLength;
}
return chunks.get(chunks.size() - 1);
}
/**
* description 获取PDF页面的所有文本位置
*
* @author yanzy
* @version 1.0
* @date 2025/3/27 17:26
*/
private static List<Position> getPositions(PdfReader reader, int pageNumber) throws Exception {
List<Position> positions = new ArrayList<>();
// 创建PdfContentByte和RenderListener来提取文本
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
parser.processContent(pageNumber, new RenderListener() {
@Override
public void beginTextBlock() {
}
@Override
public void endTextBlock() {
}
@Override
public void renderText(TextRenderInfo renderInfo) {
String text = renderInfo.getText();
float x = renderInfo.getBaseline().getStartPoint().get(0);
float y = renderInfo.getBaseline().getStartPoint().get(1);
positions.add(new Position(x, y, text));
}
@Override
public void renderImage(ImageRenderInfo renderInfo) {
}
});
return positions;
}
public static void main(String[] args) {
// 输入PDF路径
String srcPdf = "E://test.pdf";
// 输出PDF路径
String destPdf = "E://output_image.pdf";
// 图片路径
String imagePath = "E://test.jpg";
// 关键字
String keyword = "本人签名:";
//imgToPdf(srcPdf, imagePath, destPdf);
imgToPdf2(srcPdf, imagePath, destPdf, keyword);
}
/**
* description pdf中的文本坐标
*
* @author yanzy
* @date 2025/3/28 15:36
*/
public class Position {
private final float x;
private final float y;
private final String text;
public Position(float x, float y, String text) {
this.x = x;
this.y = y;
this.text = text;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public String getText() {
return text;
}
}
3、下面是pdf的内容:
4、运行程序后的结果:
5、可以看到签名照片已经成功加上了