案例源代码(已经将其制成工具类,可以直接调用)

链接:https://pan.baidu.com/s/1aQjrJOAmHogRMn8yiyh4Gg 
提取码:tl66

背景

业务需要

1.使用打印机为文档动态地盖电子印章

2.给定一串合并的学生成绩单文件,需要将其按照不同的学生进行拆分

本例解决(完成)的功能:

1.给定关键字和pdf文件路径,可以搜索到关键字在文件中所有出现的位置(所在页的页码,关键字的xy轴)

2.根据前面找到的位置,再结合传入的印章图片路径,将印章浮于关键字上方

3.根据前面找到的位置,将PDF按照页码区间进行拆分

缺陷/注意

1.印章图片需要是事先处理好的(任意常用图片格式如png、gif、jpg,但是要做背景透明处理),可以使用制图网在线生成印章测试使用

2.传入印章的大小需要是固定的,例如固定使用300x300像素的印章,我们就可以为其作单独处理,假如传入了其它大小的,就会导致盖印章的位置出现很大的偏移(当然一般都是固定的,不固定的你是要用AI技术去处理吗?)

3.只支持PDF文件的搜索

核心代码

导入pom依赖,或者对应的jar包

        <!--itext5--><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.4.3</version></dependency><!--itext的中文支持--><dependency><groupId>com.itextpdf</groupId><artifactId>itext-asian</artifactId><version>5.2.0</version></dependency><!--日志输出--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j</artifactId><version>2.11.2</version></dependency>

GetKeyWordPostion.java  用于寻找关键字的位置

