当前位置:   article > 正文

java提取PDF文字坐标_renderlistener

renderlistener

常用java操作PDF的库有PDFbox和itext,下面我会介绍如何使用PDFbox和itext来提取PDF的文字坐标。

一、itext提取文字坐标

itext版本:5.5.6,低版本的可能没有提供这种方法。

1、通过定义一个类实现RenderListener,可以通过里面的几个方法来操作PDF中的文字和图片

  1. import java.awt.Color;
  2. import java.awt.image.BufferedImage;
  3. import java.io.IOException;
  4. import java.util.ArrayList;
  5. import java.util.HashMap;
  6. import java.util.HashSet;
  7. import java.util.List;
  8. import java.util.Map;
  9. import javax.imageio.ImageIO;
  10. import com.itextpdf.awt.geom.Rectangle2D;
  11. import com.itextpdf.awt.geom.RectangularShape;
  12. import com.itextpdf.text.BaseColor;
  13. import com.itextpdf.text.Rectangle;
  14. import com.itextpdf.text.pdf.PdfContentByte;
  15. import com.itextpdf.text.pdf.parser.ImageRenderInfo;
  16. import com.itextpdf.text.pdf.parser.RenderListener;
  17. import com.itextpdf.text.pdf.parser.TextRenderInfo;
  18. public class TestRenderListener implements RenderListener {
  19. //用来存放文字的矩形
  20. List<Rectangle2D.Float> rectText = new ArrayList<Rectangle2D.Float>();
  21. //用来存放文字
  22. List<String> textList = new ArrayList<String>();
  23. //用来存放文字的y坐标
  24. List<Float> listY = new ArrayList<Float>();
  25. //用来存放每一行文字的坐标位置
  26. List<Map<String,Rectangle2D.Float>> rows_text_rect = new ArrayList<>();
  27. //PDF文件的路径
  28. protected String filepath = null;
  29. public TestRenderListener() {
  30. }
  31. //step 2,遇到"BT"执行
  32. @Override
  33. public void beginTextBlock() {
  34. // TODO Auto-generated method stub
  35. }
  36. //step 3
  37. /**
  38. * 文字主要处理方法
  39. */
  40. @Override
  41. public void renderText(TextRenderInfo renderInfo) {
  42. //获取文字的下面的矩形
  43. //Rectangle2D.Float rectBase = renderInfo.getBaseline().getBoundingRectange();
  44. String text = renderInfo.getText();
  45. if(text.length() > 0){
  46. RectangularShape rectBase = renderInfo.getBaseline().getBoundingRectange();
  47. //获取文字下面的矩形
  48. Rectangle2D.Float rectAscen = renderInfo.getAscentLine().getBoundingRectange();
  49. //计算出文字的边框矩形
  50. float leftX = (float) rectBase.getMinX();
  51. float leftY = (float) rectBase.getMinY()-1;
  52. float rightX = (float) rectAscen.getMaxX();
  53. float rightY = (float) rectAscen.getMaxY()+1;
  54. Rectangle2D.Float rect = new Rectangle2D.Float(leftX, leftY, rightX - leftX, rightY - leftY);
  55. System.out.println("text:"+text+"--x:"+rect.x + "--y:"+rect.y + "--width:"+rect.width + "--height:"+rect.height);
  56. if(listY.contains(rect.y)){
  57. int index = listY.indexOf(rect.y);
  58. float tempx = rect.x > rectText.get(index).x ? rectText.get(index).x : rect.x;
  59. rectText.set(index,new Rectangle2D.Float(tempx,rect.y,rect.width + rectText.get(index).width,rect.height));
  60. textList.set(index,textList.get(index) + text);
  61. }else{
  62. rectText.add(rect);
  63. textList.add(text);
  64. listY.add(rect.y);
  65. }
  66. Map<String,Rectangle2D.Float> map = new HashMap<>();
  67. map.put(text,rect);
  68. rows_text_rect.add(map);
  69. }
  70. }
  71. //step 4(最后执行的,只执行一次),遇到“ET”执行
  72. @Override
  73. public void endTextBlock() {
  74. // TODO Auto-generated method stub
  75. }
  76. //step 1(图片处理方法)
  77. @Override
  78. public void renderImage(ImageRenderInfo renderInfo) {
  79. }
  80. }
