使用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
相关产品推荐
相关产品推荐

