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; @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 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; } @SneakyThrows public 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
@SneakyThrows public 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("盖章完成"); }
-
公章如图所示
-
报告模版如下:
-
盖完章后
-