2、使用自定义的类来实现获取PDF的文字坐标

  1. PdfReader reader = new PdfReader(pdfPath);
  2. //新建一个PDF解析对象
  3. PdfReaderContentParser parser = new PdfReaderContentParser(reader);
  4. //包含了PDF页面的信息,作为处理的对象
  5. PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("d:/test.pdf"));
  6. for(int i = 1;i <= reader.getNumberOfPages();i++){
  7. //新建一个ImageRenderListener对象,该对象实现了RenderListener接口,作为处理PDF的主要类
  8. TestRenderListener listener = new TestRenderListener();
  9. //解析PDF,并处理里面的文字
  10. parser.processContent(i, listener);
  11. //获取文字的矩形边框
  12. List<Rectangle2D.Float> rectText = listener.rectText;
  13. List<String> textList = listener.textList;
  14. List<Float> listY = listener.listY;
  15. List<Map<String,Rectangle2D.Float>> list_text = listener.rows_text_rect;
  16. for(int k = 0;k < list_text.size();k++){
  17. Map<String,Rectangle2D.Float> map = list_text.get(k);
  18. for(Map.Entry<String, Rectangle2D.Float>entry:map.entrySet()){
  19. System.out.println(entry.getKey()+"---"+entry.getValue());
  20. }
  1. }
  2. }

二、PDFbox获取文字坐标

PDFbox与itext不同的是,PDFbox只能一个一个字的提取PDF的文字坐标,而itext是一段一段提取的。

PDFbox版本:1.8.13,不同版本可能部分代码写法不同。

  1. import java.io.*;
  2. import org.apache.pdfbox.exceptions.InvalidPasswordException;
  3. import org.apache.pdfbox.pdmodel.PDDocument;
  4. import org.apache.pdfbox.pdmodel.PDPage;
  5. import org.apache.pdfbox.pdmodel.common.PDStream;
  6. import org.apache.pdfbox.util.PDFTextStripper;
  7. import org.apache.pdfbox.util.TextPosition;
  8. import java.io.IOException;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. public class PrintTextLocations extends PDFTextStripper {
  12. static List<Float> list_postion = new ArrayList<Float>();
  13. static List<String> list_text = new ArrayList<String>();
  14. public PrintTextLocations() throws IOException {
  15. super.setSortByPosition(true);
  16. }
  17. public static void main(String[] args) throws Exception {
  18. PDDocument document = null;
  19. try {
  20. File input = new File("D://result.pdf");
  21. document = PDDocument.load(input);
  22. if (document.isEncrypted()) {
  23. document.decrypt("");
  24. }
  25. PrintTextLocations printer = new PrintTextLocations();
  26. List allPages = document.getDocumentCatalog().getAllPages();
  27. for (int i = 0; i < allPages.size(); i++) {
  28. PDPage page = (PDPage) allPages.get(i);
  29. System.out.println("Processing page: " + i);
  30. PDStream contents = page.getContents();
  31. if (contents != null) {
  32. printer.processStream(page, page.findResources(), page.getContents().getStream());
  33. }
  34. }
  35. } finally {
  36. if (document != null) {
  37. document.close();
  38. }
  39. }
  40. System.out.println(list_text.size());
  41. for(int i = 0;i < list_text.size();i++){
  42. System.out.println(list_text.get(i) );
  43. }
  44. }
  45. /**
  46. * @param text The text to be processed
  47. */
  48. @Override /* this is questionable, not sure if needed... */
  49. protected void processTextPosition(TextPosition text) {
  50. System.out.println("String[" + text.getXDirAdj() + ","
  51. + text.getYDirAdj() + " fs=" + text.getFontSize() + " xscale="
  52. + text.getXScale()+ " yscale="
  53. + text.getYScale() + " height=" + text.getHeightDir() + " space="
  54. + text.getWidthOfSpace() + " width="
  55. + text.getWidthDirAdj() + " x="
  56. + text.getX() + " y="
  57. + text.getY() + " y1="
  58. + text.getTextPos().getYPosition() + " x1="
  59. + text.getTextPos().getXPosition() + " x1="
  60. + text.getTextPos().getXScale() + " x1="
  61. + text.getTextPos().getYScale() + "]" + text.getCharacter());
  62. }
  63. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/744782
推荐阅读
相关标签
  

闽ICP备14008679号