Java 实现给pdf文件指定位置盖章功能

Java 实现给pdf文件指定位置盖章功能

开发中遇到一个需求, 需要给用户上传的的pdf文件, 指定位置上盖公章的功能, 经过调研和对比, 最终确定实现思路.

这里是使用pdf文件中的关键字进行章子的定位, 之所以这样考虑是因为如果直接写死坐标的话, 可能会出现因pdf大小, 缩放, 盖章位置变更的原因, 导致公章位置错位. 所以选择了根据关键字定位的方式.

下面列出具体的实现方式:

  1. 使用的是Java语言, 使用Maven管理依赖, 下面是操作pdf所依赖的库的坐标

    xml 复制代码
    <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>
  2. 下面是具体的代码逻辑

    • CustomRenderListener, 自定义渲染监听器, 实现查找关键字自有逻辑

      java 复制代码
      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;
              }
          }
      }
    • 获取关键字坐标的工具类

      java 复制代码
      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

      java 复制代码
          @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("盖章完成");
      
          }
    • 公章如图所示

    • 报告模版如下:

    • 盖完章后

相关推荐
Hui Baby5 小时前
springAi+MCP三种
java
hsjcjh5 小时前
【MySQL】C# 连接MySQL
java
敖正炀5 小时前
LinkedBlockingDeque详解
java
wangyadong3175 小时前
datagrip 链接mysql 报错
java
untE EADO5 小时前
Tomcat的server.xml配置详解
xml·java·tomcat
ictI CABL5 小时前
Tomcat 乱码问题彻底解决
java·tomcat
敖正炀5 小时前
DelayQueue 详解
java
敖正炀5 小时前
PriorityBlockingQueue 详解
java
shark22222225 小时前
Spring 的三种注入方式?
java·数据库·spring
陈煜的博客6 小时前
idea 项目只编译不打包,跳过测试,快速开发
java·ide·intellij-idea