package utils;import com.itextpdf.awt.geom.Rectangle2D.Float;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.*;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** 获取关键字定位的工具类*  其它的方法不用关心,我暂时都看不懂*  你调用findKeywordPostions方法就可以了,参照main方法示例*/
public class GetKeyWordPosition {public static void main(String[] args) throws IOException {//1.给定文件File pdfFile = new File("D://pt3.pdf");//2.定义一个byte数组,长度为文件的长度byte[] pdfData = new byte[(int) pdfFile.length()];//3.IO流读取文件内容到byte数组FileInputStream inputStream = null;try {inputStream = new FileInputStream(pdfFile);inputStream.read(pdfData);} catch (IOException e) {throw e;} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {}}}//4.指定关键字String keyword = "验证";//5.调用方法,给定关键字和文件List<float[]> positions = findKeywordPostions(pdfData, keyword);//6.返回值类型是  List<float[]> 每个list元素代表一个匹配的位置,分别为 float[0]所在页码  float[1]所在x轴 float[2]所在y轴System.out.println("total:" + positions.size());if (positions != null && positions.size() > 0) {for (float[] position : positions) {System.out.print("pageNum: " + (int) position[0]);System.out.print("\tx: " + position[1]);System.out.println("\ty: " + position[2]);}}}/*** findKeywordPostions* @param pdfData     通过IO流 PDF文件转化的byte数组* @param keyword     关键字* @return List<float [ ]> : float[0]:pageNum float[1]:x float[2]:y* @throws IOException*/public static List<float[]> findKeywordPostions(byte[] pdfData, String keyword) throws IOException {List<float[]> result = new ArrayList<>();List<PdfPageContentPositions> pdfPageContentPositions = getPdfContentPostionsList(pdfData);for (PdfPageContentPositions pdfPageContentPosition : pdfPageContentPositions) {List<float[]> charPositions = findPositions(keyword, pdfPageContentPosition);if (charPositions == null || charPositions.size() < 1) {continue;}result.addAll(charPositions);}return result;}private static List<PdfPageContentPositions> getPdfContentPostionsList(byte[] pdfData) throws IOException {PdfReader reader = new PdfReader(pdfData);List<PdfPageContentPositions> result = new ArrayList<>();int pages = reader.getNumberOfPages();for (int pageNum = 1; pageNum <= pages; pageNum++) {float width = reader.getPageSize(pageNum).getWidth();float height = reader.getPageSize(pageNum).getHeight();PdfRenderListener pdfRenderListener = new PdfRenderListener(pageNum, width, height);//解析pdf,定位位置PdfContentStreamProcessor processor = new PdfContentStreamProcessor(pdfRenderListener);PdfDictionary pageDic = reader.getPageN(pageNum);PdfDictionary resourcesDic = pageDic.getAsDict(PdfName.RESOURCES);try {processor.processContent(ContentByteUtils.getContentBytesForPage(reader, pageNum), resourcesDic);} catch (IOException e) {reader.close();throw e;}String content = pdfRenderListener.getContent();List<CharPosition> charPositions = pdfRenderListener.getcharPositions();List<float[]> positionsList = new ArrayList<>();for (CharPosition charPosition : charPositions) {float[] positions = new float[]{charPosition.getPageNum(), charPosition.getX(), charPosition.getY()};positionsList.add(positions);}PdfPageContentPositions pdfPageContentPositions = new PdfPageContentPositions();pdfPageContentPositions.setContent(content);pdfPageContentPositions.setPostions(positionsList);result.add(pdfPageContentPositions);}reader.close();return result;}private static List<float[]> findPositions(String keyword, PdfPageContentPositions pdfPageContentPositions) {List<float[]> result = new ArrayList<>();String content = pdfPageContentPositions.getContent();List<float[]> charPositions = pdfPageContentPositions.getPositions();for (int pos = 0; pos < content.length(); ) {int positionIndex = content.indexOf(keyword, pos);if (positionIndex == -1) {break;}float[] postions = charPositions.get(positionIndex);result.add(postions);pos = positionIndex + 1;}return result;}private static class PdfPageContentPositions {private String content;private List<float[]> positions;public String getContent() {return content;}public void setContent(String content) {this.content = content;}public List<float[]> getPositions() {return positions;}public void setPostions(List<float[]> positions) {this.positions = positions;}}private static class PdfRenderListener implements RenderListener {private int pageNum;private float pageWidth;private float pageHeight;private StringBuilder contentBuilder = new StringBuilder();private List<CharPosition> charPositions = new ArrayList<>();public PdfRenderListener(int pageNum, float pageWidth, float pageHeight) {this.pageNum = pageNum;this.pageWidth = pageWidth;this.pageHeight = pageHeight;}public void beginTextBlock() {}public void renderText(TextRenderInfo renderInfo) {List<TextRenderInfo> characterRenderInfos = renderInfo.getCharacterRenderInfos();for (TextRenderInfo textRenderInfo : characterRenderInfos) {String word = textRenderInfo.getText();if (word.length() > 1) {word = word.substring(word.length() - 1, word.length());}Float rectangle = textRenderInfo.getAscentLine().getBoundingRectange();float x = (float)rectangle.getX();float y = (float)rectangle.getY();
//                float x = (float)rectangle.getCenterX();
//                float y = (float)rectangle.getCenterY();
//                double x = rectangle.getMinX();
//                double y = rectangle.getMaxY();//这两个是关键字在所在页面的XY轴的百分比float xPercent = Math.round(x / pageWidth * 10000) / 10000f;float yPercent = Math.round((1 - y / pageHeight) * 10000) / 10000f;//                CharPosition charPosition = new CharPosition(pageNum, xPercent, yPercent);CharPosition charPosition = new CharPosition(pageNum, (float)x, (float)y);charPositions.add(charPosition);contentBuilder.append(word);}}public void endTextBlock() {}public void renderImage(ImageRenderInfo renderInfo) {}public String getContent() {return contentBuilder.toString();}public List<CharPosition> getcharPositions() {return charPositions;}}private static class CharPosition {private int pageNum = 0;private float x = 0;private float y = 0;public CharPosition(int pageNum, float x, float y) {this.pageNum = pageNum;this.x = x;this.y = y;}public int getPageNum() {return pageNum;}public float getX() {return x;}public float getY() {return y;}@Overridepublic String toString() {return "[pageNum=" + this.pageNum + ",x=" + this.x + ",y=" + this.y + "]";}}
}

SplitUtil.java    在PDF文件中提取关键字出现的页面称为一个新的PDF文件

package utils;import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;import java.io.*;
import java.util.List;/*** 分割PDF文件* 给定PDF文件和关键字,将其从PDF文件中提取(源文件不会少)出来,成为新的文件*/
public class SplitUtil {public static void main(String[] args) throws IOException {//all.pdf你在resource目录下找得到,放到绝对路径就好了splitSpecifiedStudentPDF("D://all.pdf", "D://specifed.pdf", "ZHANG", "Name");}/**** @param sourceFile 源文件* @param targetFile 目标生成文件* @param specfiedKeyword 指定查找关键字  如指定学号 1022304* @param keyword 辅助查找关键字  如查找下一个学号  “Student ID”* @return* @throws IOException*/public static boolean splitSpecifiedStudentPDF(String sourceFile, String targetFile, String specfiedKeyword, String keyword) throws IOException {//接受文件,转化为流File pdfFile = new File(sourceFile);byte[] pdfData = new byte[(int) pdfFile.length()];FileInputStream fis = new FileInputStream(pdfFile);fis.read(pdfData);//获取学生出现页码List<float[]> specifiedPositions = GetKeyWordPosition.findKeywordPostions(pdfData, specfiedKeyword);System.out.println("size: " + specifiedPositions.size());System.out.println("本人所在页码: " + specifiedPositions.get(0)[0]);//获取所有学生出现所在页码,紧邻在其后的是下一个学生所在页码List<float[]> otherPositions = GetKeyWordPosition.findKeywordPostions(pdfData, keyword);System.out.println("size: " + otherPositions.size());//起始页码就是学生第一次出现的页码  结束节码就是下一个学生出现的页码-1int startPageNum = (int) specifiedPositions.get(0)[0];int endPageNum = getNextPage(specifiedPositions, otherPositions) -1;splitPDF(new FileInputStream(sourceFile), new FileOutputStream(targetFile), startPageNum, endPageNum);return true;}//获取指定学生的下一个紧邻的学生所在页码public static int getNextPage(List<float[]> specfiedPositions, List<float[]> otherPositions){for (float[] position : otherPositions) {if(position[0]>specfiedPositions.get(0)[0])return (int)position[0];}return -1;}/*** @param inputStream  PDF文件的输入流* @param outputStream PDF文件的输出流* @param fromPage     开始的页码   闭区间* @param toPage       结束的页码   闭区间*/public static void splitPDF(InputStream inputStream,OutputStream outputStream, int fromPage, int toPage) {Document document = new Document();try {PdfReader inputPDF = new PdfReader(inputStream);int totalPages = inputPDF.getNumberOfPages();//make fromPage equals to toPage if it is greaterif (fromPage > toPage) {fromPage = toPage;}if (toPage > totalPages) {toPage = totalPages;}// Create a writer for the outputstreamPdfWriter writer = PdfWriter.getInstance(document, outputStream);document.open();PdfContentByte cb = writer.getDirectContent(); // Holds the PDF dataPdfImportedPage page;while (fromPage <= toPage) {document.newPage();page = writer.getImportedPage(inputPDF, fromPage);cb.addTemplate(page, 0, 0);fromPage++;}outputStream.flush();document.close();outputStream.close();} catch (Exception e) {e.printStackTrace();} finally {if (document.isOpen())document.close();try {if (outputStream != null)outputStream.close();} catch (IOException ioe) {ioe.printStackTrace();}}}}

StampUtil.java  在PDF文件中寻找指定关键字,并在这个位置上盖章

package utils;import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;import java.io.*;
import java.util.List;import static utils.GetKeyWordPosition.findKeywordPostions;/*** 印章工具类* 使用findKeyWordAndAddImage寻找指定关键字,并且在其所处位置盖章*/
public class StampUtil {public static void main(String[] args) throws Exception {//pt3.pdf你在resource目录下找得到,放到绝对路径下就好了findKeyWordAndAddImage("D://pt3.pdf", "src/main/resources/answer2/utils.pdf", "上海", "src/main/resources/yz.gif", -20, -100);}/*** 寻找指定的关键字后给其所在位置盖章* @param source    源pdf文件* @param target    目标pdf文件* @param keyword   关键字* @param image     印章路径* @param xOffset   x轴偏移量(没有则指定为0)* @param yOffset   y轴偏移量(没有则指定为0)* @return          返回结果* @throws IOException* @throws DocumentException*/public static boolean findKeyWordAndAddImage(String source, String target, String keyword, String image, float xOffset, float yOffset) throws IOException, DocumentException {boolean result = false;File pdfFile = new File(source);byte[] pdfData = new byte[(int) pdfFile.length()];try (FileInputStream fis = new FileInputStream(pdfFile)) {fis.read(pdfData);} catch (IOException e) {e.printStackTrace();System.out.println("文件不存在");return result;}//查到关键字返回位置List<float[]> positions = findKeywordPostions(pdfData, keyword);if(positions.size() == 0){System.out.println("关键字不存在");return result;}//添加水印 //会查询到多个关键字定位,固定取最后一个result = addImage(source, target,  image, positions.get(positions.size()-1), xOffset, yOffset);return true;}//添加水印(签章)private static boolean addImage(String source, String target, String imagePath, float[] positions, float xOffset, float yOffset) throws IOException, DocumentException {// 读取模板文件InputStream input = new FileInputStream(new File(source));PdfReader reader = new PdfReader(input);PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(target));// 提取pdf中的表单AcroFields form = stamper.getAcroFields();form.addSubstitutionFont(BaseFont.createFont("STSong-Light","UniGB-UCS2-H", BaseFont.NOT_EMBEDDED));// 读图片Image image = Image.getInstance(imagePath);// 获取操作的页面PdfContentByte under = stamper.getOverContent((int)positions[0]);//设置图片的定位image.setAbsolutePosition(positions[1]+xOffset, positions[2]+yOffset);//image.scalePercent(75); //缩放图片为指定百分比// 设置透明度为0.8PdfGState gs = new PdfGState();gs.setFillOpacity(0.8f);under.setGState(gs);// 添加图片under.addImage(image);stamper.close();reader.close();return true;}
}
 

Java操作itext,寻找给定关键字,并且进行页面抽取和页面盖章两个操作相关推荐

