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

使用iText7按指定位置提取PDF文本时提取范围不符的问题

解决iText7提取PDF特定区域文本范围过大的问题

我之前用iText7做PDF文本提取时也碰到过一模一样的问题——明明Rectangle尺寸是对的,但提取出来的文本总是超出目标范围。结合你的代码和常见的坑,大概率是两个原因:PDF坐标系统搞反了,或者默认的过滤器太宽松。下面给你一步步解决的方案:

1. 先确认并修正PDF的坐标系统

PDF的坐标系和我们日常认知的不一样:它的原点在页面左下角,y轴是向上延伸的。很多人会下意识地从页面顶部开始计算y值,这就会导致Rectangle的位置完全错了,自然提取范围不对。

你可以先把原来的Rectangle转换成PDF标准坐标系的位置,代码示例:

// 获取当前页面的尺寸
Rectangle pageSize = page.getPageSize();
// 取出你定义的原始区域
Rectangle originalRect = value.getDim();
// 把原始的y值(假设是从页面顶部往下的距离)转换成PDF坐标系的左下角y值
float correctedY = pageSize.getHeight() - originalRect.getY() - originalRect.getHeight();
// 生成修正后的区域
Rectangle correctedRect = new Rectangle(originalRect.getX(), correctedY, originalRect.getWidth(), originalRect.getHeight());

2. 替换默认过滤器为更严格的自定义过滤器

默认的TextRegionEventFilter有个坑:只要文本的任何一部分落在区域内,就会把整个文本串都提取出来。比如目标区域旁边的单词有一个字母的边缘和区域重叠,整个单词都会被包含进去,这就是你觉得范围过大的原因。

我们可以自定义一个过滤器,只提取完全落在目标区域内的文本(或者你可以调整规则,比如允许80%以上的文本在区域内):

class StrictTextRegionEventFilter extends EventFilter {
    private final Rectangle targetRegion;

    public StrictTextRegionEventFilter(Rectangle targetRegion) {
        this.targetRegion = targetRegion;
    }

    @Override
    public boolean accept(IEventData data, EventType type) {
        // 只处理文本渲染事件
        if (type.equals(EventType.RENDER_TEXT)) {
            TextRenderInfo renderInfo = (TextRenderInfo) data;
            // 获取当前文本块的 bounding box
            Rectangle textBbox = renderInfo.getBoundingBox();
            // 规则:只有文本块完全落在目标区域内才提取
            return targetRegion.contains(textBbox);
            
            // 如果需要宽松一点的规则(比如文本块80%以上在区域内),可以用下面的代码替换上面的return
            // float intersectionArea = targetRegion.getIntersection(textBbox).getArea();
            // float textArea = textBbox.getArea();
            // return textArea > 0 && (intersectionArea / textArea) >= 0.8f;
        }
        return false;
    }
}

3. 修改你的提取代码

把原来的过滤器替换成我们自定义的,同时用修正后的Rectangle:

private void estraiValori(PdfPage page) {
    Rectangle pageSize = page.getPageSize();
    for (Entry<String, Elemento> entry : templateMap.entrySet()) {
        String key = entry.getKey();
        Elemento value = entry.getValue();
        
        // 修正坐标
        Rectangle originalRect = value.getDim();
        float correctedY = pageSize.getHeight() - originalRect.getY() - originalRect.getHeight();
        Rectangle correctedRect = new Rectangle(originalRect.getX(), correctedY, originalRect.getWidth(), originalRect.getHeight());
        
        // 使用自定义严格过滤器
        StrictTextRegionEventFilter strictFilter = new StrictTextRegionEventFilter(correctedRect);
        FilteredEventListener listener = new FilteredEventListener();
        // 两种策略都可以用,这里以SimpleTextExtractionStrategy为例
        SimpleTextExtractionStrategy extractionStrategy = listener.attachEventListener(new SimpleTextExtractionStrategy(), strictFilter);
        new PdfCanvasProcessor(listener).processPageContent(page);
        
        // 去掉多余的空格和换行
        String actualText = extractionStrategy.getResultantText().trim();
        System.out.println(actualText);
    }
}

你可以先测试坐标修正后的效果,如果还是有多余文本,再启用自定义过滤器的严格规则,应该就能精准提取到目标区域的文本了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:31:16