Java:Apache PDFbox提取突出显示的文本

时间:2015-10-21 07:51:37

标签: java pdf pdfbox

我正在使用Apache PDFbox库从PDF文件中提取突出显示的文本(即黄色背景)。我对这个库完全是新手,并且不知道它用于此目的的哪个类。 到目前为止,我已经使用下面的代码从评论中提取了文本。

PDDocument pddDocument = PDDocument.load(new File("test.pdf"));
    List allPages = pddDocument.getDocumentCatalog().getAllPages();
    for (int i = 0; i < allPages.size(); i++) {
    int pageNum = i + 1;
    PDPage page = (PDPage) allPages.get(i);
    List<PDAnnotation> la = page.getAnnotations();
    if (la.size() < 1) {
    continue;
    }
    System.out.println("Total annotations = " + la.size());
    System.out.println("\nProcess Page " + pageNum + "...");
    // Just get the first annotation for testing
    PDAnnotation pdfAnnot = la.get(0); 
    System.out.println("Getting text from comment = " + pdfAnnot.getContents());

现在我需要获得突出显示的文本,任何代码示例都将受到高度赞赏。

2 个答案:

答案 0 :(得分:6)

我希望这个答案可以帮助每个面临同样问题的人。

// PDF32000-2008
// 12.5.2 Annotation Dictionaries
// 12.5.6 Annotation Types
// 12.5.6.10 Text Markup Annotations
@SuppressWarnings({ "unchecked", "unused" })
public ArrayList<String> getHighlightedText(String filePath, int pageNumber) throws IOException {
    ArrayList<String> highlightedTexts = new ArrayList<>();
    // this is the in-memory representation of the PDF document.
    // this will load a document from a file.
    PDDocument document = PDDocument.load(filePath);
    // this represents all pages in a PDF document.
    List<PDPage> allPages =  document.getDocumentCatalog().getAllPages();
    // this represents a single page in a PDF document.
    PDPage page = allPages.get(pageNumber);
    // get  annotation dictionaries
    List<PDAnnotation> annotations = page.getAnnotations();

    for(int i=0; i<annotations.size(); i++) {
        // check subType 
        if(annotations.get(i).getSubtype().equals("Highlight")) {
            // extract highlighted text
            PDFTextStripperByArea stripperByArea = new PDFTextStripperByArea();

            COSArray quadsArray = (COSArray) annotations.get(i).getDictionary().getDictionaryObject(COSName.getPDFName("QuadPoints"));
            String str = null;

            for(int j=1, k=0; j<=(quadsArray.size()/8); j++) {

                COSFloat ULX = (COSFloat) quadsArray.get(0+k);
                COSFloat ULY = (COSFloat) quadsArray.get(1+k);
                COSFloat URX = (COSFloat) quadsArray.get(2+k);
                COSFloat URY = (COSFloat) quadsArray.get(3+k);
                COSFloat LLX = (COSFloat) quadsArray.get(4+k);
                COSFloat LLY = (COSFloat) quadsArray.get(5+k);
                COSFloat LRX = (COSFloat) quadsArray.get(6+k);
                COSFloat LRY = (COSFloat) quadsArray.get(7+k);

                k+=8;

                float ulx = ULX.floatValue() - 1;                           // upper left x.
                float uly = ULY.floatValue();                               // upper left y.
                float width = URX.floatValue() - LLX.floatValue();          // calculated by upperRightX - lowerLeftX.
                float height = URY.floatValue() - LLY.floatValue();         // calculated by upperRightY - lowerLeftY.

                PDRectangle pageSize = page.getMediaBox();
                uly = pageSize.getHeight() - uly;

                Rectangle2D.Float rectangle_2 = new Rectangle2D.Float(ulx, uly, width, height);
                stripperByArea.addRegion("highlightedRegion", rectangle_2);
                stripperByArea.extractRegions(page);
                String highlightedText = stripperByArea.getTextForRegion("highlightedRegion");

                if(j > 1) {
                    str = str.concat(highlightedText);
                } else {
                    str = highlightedText;
                }
            }
            highlightedTexts.add(str);
        }
    }
    document.close();

    return highlightedTexts;
}

答案 1 :(得分:4)

问题Not able to read the exact text highlighted across the lines中的代码已经说明了用于从PDFBox页面上的有限内容区域提取文本的大多数概念。

在研究了这段代码后,OP仍在评论中表示:

  

但令我困惑的一件事是 QuadPoints 而不是 Rect 。正如你在评论中提到的那样。这是什么,你可以用一些代码行或用简单的词来解释它,因为我也面临着多行高亮的同样问题吗?

通常,注释引用的区域是矩形:

  

Rect 矩形(必填)注释矩形,以默认用户空间单位定义页面上注释的位置。

     

(来自表164 - 所有注释词典共有的条目 - 在ISO 32000-1中)

对于某些注释类型(例如文本标记),此位置值不够,因为:

  • 标记文本可以以某个奇数角写入,但说明书中提到的矩形类型是指边缘平行于页边的矩形;和
  • 标记的文本可以从一行中的任何地方开始,然后在另一行中的任何地方结束,因此标记区域根本不是矩形,而是多个矩形部分的并集。

因此,为了处理这些注释类型,PDF规范提供了一种更通用的方法来定义区域:

  

QuadPoints array (必需)一个8×n数字的数组,用于指定默认用户空间中n个四边形的坐标。每个四边形应包含注释背后的文本中的一个或一组连续单词。每个四边形的坐标应按顺序

给出      

x 1 y 1 x 2 y 2 x 3 y < sub> 3 x 4 y 4

     

以逆时针顺序指定四边形的四个顶点(参见图64)。文本应相对于边连接点(x 1 ,y 1 )和(x 2 ,y 2) )。

     

(来自表179 - 特定于文本标记注释的附加条目 - 在ISO 32000-1中)

因此,而不是

给出的矩形
PDRectangle rect = pdfAnnot.getRectangle();

referenced question的代码中,您必须考虑

给出的四边形
COSArray quadsArray = (COSArray) pdfAnnot.getDictionary().getDictionaryObject(COSName getPDFName("QuadPoints"));

并相应地定义PDFTextStripperByArea stripper的区域。不幸的是PDFTextStripperByArea.addRegion期望一个矩形作为参数,而不是一些通用的四边形。由于文本通常是水平或垂直打印,因此不会造成太大问题。

PS 有关 QuadPoints 规范的一个警告,该命令在现实PDF中可能有所不同,参见问题PDF Spec vs Acrobat creation (QuadPoints)

相关问题