Java: Apache PDFBox提取高亮文本

5

我正在使用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());

现在我需要获取突出显示的文本,如果有代码示例将不胜感激。

这个问题或许能帮到你:https://dev59.com/7Y_ea4cB1Zd3GeqPKirz。 - mkl
@mkl非常感谢您提供的链接,它确实帮助了我。但是有一件事让我感到困惑,就是QuadPoints而不是Rect。正如您在评论中提到的那样。这是什么,您能用一些代码行或简单的话来解释一下吗?因为我也遇到了多行高亮的问题。 - Abid Khan
并请在回答中写下我会接受它。 - Abid Khan
2个回答

9

我希望这个答案能帮助到所有遇到同样问题的人。

// 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;
}

5
非常感谢您提供的例子!以下是使其与PDFBox 2.0配合使用所需的更改: PDDocument document = PDDocument.load(new File(filePath)); List<PDPage> allPages = new ArrayList<>(); document.getDocumentCatalog().getPages().forEach(allPages::add); PDPage page = allPages.get(pageNumber); COSArray quadsArray = (COSArray) annotations.get(i).getCOSObject().getDictionaryObject(COSName.getPDFName("QuadPoints")); - dev-random

7
问题中的代码Not able to read the exact text highlighted across the lines已经演示了使用PDFBox从页面上的有限内容区域中提取文本的大部分概念。
通过学习这段代码,OP在评论中仍然感到困惑:

但是我对QuadPoints而不是Rect感到困惑。如你在评论中提到的那样。它是什么,你能用一些代码行或简单的话来解释一下吗,因为我也遇到了同样的多行高亮问题?

通常,注释所涉及的区域是一个矩形:

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

(源自 ISO 32000-1 中的表164 - 所有注释字典通用的条目)

对于某些注释类型(例如文本标记),此位置值不足,因为:
  • 标记的文本可能写在一些奇怪的角度,但是规范中提到的矩形类型指的是边缘平行于页面边缘的矩形;和
  • 标记的文本可能从一行中的任何位置开始,在另一行的任何位置结束,因此标记区域根本不是矩形,而是多个矩形部分的联合。
因此,为了应对这些注释类型,PDF规范提供了一种更通用的定义区域的方式:

QuadPoints数组 (必需)一个8×n数字的数组,指定n个四边形在默认用户空间中的坐标。每个四边形都包含注释底层文本中的一个单词或一组相邻的单词。每个四边形的坐标应按顺时针顺序给出

x1 y1 x2 y2 x3 y3 x4 y4

指定四边形的四个顶点(参见图64)。文本应以连接点(x1, y1)和(x2, y2)的边为参考进行定向。

(源自 ISO 32000-1 中的表179 - 特定于文本标记注释的其他条目)

因此,与其给出由矩形给出的矩形,
PDRectangle rect = pdfAnnot.getRectangle();

参考问题中的代码中,您需要考虑所给出的四边形。
COSArray quadsArray = (COSArray) pdfAnnot.getDictionary().getDictionaryObject(COSName getPDFName("QuadPoints"));

要根据需要为PDFTextStripperByArea stripper定义区域。不幸的是,PDFTextStripperByArea.addRegion期望一个矩形参数,而不是一些通用的四边形。由于文本通常是水平或垂直打印的,因此这应该不会引起太大问题。

PS有一个关于QuadPoints规范的警告,顺序在现实生活中的PDF中可能有所不同,请参阅问题PDF Spec vs Acrobat creation (QuadPoints)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接