今天接到一個需求,需要在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 {// 讀取原始PDFPdfReader 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() {@Overridepublic void beginTextBlock() {}@Overridepublic void endTextBlock() {}@Overridepublic 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));}@Overridepublic 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、可以看到簽名照片已經成功加上了