Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

JAVA替换PDF文字

北漂追梦人 2019-06-12 03:34:00 阅读数:75 评论数:0 点赞数:0 收藏数:0

前言:

  以下是通过网上查阅资料,东拼西凑实现的一个使用java替换pdf文字的功能。使用的是itextpdf.jar

参考:

  https://blog.csdn.net/sdizoea/article/details/75105798

  https://blog.csdn.net/sishenkankan/article/details/53107195

具体实现:

  1.引入jar包

 <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itextpdf</artifactId>
      <version>5.5.13</version>
 </dependency>
 <dependency>
      <groupId>com.itextpdf</groupId>
      <artifactId>itext-asian</artifactId>
      <version>5.2.0</version>
 </dependency>

  2.编写实现类

    实现类主要有三个类。

    一个是用来保存关键字信息的实体类MatchItem;

    一个是匹配关键字的监听类KeyWordPositionListener;

    最后一个是查找关键字、关键字替换的实现类PdfUtils。

  具体代码如下:

  MatchItem实体类

 /**
  * 用来保存关键字信息
  */
 public class MatchItem {
 
     //页数
     private Integer pageNum;
     //x坐标
     private Float x;
     //y坐标
     private Float y;
     //页宽
     private Float pageWidth;
     //页高
     private Float pageHeight;
     //匹配字符
     private String content;
     //字体宽
     private float fontWidth;
     //字体高
     private float fontHeight = 12;
 
     public Integer getPageNum() {
         return pageNum;
     }
 
     public void setPageNum(Integer pageNum) {
         this.pageNum = pageNum;
     }
 
     public Float getX() {
         return x;
     }
 
     public void setX(Float x) {
         this.x = x;
     }
 
     public Float getY() {
         return y;
     }
 
     public void setY(Float y) {
         this.y = y;
     }
 
     public Float getPageWidth() {
         return pageWidth;
     }
 
     public void setPageWidth(Float pageWidth) {
         this.pageWidth = pageWidth;
     }
 
     public Float getPageHeight() {
         return pageHeight;
     }
 
     public void setPageHeight(Float pageHeight) {
         this.pageHeight = pageHeight;
     }
 
     public String getContent() {
         return content;
     }
 
     public void setContent(String content) {
         this.content = content;
     }
 
     public float getFontWidth() {
         return fontWidth;
     }
 
     public void setFontWidth(float fontWidth) {
         this.fontWidth = fontWidth;
     }
 
     public float getFontHeight() {
         return fontHeight;
     }
 
     public void setFontHeight(float fontHeight) {
         this.fontHeight = fontHeight;
     }
 
     @Override
     public String toString() {
         return "MatchItem{" +
                 "pageNum=" + pageNum +
                 ", x=" + x +
                 ", y=" + y +
                 ", pageWidth=" + pageWidth +
                 ", pageHeight=" + pageHeight +
                 ", content='" + content + '\'' +
                 '}';
     }
 }

  

  KeyWordPositionListener监听类

 import com.itextpdf.awt.geom.Rectangle2D;
 import com.itextpdf.text.Rectangle;
 import com.itextpdf.text.pdf.parser.ImageRenderInfo;
 import com.itextpdf.text.pdf.parser.RenderListener;
 import com.itextpdf.text.pdf.parser.TextRenderInfo;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /**
  * 用来匹配pdf的关键词 监听类
  */
 public class KeyWordPositionListener implements RenderListener {
 
     //存放匹配上的字符信息
     private List<MatchItem> matches = new ArrayList<MatchItem>();
     //存放所有的字符信息
     private List<MatchItem> allItems = new ArrayList<MatchItem>();
 
     private Rectangle curPageSize;
 
     /**
      * 匹配的关键字
      */
     private String keyword;
     /**
      * 匹配的当前页
      */
     private Integer pageNumber;
 
     @Override
     public void beginTextBlock() {
         //do nothing
     }
 
     @Override
     public void renderText(TextRenderInfo renderInfo) {
         //获取字符
         String content = renderInfo.getText();
         Rectangle2D.Float textRectangle = renderInfo.getDescentLine().getBoundingRectange();
 
         MatchItem item = new MatchItem();
         item.setContent(content);
         item.setPageNum(pageNumber);
         item.setFontHeight(textRectangle.height == 0 ? 12:textRectangle.height);//默认12
         item.setFontWidth(textRectangle.width);
         item.setPageHeight(curPageSize.getHeight());
         item.setPageWidth(curPageSize.getWidth());
         item.setX((float)textRectangle.getX());
         item.setY((float)textRectangle.getY());
 
         //若keyword是单个字符,匹配上的情况
         if(content.equalsIgnoreCase(keyword)) {
             matches.add(item);
         }
         //保存所有的项
         allItems.add(item);
     }
 
     @Override
     public void endTextBlock() {
         //do nothing
     }
 
     @Override
     public void renderImage(ImageRenderInfo renderInfo) {
         //do nothing
     }
 
     /**
      * 设置需要匹配的当前页
      * @param pageNumber
      */
     public void setPageNumber(Integer pageNumber) {
         this.pageNumber = pageNumber;
     }
 
     /**
      * 设置需要匹配的关键字,忽略大小写
      * @param keyword
      */
     public void setKeyword(String keyword) {
         this.keyword = keyword;
     }
 
     /**
      * 返回匹配的结果列表
      * @return
      */
     public List<MatchItem> getMatches() {
         return matches;
     }
 
     void setCurPageSize(Rectangle rect) {
         this.curPageSize = rect;
     }
 
     public List<MatchItem> getAllItems() {
         return allItems;
     }
 
     public void setAllItems(List<MatchItem> allItems) {
         this.allItems = allItems;
     }
 
 }

 

  PdfUtils核心功能实现类

 import com.itextpdf.text.BaseColor;
 import com.itextpdf.text.Font;
 import com.itextpdf.text.Rectangle;
 import com.itextpdf.text.pdf.BaseFont;
 import com.itextpdf.text.pdf.PdfContentByte;
 import com.itextpdf.text.pdf.PdfReader;
 import com.itextpdf.text.pdf.PdfStamper;
 import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
 
 import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 /**
  * pdf替换文字工具类
  *
  * 思路:
  * 1.逐页搜索关键字,逐页匹配
  * 2.先读取一页的所有字符信息,存放到allItems中
  * 3.把一页的字符拼接成字符串,然后匹配关键字,匹配上,记录匹配的第一个字符的MatchItem信息;匹配不是,继续下一页匹配
  * 4.根据匹配字符串的长度和字符的宽高信息画遮罩层,然后替换文字生成新的pdf文件
  *
  * 不足之处:
  * 1.目前只支持单字符串匹配
  * 2.替换之后的文字无法和原pdf中替换掉的文字信息一致(主要有:字体大小、样式等)
  * 3.某些情况下(主要是替换字体的大小)替换之后显示不是太整齐
  * 4.字体大小、样式无法把控
  * 5.无法匹配目标文字在两页中显示的情况(例如:目标文字:替换工具,第一页页尾有替换两字,第二页页首有工具二字)
  *
  */
 public class PdfUtils {
 
     public static void main(String[] args) throws Exception{
 //        List<MatchItem> matchItems = matchPage("C:\\Users\\Desktop\\pdftest.pdf", "系统");
 //        for(MatchItem m : matchItems){
 //            System.out.println(m);
 //        }
 //        manipulatePdf("C:\\Users\\Desktop\\pdftest.pdf","C:\\Users\\Desktop\\pdftest_new.pdf",matchItems,"系统");
         String src = "C:\\\\Users\\\\Desktop\\\\pdftest.pdf";
         String dest = "C:\\\\Users\\\\Desktop\\\\pdftest_new.pdf";
         String keyWord = "登陆";
         String keyWordNew = "测试";
         pdfReplace(src,dest,keyWord,keyWordNew);
     }
 
     /**
      * 根据关键字和pdf路径,全文搜索关键字
      * @param filePath pdf目标路径
      * @param keyword 关键字
      * @return
      * @throws Exception
      */
     public static List<MatchItem> matchAll(String filePath, String keyword) throws Exception {
         List<MatchItem> items = new ArrayList<MatchItem>();
         PdfReader reader = new PdfReader(filePath);
         //获取pdf页数
         int pageSize = reader.getNumberOfPages();
         //逐页匹配关键字
         for(int page = 1;page <= pageSize;page++){
             items.addAll(matchPage(reader,page,keyword));
         }
         return items;
     }
 
     /**
      * 根据关键字、文档路径、pdf页数寻找特定的文件内容
      * @param reader
      * @param pageNumber 页数
      * @param keyword 关键字
      * @return
      * @throws Exception
      */
     public static List<MatchItem> matchPage(PdfReader reader, Integer pageNumber,String keyword) throws Exception {
         PdfReaderContentParser parse = new PdfReaderContentParser(reader);
         Rectangle rectangle = reader.getPageSize(pageNumber);
         //匹配监听
         KeyWordPositionListener renderListener = new KeyWordPositionListener();
         renderListener.setKeyword(keyword);
         renderListener.setPageNumber(pageNumber);
         renderListener.setCurPageSize(rectangle);
         parse.processContent(pageNumber, renderListener);
         return findKeywordItems(renderListener,keyword);
     }
 
     /**
      * 找到匹配的关键词块
      * @param renderListener
      * @param keyword
      * @return
      */
     public static List<MatchItem> findKeywordItems(KeyWordPositionListener renderListener,String keyword){
         //先判断本页中是否存在关键词
         List<MatchItem> allItems = renderListener.getAllItems();//所有块LIST
         StringBuffer sbtemp = new StringBuffer("");
 
         for(MatchItem item : allItems){//将一页中所有的块内容连接起来组成一个字符串。
             sbtemp.append(item.getContent());
         }
 
         List<MatchItem> matches = renderListener.getMatches();
 
         //一页组成的字符串没有关键词,直接return
         //第一种情况:关键词与块内容完全匹配的项,直接返回
         if(sbtemp.toString().indexOf(keyword) == -1 || matches.size() > 0){
             return matches;
         }
         //第二种情况:多个块内容拼成一个关键词,则一个一个来匹配,组装成一个关键词
         sbtemp = new StringBuffer("");
         List<MatchItem> tempItems = new ArrayList();
         for(MatchItem item : allItems){
             if(keyword.indexOf(item.getContent()) != -1 ){
                 tempItems.add(item);
                 sbtemp.append(item.getContent());
 
                 if(keyword.indexOf(sbtemp.toString()) == -1){//如果暂存的字符串和关键词 不再匹配时
                     sbtemp = new StringBuffer(item.getContent());
                     tempItems.clear();
                     tempItems.add(item);
                 }
 
                 if(sbtemp.toString().equalsIgnoreCase(keyword)){//暂存的字符串正好匹配到关键词时
                     matches.add(tempItems.get(0));//得到匹配的项
                     sbtemp = new StringBuffer("");//清空暂存的字符串
                     tempItems.clear();//清空暂存的LIST
                     continue;//继续查找
                 }
             }else{//如果找不到则清空
                 sbtemp = new StringBuffer("");
                 tempItems.clear();
             }
         }
         return matches;
     }
 
     /**
      * 替换目标文字,生成新的pdf文件
      * @param src 目标pdf路径
      * @param dest 新pdf的路径
      * @throws Exception
      */
     public static void manipulatePdf(String src,String dest,List<MatchItem> matchItems,String keyWord,String keyWordNew) throws Exception{
         PdfReader reader = new PdfReader(src);
         PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
         PdfContentByte canvas = null;
         Map<Integer,List<MatchItem>> mapItem = new HashMap<Integer,List<MatchItem>>();
         List<MatchItem> itemList = null;
         for(MatchItem item : matchItems){
             Integer pageNum = item.getPageNum();
             if(mapItem.containsKey(pageNum)){
                 itemList = mapItem.get(pageNum);
                 itemList.add(item);
                 mapItem.put(pageNum,itemList);
             }else{
                 itemList = new ArrayList<MatchItem>();
                 itemList.add(item);
                 mapItem.put(pageNum,itemList);
             }
         }
         //遍历每一页去修改
         for(Integer page : mapItem.keySet()){
             List<MatchItem> items = mapItem.get(page);
             //遍历每一页中的匹配项
             for(MatchItem item : items){
                 canvas = stamper.getOverContent(page);
                 float x = item.getX();
                 float y = item.getY();
                 float fontWidth = item.getFontWidth();
                 float fontHeight = item.getFontHeight();
                 canvas.saveState();
                 canvas.setColorFill(BaseColor.WHITE);
                 canvas.rectangle(x, y,fontWidth*keyWord.length(),fontWidth+2);
                 canvas.fill();
                 canvas.restoreState();
                 //开始写入文本
                 canvas.beginText();
                 BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
                 Font font = new Font(bf,fontWidth,Font.BOLD);
                 //设置字体和大小
                 canvas.setFontAndSize(font.getBaseFont(), fontWidth);
                 //设置字体的输出位置
                 canvas.setTextMatrix(x, y+fontWidth/10+0.5f);
                 //要输出的text
                 canvas.showText(keyWordNew);
 
                 canvas.endText();
             }
         }
         stamper.close();
         reader.close();
         System.out.println("complete");
     }
 
     /**
      * 替换pdf中指定文字
      * @param src 目标pdf路径
      * @param dest 新pdf的路径
      * @param keyWord 替换的文字
      * @param keyWordNew 替换后的文字
      * @throws Exception
      */
     public static void pdfReplace(String src,String dest,String keyWord,String keyWordNew) throws Exception{
         manipulatePdf(src,dest,matchAll(src,keyWord),keyWord,keyWordNew);
     }
 }

 

  PS:以上就是功能所有实现,不足之处和适应场景程序备注里面已详细说明,每个方法的作用及参数说明也都在程序中备注说明。

版权声明
本文为[北漂追梦人]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/ntfblogs/p/10986268.html