  1. java定义接口必用关键字_Java中定义接口的关键字是什么

    Java中定义接口的关键字是什么 Java中定义接口的关键字是"interface"."interface"是面向对象编程语言中接口操作的关键字,功能是把所需成 ...

  2. java 生成pdf itext_使用Java组件itext 生成pdf介绍

    iText是一个能够快速产生PDF文件的Java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好的给合.使用iText与 ...

  3. Java中的50个关键字

    2019独角兽企业重金招聘Python工程师标准>>> Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标示符.对于保留字,用户只能按照系统规定的方式 ...

  4. java语言程序设计考点_计算机二级考试Java语言程序设计考点:关键字

    大家回忆一下我们在学习汉语的时候,开始学的是什么?肯定是先学一些单个的字,只有认识了单个的字,然后才能组成词,然后才能慢慢的到句子,然后到文章.学习同计算机交流跟这个过程是一样的,首先我们得学习一些计 ...

  5. java itext 设计器_使用Java组件itext 生成pdf的介绍

    [IT168 技术]iText是一个能够快速产生PDF文件的java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好的给 ...

  6. Java实战应用50篇(一)-Java并发编程:volatile关键字解析

    前言 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字 ...

  7. [转载] Java中的50个关键字

    参考链接: Java平台如何独立 Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标示符.对于保留字,用户只能按照系统规定的方式使用,不能自行定义.Java中有50个常 ...

