itext7知识点研究(PDF编辑)
取出pdf文档文字
String sourceFolder2 = "E:\\picture2\\租赁合同2.pdf";
PdfDocument doc = new PdfDocument(new PdfReader(sourceFolder2));
float height = doc.getPage(1).getPageSize().getHeight();
float width = doc.getPage(1).getPageSize().getWidth();
Rectangle rect = new Rectangle(width,height);
FilteredTextEventListener filterListener = new FilteredTextEventListener(new LocationTextExtractionStrategy(), new TextRegionEventFilter(rect));
String extractedText = PdfTextExtractor.getTextFromPage(doc.getPage(1), filterListener);
System.out.println(extractedText);
- 上面的例子就可以取出第一页所有的文字,如果需要取出某些文字需要知道文字的具体方位,画个矩形就可以取出
 - 以上代码依赖com.itextpdf.kernel
 
- 取出多个位置的文字
 
@Test
public void testWithMultiFilteredRenderListener() throws IOException {
    PdfDocument pdfDocument = new PdfDocument(new PdfReader(sourceFolder + "test.pdf"));
    float x1, y1, x2, y2;
    FilteredEventListener listener = new FilteredEventListener();
    x1 = 122;
    x2 = 22;
    y1 = 678.9f;
    y2 = 12;
    ITextExtractionStrategy region1Listener = listener.attachEventListener(new LocationTextExtractionStrategy(),
            new TextRegionEventFilter(new Rectangle(x1, y1, x2, y2)));
    x1 = 156;
    x2 = 13;
    y1 = 678.9f;
    y2 = 12;
    ITextExtractionStrategy region2Listener = listener.attachEventListener(new LocationTextExtractionStrategy(),
            new TextRegionEventFilter(new Rectangle(x1, y1, x2, y2)));
    PdfCanvasProcessor parser = new PdfCanvasProcessor(new GlyphEventListener(listener));
    parser.processPageContent(pdfDocument.getPage(1));
    Assert.assertEquals("Your", region1Listener.getResultantText());
    Assert.assertEquals("dju", region2Listener.getResultantText());
}
遍历pdf每个字符
- 之前一直以为Listen监听遍历pdf文本只能一段一段遍历,现在发现他实际上提供了遍历字符的方法\
 - 两个监听器,一个监听的段落,一个监听每个字符
 
static class MyEventListener implements IEventListener {
private List<Rectangle> rectangles = new ArrayList<>(); @Override
public void eventOccurred(IEventData data, EventType type) {
if (type == EventType.RENDER_TEXT) {
TextRenderInfo renderInfo = (TextRenderInfo) data;
Vector startPoint = renderInfo.getDescentLine().getStartPoint();
Vector endPoint = renderInfo.getAscentLine().getEndPoint();
float x1 = Math.min(startPoint.get(0), endPoint.get(0));
float x2 = Math.max(startPoint.get(0), endPoint.get(0));
float y1 = Math.min(startPoint.get(1), endPoint.get(1));
float y2 = Math.max(startPoint.get(1), endPoint.get(1));
rectangles.add(new Rectangle(x1, y1, x2 - x1, y2 - y1));
}
} @Override
public Set<EventType> getSupportedEvents() {
return new LinkedHashSet<>(Collections.singletonList(EventType.RENDER_TEXT));
} public List<Rectangle> getRectangles() {
return rectangles;
} public void clear() {
rectangles.clear();
}
} static class MyCharacterEventListener extends MyEventListener {
@Override
public void eventOccurred(IEventData data, EventType type) {
if (type == EventType.RENDER_TEXT) {
TextRenderInfo renderInfo = (TextRenderInfo) data;
for (TextRenderInfo tri : renderInfo.getCharacterRenderInfos()) {
super.eventOccurred(tri, type);
}
}
}
}
- 标记每个字符,提供了这样的方法,可以发挥想象做更多的事,给个图片更清楚点
 
private void parseAndHighlight(String input, String output, boolean singleCharacters) throws IOException {
PdfDocument pdfDocument = new PdfDocument(new PdfReader(input), new PdfWriter(output)); MyEventListener myEventListener = singleCharacters ? new MyCharacterEventListener() : new MyEventListener();
PdfDocumentContentParser parser = new PdfDocumentContentParser(pdfDocument);
for (int pageNum = 1; pageNum <= pdfDocument.getNumberOfPages(); pageNum++) {
parser.processContent(pageNum, myEventListener);
List<Rectangle> rectangles = myEventListener.getRectangles();
PdfCanvas canvas = new PdfCanvas(pdfDocument.getPage(pageNum));
canvas.setLineWidth(0.5f);
canvas.setStrokeColor(ColorConstants.RED);
for (Rectangle rectangle : rectangles) {
canvas.rectangle(rectangle);
canvas.stroke();
}
myEventListener.clear();
} pdfDocument.close();
}

- 要实现上面的效果,只要调用上面的方法即可
 
