You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PDFBox 2.0.20如何检测page.getAnnotations()返回空时的PDF遮盖高亮文本

基于PDFBox 2.0.20检测黑块遮盖文本的解决方案

你调用page.getAnnotations()返回空列表,是因为该PDF中的黑色遮盖块不属于注释类对象,而是直接写在页面内容流中的矢量填充矩形,和页面文本属于同一层级的绘制内容,因此无法通过注释接口捕获。

可按照以下思路实现检测:

实现逻辑

  • 第一步:自定义内容流处理器,提取目标页面所有绘制指令,筛选出填充色为纯黑的矩形对象,记录每个矩形的坐标、宽高参数
  • 第二步:提取目标页面所有文本片段,记录每个文本片段的包围盒坐标、内容信息
  • 第三步:做空间重叠校验,若文本片段的包围盒与黑色矩形的包围盒重合度超过80%,即可判定该文本为被黑块遮盖的目标文本

核心代码示例

import org.apache.pdfbox.contentstream.PDFStreamEngine;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
import org.apache.pdfbox.text.PDFTextStripperByArea;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// 自定义流处理器,提取黑矩形区域
public class BlackMaskExtractor extends PDFStreamEngine {
    private final List<Rectangle> blackMasks = new ArrayList<>();
    private PDColor currentNonStrokingColor;

    @Override
    protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
        String opName = operator.getName();
        // 捕获设置非描边颜色指令
        if ("scn".equals(opName) || "sc".equals(opName)) {
            currentNonStrokingColor = getGraphicsState().getNonStrokingColor();
        }
        // 捕获矩形绘制指令
        else if ("re".equals(opName)) {
            float x = ((org.apache.pdfbox.cos.COSNumber) operands.get(0)).floatValue();
            float y = ((org.apache.pdfbox.cos.COSNumber) operands.get(1)).floatValue();
            float width = ((org.apache.pdfbox.cos.COSNumber) operands.get(2)).floatValue();
            float height = ((org.apache.pdfbox.cos.COSNumber) operands.get(3)).floatValue();
            // 判断是否为纯黑填充
            if (currentNonStrokingColor != null && currentNonStrokingColor.toRGB() == Color.BLACK.getRGB()) {
                // 坐标系转换适配:PDF默认原点在左下角,适配文本提取常用的左上角坐标系
                int pageHeight = (int) getCurrentPage().getMediaBox().getHeight();
                Rectangle rect = new Rectangle((int)x, pageHeight - (int)y - (int)height, (int)width, (int)height);
                blackMasks.add(rect);
            }
        }
        super.processOperator(operator, operands);
    }

    public List<Rectangle> getBlackMasks() {
        return blackMasks;
    }
}

// 调用示例
public class MaskedTextDetector {
    public static void main(String[] args) throws IOException {
        PDDocument document = PDDocument.load(new File("Manafort-response.pdf"));
        // 目标页为5、6、7、9,PDFBox页码从0开始,对应索引为4、5、6、8
        int[] targetPageIndexes = new int[]{4,5,6,8};
        for (int pageIndex : targetPageIndexes) {
            PDPage page = document.getPage(pageIndex);
            // 提取当前页所有黑块区域
            BlackMaskExtractor maskExtractor = new BlackMaskExtractor();
            maskExtractor.processPage(page);
            List<Rectangle> masks = maskExtractor.getBlackMasks();
            // 提取黑块覆盖区域的文本
            PDFTextStripperByArea textStripper = new PDFTextStripperByArea();
            for (int i = 0; i < masks.size(); i++) {
                textStripper.addRegion("mask_" + i, masks.get(i));
            }
            textStripper.extractRegions(page);
            // 输出结果
            for (int i = 0; i < masks.size(); i++) {
                String maskedText = textStripper.getTextForRegion("mask_" + i);
                if (!maskedText.trim().isEmpty()) {
                    System.out.printf("第%d页,第%d个黑块下的文本:%s%n", pageIndex + 1, i + 1, maskedText.trim());
                }
            }
        }
        document.close();
    }
}

注意事项

  • 坐标适配:如果你的文本提取逻辑用的是原生PDF坐标系,可删除坐标转换的逻辑,避免坐标不匹配导致漏判
  • 阈值调整:如果存在部分遮盖的场景,可根据需求调整重叠度判定的阈值,默认80%的重合度即可判定为被遮盖文本
  • 图片遮盖适配:如果后续遇到用图片做遮盖的场景,需要额外提取页面中的图片区域,再和文本做重叠校验,本次目标PDF的遮盖为矢量矩形,无需额外处理图片逻辑

内容的提问来源于stack exchange,提问作者Ahmad AlMughrabi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:45:03