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

使用PDFBox如何区分PDF页面中图片上层文字与被图片遮挡的底层文字

PDFBox 区分图片上下层文字的实现方案

核心逻辑是利用PDF页面内容流的绘制顺序规则:PDF 中所有元素的层级由它在内容流里的出现顺序决定,先写入的元素层级更低,后写入的元素层级更高。因此只要你拿到图片和所有文本元素的绘制顺序,就能直接判断遮挡关系。

具体实现步骤如下:

  • 第一步:自定义 PDFStreamEngine 子类,重写对应的操作符处理方法,同时记录所有元素的绘制顺序索引
    你需要同时监听图片绘制和文本绘制的操作符,每处理一个元素就给它分配一个自增的序号,代表它的绘制先后顺序
  • 第二步:收集所有图片的 BoundingBox 以及对应的绘制序号,同时收集所有文本块的 BoundingBox 和对应的绘制序号
  • 第三步:对每个落在图片 bbox 范围内的文本块,直接对比两者的绘制序号:
    • 如果文本的序号 < 图片的序号:文本绘制在图片之前,属于底层被遮挡的文字
    • 如果文本的序号 > 图片的序号:文本绘制在图片之后,属于叠在图片上层的文字

注意:如果页面有内容组(Form XObject)嵌套的情况,需要递归处理 XObject 内部的内容流,同样按内部的绘制顺序记录序号,避免层级判断错误。

核心代码参考片段:

// 自定义内容流处理器
public class LayerAwareContentExtractor extends PDFStreamEngine {
    private int drawOrder = 0;
    private List<ElementInfo> elements = new ArrayList<>();

    // 处理图片绘制操作符
    @Override
    protected void processOperator(Operator operator, List<COSBase> operands) throws IOException {
        if ("Do".equals(operator.getName())) {
            COSName name = (COSName) operands.get(0);
            PDXObject xobject = getResources().getXObject(name);
            if (xobject instanceof PDImageXObject) {
                // 记录图片的bbox和绘制序号
                Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
                Rectangle2D bbox = calculateImageBBox(ctm, (PDImageXObject)xobject);
                elements.add(new ElementInfo("image", bbox, drawOrder++));
            } else if (xobject instanceof PDFormXObject) {
                // 递归处理表单XObject内部内容
                processChildStream((PDFormXObject)xobject, getCurrentPage(), getGraphicsState().getCurrentTransformationMatrix());
            }
        }
        super.processOperator(operator, operands);
    }

    // 处理文本块,重写writeString方法
    @Override
    protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
        // 计算当前文本块的bbox
        Rectangle2D textBbox = calculateTextBBox(textPositions);
        elements.add(new ElementInfo("text", textBbox, drawOrder++));
        super.writeString(string, textPositions);
    }
}

你只需要遍历最终得到的 elements 列表,匹配 bbox 重叠的图片和文本,对比两者的 drawOrder 值就能直接得到层级关系。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 12:54:04