@Test
public void highlightNotDefTest() throws IOException, InterruptedException {
String input = sourceFolder + "page229.pdf";
String output = outputPath + "page229.pdf";
//false 表示短语单词为单位 true表示每个字符都遍历
parseAndHighlight(input, output, false);
}
- false的效果

 
定位某些单词
@Test
public void findPosition() throws Exception {
    String sourceFolder2 = "E:\\picture2\\租赁合同2.pdf";
    String output = "E:\\picture2\\租赁合同2_stroke.pdf";
    PdfReader reader = new PdfReader(sourceFolder2);
    PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(output));
    PdfPage lastPage = pdfDocument.getLastPage();
    RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy("甲方");
    PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
    canvasProcessor.processPageContent(lastPage);
    Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();
    PdfCanvas pdfCanvas = new PdfCanvas(lastPage);
    pdfCanvas.setLineWidth(0.5f);
    List<IPdfTextLocation> sets = new ArrayList<>();
    for (IPdfTextLocation location : resultantLocations) {
        Rectangle rectangle = location.getRectangle();
        pdfCanvas.rectangle(rectangle);
        pdfCanvas.setStrokeColor(ColorConstants.RED);
        pdfCanvas.stroke();
        System.out.println(rectangle.getX() + "," + rectangle.getY() + "," + rectangle.getLeft() + "," +
                rectangle.getRight() + "," + rectangle.getTop() + "," + rectangle.getBottom() + "," +
                rectangle.getWidth() + "," + rectangle.getHeight());
        System.out.println(location.getText());
        sets.add(location);
    }
    Collections.sort(sets, new Comparator<IPdfTextLocation>() {
        @Override
        public int compare(IPdfTextLocation o1, IPdfTextLocation o2) {
            return o1.getRectangle().getY() - o2.getRectangle().getY() > 0 ? 1 : o1.getRectangle().getY() - o2.getRectangle().getY() == 0 ? 0 : -1;
        }
    });
    System.out.println(sets.get(0).getRectangle().getY());
    pdfDocument.close();
}
- 以下是输出
 
88.0,297.53,88.0,115.72,311.53,297.53,27.720001,14.0
甲方
213.0,674.176,213.0,241.0,688.176,674.176,28.0,14.0
甲方
227.75,767.7765,227.75,254.75,781.2765,767.7765,27.0,13.5
甲方
322.25,767.7765,322.25,349.25,781.2765,767.7765,27.0,13.5
甲方
297.53
- 上面的方法用来合同签章定位上,已经可以做到定位最后某个特定单词
 
添加文字和图片
@Test
public void imagesWithDifferentDepth() throws IOException, InterruptedException {
    String outFileName = destinationFolder + "transparencyTest01.pdf";
    String cmpFileName = sourceFolder + "cmp_transparencyTest01.pdf";
    PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName, new WriterProperties()
            .setCompressionLevel(CompressionConstants.NO_COMPRESSION)));
    PdfPage page = pdfDocument.addNewPage(PageSize.A3);//默认添加A4
    PdfCanvas canvas = new PdfCanvas(page);
    canvas.setFillColor(ColorConstants.LIGHT_GRAY).fill();//设置填充背景色
    canvas.rectangle(80, 0, 700, 1200).fill();
    //开始添加文字
    canvas
            .saveState()
            .beginText()
            .moveText(116, 1150) //从哪里开始写
            .setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 14) //字体和大小
            .setFillColor(ColorConstants.MAGENTA) //字体颜色
            .showText("8 bit depth PNG") //具体展示的文字
            .endText()
            .restoreState();
    //读取并添加图片到指定位置
    ImageData img = ImageDataFactory.create(sourceFolder + "manualTransparency_8bit.png");
    canvas.addImage(img, 100, 780, 200, false);
    //收尾步骤,关闭画布和pdf,否则pdf打开错误
    canvas.release();
    pdfDocument.close();
}
覆盖原来的文字
- 由于itext没提供替换pdf文字的接口,只能通过覆盖文字的形式完成
 
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
        PdfReader reader = new PdfReader(src);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        PdfContentByte canvas = stamper.getUnderContent(1);
        canvas.saveState();
        canvas.setColorFill(BaseColor.YELLOW);
        canvas.rectangle(36, 786, 66, 16);
        canvas.fill();
        canvas.restoreState();
        //开始写入文本
        canvas.beginText();
        for (Entry<String, ReplaceRegion> entry : entrys) {
        	ReplaceRegion val = entry.getValue();
        	//设置字体
        	canvas.setFontAndSize(font.getBaseFont(), getFontSize());
            canvas.setTextMatrix(val.getX(),val.getY()+2/*修正背景与文本的相对位置*/);
            canvas.showText((String) replaceTextMap.get(value.getAliasName()));
		}
        canvas.endText();
        stamper.close();
        reader.close();
    }
												
											itext7知识点研究(PDF编辑)的更多相关文章
- 在线PDF编辑网站http://www.pdfescape.com
		