  8. java使用itext将图片放到pdf模板的指定位置

    java使用itext将图片放到pdf模板的指定位置 前面的准备步骤可以参考我的上一篇文章 这里直接上代码 这里用的图片是路径的形式,还有种情况是图片是base64的时候,这种情况就需要转一下图片格式 ...

  9. Java并发编程:volatile关键字解析(转载)

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 v ...

最新文章

  1. 太厉害了!这应该是目前Redis可视化工具最全的横向评测
  2. conda 装tensorboardx_【工欲善其事】TensorboardX的使用
  3. 洛谷——P2083 找人
  4. 什么是进程什么是线程,他们的区别是什么
  5. 《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
  6. Delphi中关于Rtti的一些操作(一)
  7. 云服务和serverless
  8. Hacker-基础学习(1)
  9. vs2015 mysql edmx_VS2015+MySql EF的配置问题
  10. Oracle 11.2.0.4.0 Dataguard部署和日常维护(6)-Active Dataguard篇
  11. FTP/文件传输协议
  12. pycharm中遇到master in has no tracked branch的解决方式
  13. 安卓动画入门教程 Animation in Android(1)
  14. android 手机ssh客户端,android手机ssh客户端ConnectBot
  15. springboot+nodejs+vue公寓客房预订网站
  16. 社交网络崛起带来口碑营销的复兴
  17. 关于利用kali linux2017.2中MSFCONSOLE 利用MS17-010漏洞发起攻击的坑
  18. 【SPSS】百分位数计算方法探讨:SPSS计算差异
  19. pass在c语言中的作用,Python语句中pass语句有什么作用?浅谈pass语句的用法
  20. ST-GCN demo运行记录

热门文章

  1. 不错的向上滚动广告代码
  2. 谷爱凌惊“险”一跳,最少价值10个亿!
  3. 郭明錤:全新设计AirPods Pro2将于2022年末推出
  4. 1英寸大底手机来了 是索尼的营销噱头吗?
  5. 礼橙专车、青菜拼车今日起改名啦!
  6. 华为P50保护壳曝光:双环形后置相机模组实锤
  7. iQOO Z1于10月21日开启双十一钜惠,最高立减200元
  8. 罗永浩宣布要做带货一哥后,合作单子如雪花般飞来
  9. 京东发布双11首份战报:手机品类18秒销量突破万台
  10. 荣耀20 Pro 5000元最强拍照机翻车?官方怒放样张辟谣