Java 實現給pdf文件指定位置蓋章功能
開發中遇到一個需求, 需要給用戶上傳的的pdf文件, 指定位置上蓋公章的功能, 經過調研和對比, 最終確定實現思路.
這里是使用pdf文件中的關鍵字進行章子的定位, 之所以這樣考慮是因為如果直接寫死坐標的話, 可能會出現因pdf大小, 縮放, 蓋章位置變更的原因, 導致公章位置錯位. 所以選擇了根據關鍵字定位的方式.
下面列出具體的實現方式:
-
使用的是Java語言, 使用Maven管理依賴, 下面是操作pdf所依賴的庫的坐標
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.12</version> </dependency> <dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version> </dependency>
-
下面是具體的代碼邏輯
-
CustomRenderListener, 自定義渲染監聽器, 實現查找關鍵字自有邏輯
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 lombok.Data;/*** pdf關鍵詞幫助類** @author wdhcr*/ @Data public class CustomRenderListener implements RenderListener {// 坐標private float[] coordinate = null;// 關鍵字private String keyWord;// pdf當前頁private int page;@Overridepublic void beginTextBlock() {}@Overridepublic void endTextBlock() {}@Overridepublic void renderImage(ImageRenderInfo arg0) {}@Overridepublic void renderText(TextRenderInfo textRenderInfo) {String text = textRenderInfo.getText();if (null != text && text.contains(keyWord)) {Float boundingRange = textRenderInfo.getBaseline().getBoundingRectange();coordinate = new float[3];coordinate[0] = boundingRange.x;coordinate[1] = boundingRange.y;coordinate[2] = page;}} }
-
獲取關鍵字坐標的工具類
import com.itextpdf.text.Image; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfGState; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import com.itextpdf.text.pdf.parser.PdfReaderContentParser; import com.jkwl.common.exception.BaseException; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j;import java.io.*;/*** Pdf定位工具類* @author wdhcr*/ @Slf4j public class PdfUtils {/*** 獲取關鍵字所在PDF坐標** @param pdfReader 流* @param keyWords 關鍵詞* @return float[] 坐標*/public static float[] getKeyWords(PdfReader pdfReader, String keyWords) {float[] coordinate = null;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);coordinate = renderListener.getCoordinate();if (coordinate != null) {break;}}} catch (IOException e) {e.printStackTrace();}return coordinate;}@SneakyThrowspublic static void stampToPdf(InputStream pdfInputStream, String keyWords, InputStream sealInputStream, OutputStream outputStream) {byte[] sealBytes = sealInputStream.readAllBytes();PdfReader reader = new PdfReader(pdfInputStream);float[] xyz = PdfUtils.getKeyWords(reader, keyWords);if (xyz == null) {throw new BaseException("未找到蓋章位置");}PdfStamper stamper = new PdfStamper(reader, outputStream);// 將印章圖片放在pdf文件的第?頁PdfContentByte over = stamper.getOverContent((int) xyz[2]);// 需要插入的圖片Image contractSealImg = Image.getInstance(sealBytes);// 保存狀態over.saveState();// 圖片處理PdfGState pdfGState = new PdfGState();// 給圖片設置透明度,一般不需要pdfGState.setFillOpacity(0.8F);over.setGState(pdfGState);contractSealImg.setAbsolutePosition(xyz[0] + 50, xyz[1] - 40);// 設置圖片大小contractSealImg.scaleAbsolute(100, 100);// 將圖片添加到pdf文件over.addImage(contractSealImg);over.restoreState();stamper.setFormFlattening(true);// 關閉流stamper.close();reader.close();}}
-
測試demo
@SneakyThrowspublic static void main(String[] args) {FileInputStream pdfInputStream = new FileInputStream("/Users/Desktop/報告模版.pdf");FileInputStream sealInputStream = new FileInputStream("/Users/Desktop/dbd.png");FileOutputStream fileOutputStream = new FileOutputStream("/Users/Desktop/報告模版蓋章.pdf");// 關鍵字為: 簽發日期PdfUtils.stampToPdf(pdfInputStream, "簽發日期", sealInputStream, fileOutputStream);fileOutputStream.close();pdfInputStream.close();sealInputStream.close();System.out.println("蓋章完成");}
-
公章如圖所示
-
報告模版如下:
-
蓋完章后
-