使用iText提取PDF高亮文本失败,求问题排查与方案建议
问题分析
你的代码无法提取高亮文本的核心原因有几个:
- 错误依赖
CONTENTS字段:PDF的高亮注释中,CONTENTS字段通常存储注释备注文字,而非被高亮的页面文本,多数情况下这个字段为空。真正要通过注释的QuadPoints定位页面高亮区域,再提取对应文本。 - 未处理间接引用:注释数组(
ANNOTS)中的元素可能是PdfIndirectReference类型,直接转PdfDictionary会失败,需先解析引用。 - 返回值未拼接结果:代码中
highlightedText始终为空,没有将提取到的文本拼接进去。
更优实现方式(iText 7版本)
以下是修正后的代码,通过解析高亮注释的QuadPoints定位文本区域,再提取对应内容:
import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.*; import com.itextpdf.kernel.pdf.canvas.parser.PdfTextExtractor; import com.itextpdf.kernel.pdf.canvas.parser.filter.TextRegionEventFilter; import com.itextpdf.kernel.pdf.canvas.parser.listener.FilteredTextEventListener; import com.itextpdf.kernel.pdf.canvas.parser.listener.LocationTextExtractionStrategy; import java.io.IOException; import java.util.ArrayList; import java.util.List; public String getHighlightedText() { StringBuilder highlightedText = new StringBuilder(); String pdfFilePath = "test.pdf"; try (PdfReader reader = new PdfReader(pdfFilePath); PdfDocument pdfDoc = new PdfDocument(reader)) { for (int pageNum = 1; pageNum <= pdfDoc.getNumberOfPages(); pageNum++) { PdfPage page = pdfDoc.getPage(pageNum); PdfArray annotsArray = page.getPdfObject().getAsArray(PdfName.ANNOTS); if (annotsArray == null) { continue; } for (int i = 0; i < annotsArray.size(); i++) { PdfObject annotObj = annotsArray.get(i); // 处理间接引用 if (annotObj instanceof PdfIndirectReference) { annotObj = ((PdfIndirectReference) annotObj).getRefersTo(); } if (!(annotObj instanceof PdfDictionary)) { continue; } PdfDictionary annotDict = (PdfDictionary) annotObj; if (PdfName.HIGHLIGHT.equals(annotDict.getAsName(PdfName.SUBTYPE))) { // 获取QuadPoints,每个高亮区域由8个数值组成(x1,y1,x2,y2,x3,y3,x4,y4) PdfArray quadPoints = annotDict.getAsArray(PdfName.QuadPoints); if (quadPoints == null) { continue; } // 将QuadPoints转换为文本提取的过滤区域 List<Rectangle> rectangles = new ArrayList<>(); for (int j = 0; j < quadPoints.size(); j += 8) { float x1 = quadPoints.getAsNumber(j).floatValue(); float y1 = quadPoints.getAsNumber(j + 1).floatValue(); float x3 = quadPoints.getAsNumber(j + 4).floatValue(); float y3 = quadPoints.getAsNumber(j + 5).floatValue(); // 构建矩形区域(取对角点即可) rectangles.add(new Rectangle(Math.min(x1, x3), Math.min(y1, y3), Math.abs(x3 - x1), Math.abs(y3 - y1))); } // 提取指定区域的文本 TextRegionEventFilter filter = new TextRegionEventFilter(rectangles); LocationTextExtractionStrategy strategy = new LocationTextExtractionStrategy(); FilteredTextEventListener filteredListener = new FilteredTextEventListener(strategy, filter); String extractedText = PdfTextExtractor.getTextFromPage(page, filteredListener); if (!extractedText.isEmpty()) { highlightedText.append(extractedText).append("\n"); } } } } } catch (IOException e) { e.printStackTrace(); } return highlightedText.toString().trim(); }
说明:
- 用
QuadPoints定位高亮区域,这是PDF标准中存储高亮位置的字段。 - 处理了注释的间接引用,避免类型转换失败。
- 通过
TextRegionEventFilter过滤指定区域文本,确保提取的是高亮内容。 - 用
StringBuilder高效拼接结果,减少内存浪费。
可用替代库
- Apache PDFBox:Apache开源PDF处理库,API直观,支持注释解析和区域文本提取,是iText的主流替代方案。
- PDFClown:跨平台PDF操作库,提供面向对象的API,支持注释和文本提取功能。
- Aspose.PDF for Java:商业库,功能全面,对复杂PDF兼容性较好,但需付费授权。
内容的提问来源于stack exchange,提问作者Yogeshwar Chaturvedi
相关产品推荐
相关产品推荐

