Java操作itext,寻找给定关键字,并且进行页面抽取和页面盖章两个操作
案例源代码(已经将其制成工具类,可以直接调用)
链接: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,寻找给定关键字,并且进行页面抽取和页面盖章两个操作相关推荐
- java定义接口必用关键字_Java中定义接口的关键字是什么
Java中定义接口的关键字是什么 Java中定义接口的关键字是"interface"."interface"是面向对象编程语言中接口操作的关键字,功能是把所需成 ...
- java 生成pdf itext_使用Java组件itext 生成pdf介绍
iText是一个能够快速产生PDF文件的Java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好的给合.使用iText与 ...
- Java中的50个关键字
2019独角兽企业重金招聘Python工程师标准>>> Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标示符.对于保留字,用户只能按照系统规定的方式 ...
- java语言程序设计考点_计算机二级考试Java语言程序设计考点:关键字
大家回忆一下我们在学习汉语的时候,开始学的是什么?肯定是先学一些单个的字,只有认识了单个的字,然后才能组成词,然后才能慢慢的到句子,然后到文章.学习同计算机交流跟这个过程是一样的,首先我们得学习一些计 ...
- java itext 设计器_使用Java组件itext 生成pdf的介绍
[IT168 技术]iText是一个能够快速产生PDF文件的java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好的给 ...
- Java实战应用50篇(一)-Java并发编程:volatile关键字解析
前言 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字 ...
- [转载] Java中的50个关键字
参考链接: Java平台如何独立 Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标示符.对于保留字,用户只能按照系统规定的方式使用,不能自行定义.Java中有50个常 ...
- java使用itext将图片放到pdf模板的指定位置
java使用itext将图片放到pdf模板的指定位置 前面的准备步骤可以参考我的上一篇文章 这里直接上代码 这里用的图片是路径的形式,还有种情况是图片是base64的时候,这种情况就需要转一下图片格式 ...
- Java并发编程:volatile关键字解析(转载)
转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 v ...
最新文章
- 太厉害了!这应该是目前Redis可视化工具最全的横向评测
- conda 装tensorboardx_【工欲善其事】TensorboardX的使用
- 洛谷——P2083 找人
- 什么是进程什么是线程,他们的区别是什么
- 《Android开发艺术探索》自定义View中关于“HorizontalScrollViewEx”的改进
- Delphi中关于Rtti的一些操作(一)
- 云服务和serverless
- Hacker-基础学习(1)
- vs2015 mysql edmx_VS2015+MySql EF的配置问题
- Oracle 11.2.0.4.0 Dataguard部署和日常维护(6)-Active Dataguard篇
- FTP/文件传输协议
- pycharm中遇到master in has no tracked branch的解决方式
- 安卓动画入门教程 Animation in Android(1)
- android 手机ssh客户端,android手机ssh客户端ConnectBot
- springboot+nodejs+vue公寓客房预订网站
- 社交网络崛起带来口碑营销的复兴
- 关于利用kali linux2017.2中MSFCONSOLE 利用MS17-010漏洞发起攻击的坑
- 【SPSS】百分位数计算方法探讨:SPSS计算差异
- pass在c语言中的作用,Python语句中pass语句有什么作用?浅谈pass语句的用法
- ST-GCN demo运行记录