java实现查找PDF关键字所在页码及其坐标
1、因为最近有这方面的需求,用过之后记录一下。
2、此功能跟PDF中Ctrl+F性质一样,如果PDF中为图片形式的不支持定位到关键字。
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; /**
* 消失的太阳
*/
public class MyTest { public static void main(String[] args) throws IOException {
//1.给定文件
File pdfFile = new File("D://test.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;
} @Override
public String toString() {
return "[pageNum=" + this.pageNum + ",x=" + this.x + ",y=" + this.y + "]";
}
}
}
java实现查找PDF关键字所在页码及其坐标的更多相关文章
- 【定位:PDF文件定位关键字所在坐标和页码】
iText简介: iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件 ...
- <转>java 快速查找
[Ct rl+T] 搜索当前接口的实现类 1. [ALT +/] 此快捷键为用户编辑的好帮手,能为用户提供内容的辅助,不要为记不全方法和属性名称犯愁,当记不全类.方法和属性的名字时,多体验一下[ ...
- 巨人大哥谈Java中的Synchronized关键字用法
巨人大哥谈Java中的Synchronized关键字用法 认识synchronized 对于写多线程程序的人来说,经常碰到的就是并发问题,对于容易出现并发问题的地方价格synchronized基本上就 ...
- 浅谈Java中的final关键字
浅谈Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- Java 并发:volatile 关键字解析
摘要: 在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保 ...
- Java基础之static关键字的用法
Java中的static关键字主要用于内存管理.我们可以应用static关键字在变量.方法.块和嵌套类中. static关键字属于类,而不是类的实例. 静态(static)可以是: 变量 ...
- 【java中的final关键字】
转自:https://www.cnblogs.com/xiaoxi/p/6392154.html 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括成员变量 ...
- java中的final关键字的用法
一. 什么是final关键字? final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.一旦你将引用声明作final,你将不能改变这个引用了,编译器会检查代码,如果你试图将变 ...
- java并发系列(六)-----Java并发:volatile关键字解析
在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保证可见性 ...
随机推荐
- hdu3416+hdu6582(最短路+最大流)
题意 hdu3416: 给一个图,边不能重复选,问有多少个最短路 hdu6582: 给一个图,问最少删除边权多少的边后,最短路长度增加 分析 边不能重复选这个条件可以想到边权为1,跑最大流,所以我们可 ...
- @ConfigurationProperties 注解使用姿势,这一篇就够了
在编写项目代码时,我们要求更灵活的配置,更好的模块化整合.在 Spring Boot 项目中,为满足以上要求,我们将大量的参数配置在 application.properties 或 applicat ...
- flask+uwsgi+nginx+docker-compose部署
简单介绍 Flask这里就不多阐述了,已经是很流行的一个轻量级python框架了,对于小.中型项目特别适合.这里用docker的compose编排部署.uwsgi 简单的说明下,uWSGI是一个Web ...
- JS面向对象编程(二):构造函数的继承
对象之间继承的 5 中方法. 比如, 现在有一个"动物"对象的构造函数. function Animal(){ ...
- Android Studio "cannot resolve symbol R" 问题
初接触Android Studio,又遇到了 "cannot resolve symbol R"问题(以前在 Eclipse 也遇到过),网上方法不一,后来在stackoverfl ...
- Linux curl 常用示例
本篇文章包含了curl的常用案例使用. 如果想了解curl选项的详细说明,请参考前一篇文章「Linux curl 命令详解」. 常见网页访问示例 基本用法 访问一个网页 curl https://ww ...
- Web开发中的相对路径和绝对路径
在学习HTML的时候一定会遇到引入文件和链接跳转页面,比如:JS文件.CSS文件.Image图片.我们就会考虑是相对路径和绝对路径的问题.下面PHP程序员雷雪松就详细讲解下Web开发中的相对路径和绝对 ...
- 送礼物「JSOI 2015」RMQ+01分数规划
[题目描述] 礼品店一共有N件礼物排成一列,每件礼物都有它的美观度.排在第\(i(1\leq i\leq N)\)个位置的礼物美观度为正整数\(A_I\).JYY决定选出其中连续的一段,即编号为礼物\ ...
- netty源码解解析(4.0)-17 ChannelHandler: IdleStateHandler实现
io.netty.handler.timeout.IdleStateHandler功能是监测Channel上read, write或者这两者的空闲状态.当Channel超过了指定的空闲时间时,这个Ha ...
- 对平底锅和垃圾的O奖论文的整理和学习[1](2018-02-08发布于知乎)
今天和杉杉同志在Pacific Coffee坐了0.4天,目前两人都处于放空状态. 这种天气有暖气真的太棒了. 我今天看的论文是这两篇: MCM2013B题O奖论文MCM2016B题O奖论文 先说第一 ...