java - PDF 中的文本以不同方式吐出

标签 java parsing pdf itext pdfbox

我正在使用 iText 阅读 pdf 文档页面中的文本。 PDF中有两行完全相同,但解析后的输出两行不同。 iText 库以不同方式输出文本的原因可能是什么?两条线(串)的长度相同。

使用的 iText 方法:

String text = PdfTextExtractor.getTextFromPage(reader, 1);

当我检查“text”元素时,输出如下。然而,这三行在 pdf 中似乎完全相同。

XXXXXX XXXXX XXXXX : XXXXX :
#*2 1
XXXXXX XXXXX XXXXX : #*3 XXXXX : 2
XXXXXX XXXXX XXXXX : XXXXX :
#15 1

编辑:额外问题: 当我使用 PDFBox 时,解析的输出有很大不同。为什么使用 iText 与 PDFBox 时输出文本存在差异?

最佳答案

虽然在屏幕截图中,各行看起来都处于恒定的水平,

screenshot

他们实际上不是。 “XXX...:”和“TOTAL :”部分位于 y 坐标 469.45、457.95 和 446.45,而“#..”、“1”和“2”部分位于y 坐标 468.65、457.15 和 445.65。

为了将水平文本视为在同一行,使用默认文本提取策略 (LocationTextExtractionStrategy) 的 iText 文本提取要求转换后的 y 坐标相同到int。 (实际上这有点简化,整个情况请看LocationTextExtractionStrategy.TextChunkLocationDefaultImp)

在当前的情况下,这仅是中间行的情况,(int) 457.95 = 457 = (int) 457.15。因此,默认文本提取结果是:

XXXXXX XXXXX XXXXX : TOTAL :
#*2 1
XXXXXX XXXXX XXXXX : #*3 TOTAL : 2
XXXXXX XXXXX XXXXX: TOTAL :
#15 1
<小时/>

在这种情况下,您需要一种能够以不同方式识别行的文本提取策略。如果你例如使用HorizontalTextExtractionStrategyHorizontalTextExtractionStrategy2 (取决于您的 iText 版本,前一个适用于最高 iText 5.5.8,后一个适用于较新的 iText 5.5.x 版本)来自 this answer ,你会得到:

XXXXXX XXXXX XXXXX : #*2 TOTAL : 1
XXXXXX XXXXX XXXXX : #*3 TOTAL : 2
XXXXXX XXXXX XXXXX: #15 TOTAL : 1

(使用 TextExtraction.java 测试方法 testTest_pdf() 进行测试)

<小时/>

顺便说一句,这并不意味着默认情况下应该切换到 Horizo​​ntalTextExtractionStrategy2。此方法也有其缺点,特别是它会查看整个页面(或至少整个页面部分,如果通过过滤器提取)宽度来查找行。因此,如果您的页面例如有两列彼此相连的文本,并且每列的行的高度大致相同,此策略可能会返回完全垃圾。

附录

OP 在评论中询问

Can you give me a brief explanation of what the HorizontalTextExtractionStrategy is doing?

在扫描页面时,此策略仅从文本绘制指令中收集文本 block 及其边界框坐标。

当要求提供结果文本时,它会首先将所有这些边界框投影到页面坐标系的 y 轴上。

在第二遍中,它将此投影图像的每个连通分量解释为单线的 y 坐标范围:它从上到下迭代这些连通分量;对于每个组件,它会将所有 block 投影到其中,按其 x 坐标对它们进行排序,在适当的位置添加空格,然后将它们合并到文本行。

最后它返回这些行的串联(中间有换行符)。

LocationTextExtractionStrategy says "This renderer keeps track of the orientation and distance (both perpendicular and parallel) to the unit vector of the orientation. Text is ordered by orientation, then perpendicular, then parallel distance. Text with the same perpendicular distance, but different parallel distance is treated as being on the same line." That does not make a lot of sense to me.

本质上,它也是一种双 channel 策略,在第一 channel 中收集所有带有坐标的文本 block ,在第二 channel 中将它们排列为行。不过,该策略考虑了 block 基线的方向,并首先按基线角度进行排序。

在具有相同基线角度的 block 中,如果它们的(有界)基线位于同一(无界)行上,则认为这些 block 属于同一文本行。

被认为属于同一文本行的 block 将按照书写方向进行排序,并在适当的位置插入空格。

此策略进行的比较均基于 int 值,因此允许微小的差异

关于java - PDF 中的文本以不同方式吐出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37307289/

相关文章:

java - 如果日期无效,Spring mvc Joda Datetime 转换器将失败

java - 在 Java 中的特定时间运行程序或方法

c++ - 用qi和其他部分解析为结构

java - 从文本字符串中解析日期

android - 我怎样才能从 sdcard 打开 pdf 我可以从 Assets 文件夹

java - 如何使用 Hibernate Validator 动态解析消息参数?

java - LocalDateTime 带有附加注释

Python path.join 在 Mac 和 Windows 中运行时的行为不同

java - 我可以仅使用输入在 iText 中生成上标吗?

r - 有没有办法将 grob 直接保存到 rasterGrob?