网站地址:http://www.pdfescape.com 先转载一个简单介绍的文章 如果你以前很少阅读PDF文档,电脑中也没有PDF阅读器:adobe reader,foxit reader之类的软 ...
 - PDF编辑方法,PDF如何去除数字签名
		
有些人会在PDF文件中添加数字签名,但当PDF文件有数字签名的时候就无法对PDF文件进行编辑.添加等操作.这个时候就需要去除PDF文件中的数字签名了,要怎么做呢,就由我来跟大家分享一下小编我的去除数字 ...
 - PDF编辑方法,PDF怎么去除背景
		
PDF文件现在是使用的频率很高的一个软件的格式,PDF文件能够更加直观清楚的表达,PDF文件的使用很方便但编辑起来就来没有那么容易了,PDF文件的编辑是需要借助软件的,今天小编就来跟大家分享一下PDF ...
 - 不花钱搞定PDF编辑难题
		
PDF格式是专为显示而设计的格式,并不容易被编辑,市面上并没有一款可以真正免费使用的PDF编辑器. 不花钱搞定PDF编辑难题的办法: 1.免费使用PDF编辑器+去水印:免费版的PDF编辑器不是会加水印 ...
 - 付费?是不可能的!20行Python代码实现一款永久免费PDF编辑工具
		
PDF(Portable Document Format),中文名称便携文档格式是我们经常会接触到的一种文件格式,文献.文档…很多都是PDF格式.它以格式稳定的优势,使得我们在打印.分享.传输过程中能 ...
 - PDF编辑、删除、替换某页面或文字
		
在工作中,我们常常会用到PDF,当然尤其是会计,我虽然是程序员,但是“小老鼠”是会计,前几天,突然问我,怎么样将PDF中的某个页面替换掉,也就是删掉某页然后再从另外一个地方找一页补上来: 还需要改变这 ...
 - itext7 html转pdf实现
		
公司最近做一个交易所项目,里面涉及一个需求就是将html模板,在填充数据后转换为pdf,这样防止数据更改,下面是具体实现 1 pom文件 <dependency> <groupId& ...
 - PDF编辑:pdfFactory文本备注功能详解
		
除了word的doc文件外,PDF也是我们经常接触到的文件格式,经常需要在pdf文件上进行编辑与修改,或者给内容做提示和备注. 文件的文本备注功能可以用pdfFactory来进行,编辑打印PDF一条龙 ...
 - PDF编辑神器
		
转自网络 http://files.cnblogs.com/files/quejuwen/pdfeditportable.zip
 
随机推荐
- thinkphp5.0 - Redis 实现秒杀
			
首先,因为秒杀这个环节在商城项目中比较常见,最近写商城项目,碰到这个功能模块,于是就拿出来给大家分享一波. 难点:高并发的情况下,正常逻辑写的话数据库的库存会出现负数,对付这类问题有很多解决方案,我就 ...
 - Intersect交集Except差集Union并集实例
			
int[] oldArray = { 1, 2, 3, 4, 5 };int[] newArray = { 2, 4, 5, 7, 8, 9 };var jiaoJi = oldArray.Inter ...
 - 关于Shader的学习记录
			
float4 _EmissiveColor; float4 _AmbientColor; float _MySliderValue; void surf (Input IN, inout Surfac ...
 - vivo手机,自带世界之窗浏览器,sessionStorage设置的值为null
			
最近遇到一个小问题 用vivo手机自带浏览器,每次跳转到一个新页面都是重新打开一个webpage,导致sessionStorage设置的值都没了. 所以开发移动端网页时,谨慎使用sessionStor ...
 - oracle数据库名称已被一现有约束条件占用
			
使用oracle数据库出现名称已被一现有约束条件占用的错误,我的原因是在同一个库中有一个表使用了外键FK_SNO,自己新建的一个表中也使用了外键FK_SNO,导致出现了错误. 这时改变一下外键FK_S ...
 - Codeforces Round #437 B. Save the problem!
			
题意: 给你一个方案数,要求你输出满足该条件的总金额,面值数,和各个面值是多少,答案有多个,随便输出一个即可. Examples Input 18 Output 30 41 5 10 25 Input ...
 - C++成员函数在内存中的存储方式
			
用类去定义对象时,系统会为每一个对象分配存储空间.如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间.按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分 ...
 - python的条件语句
			
Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. Python 编程中 if 语句用于控制程序的执行,基本形式为: if 判断条件: 执行语句…… el ...
 - mybatis中查询使用#{}和${}的区别
			
${}中的变量什么值,就会简单的替代变量,不会做处理 比如delete * from tb_label where name=${labelname} 如果labelname的值是 something ...
 - Linux驱动之同步、互斥、阻塞的应用
			
同步.互斥.阻塞的概念: 同步:在并发程序设计中,各进程对公共变量的访问必须加以制约,这种制约称为同步. 互斥机制:访问共享资源的代码区叫做临界区,这里的共享资源可能被多个线程需要,但这些共享资源又不 ...