PDF 中的文本以不同方式吐出
Text from PDF spitting out differently
我正在使用 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 时输出文本不同?
虽然在屏幕截图中,行看起来像它们一样,但每行都处于恒定水平,
他们实际上不是。 '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
在这种情况下,您需要一种以不同方式识别行的文本提取策略。如果你例如使用 HorizontalTextExtractionStrategy
or HorizontalTextExtractionStrategy2
(depending on your iText version, the former one for up to iText 5.5.8, the latter one for newer iText 5.5.x versions) from this answer,你会得到:
XXXXXX XXXXX XXXXX : #*2 TOTAL : 1
XXXXXX XXXXX XXXXX : #*3 TOTAL : 2
XXXXXX XXXXX XXXXX: #15 TOTAL : 1
(使用 TextExtraction.java 测试方法 testTest_pdf()
测试)
顺便说一句,这并不意味着应该默认切换到 HorizontalTextExtractionStrategy2
。这种方法也有它的缺点,特别是它会查看整个页面(或者至少是整个页面部分,如果通过过滤器提取)宽度来查找行。因此,如果您的页面例如有两列文本相互连接,并且每列的行只有相同的近似高度,这种策略可能 return 完全是垃圾。
附录
OP 在评论中提问
Can you give me a brief explanation of what the HorizontalTextExtractionStrategy
is doing?
在扫描页面时,此策略仅从文本绘制指令中收集文本块及其边界框坐标。
当要求生成文本时,它会在第一遍中将所有这些边界框投影到页面坐标系的 y 轴上。
在第二遍中,它将此投影图像的每个连通分量解释为单条线的 y 坐标范围:它从上到下遍历这些连通分量-底部;对于每个组件,它获取所有投影到其中的块,按它们的 x 坐标对它们进行排序,在适当的地方添加空格,并将它们合并到文本行中。
最后 return 是这些行的串联(中间有换行符)。
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.
本质上它也是一个双遍策略,在第一遍中收集所有带有坐标的文本块,在第二遍中将它们排列成行。不过,此策略考虑了块基线的方向,并首先按基线角度排序。
在具有相同基线角度的块中,如果它们的(有界)基线在同一(无界)行上,它认为块属于同一文本行。
然后将被认为属于同一文本行的块按书写方向排序,并在适当的地方插入空格。
此策略进行的比较均基于 int
值,因此允许有微小差异
我正在使用 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 时输出文本不同?
虽然在屏幕截图中,行看起来像它们一样,但每行都处于恒定水平,
他们实际上不是。 '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
在这种情况下,您需要一种以不同方式识别行的文本提取策略。如果你例如使用 HorizontalTextExtractionStrategy
or HorizontalTextExtractionStrategy2
(depending on your iText version, the former one for up to iText 5.5.8, the latter one for newer iText 5.5.x versions) from this answer,你会得到:
XXXXXX XXXXX XXXXX : #*2 TOTAL : 1
XXXXXX XXXXX XXXXX : #*3 TOTAL : 2
XXXXXX XXXXX XXXXX: #15 TOTAL : 1
(使用 TextExtraction.java 测试方法 testTest_pdf()
测试)
顺便说一句,这并不意味着应该默认切换到 HorizontalTextExtractionStrategy2
。这种方法也有它的缺点,特别是它会查看整个页面(或者至少是整个页面部分,如果通过过滤器提取)宽度来查找行。因此,如果您的页面例如有两列文本相互连接,并且每列的行只有相同的近似高度,这种策略可能 return 完全是垃圾。
附录
OP 在评论中提问
Can you give me a brief explanation of what the
HorizontalTextExtractionStrategy
is doing?
在扫描页面时,此策略仅从文本绘制指令中收集文本块及其边界框坐标。
当要求生成文本时,它会在第一遍中将所有这些边界框投影到页面坐标系的 y 轴上。
在第二遍中,它将此投影图像的每个连通分量解释为单条线的 y 坐标范围:它从上到下遍历这些连通分量-底部;对于每个组件,它获取所有投影到其中的块,按它们的 x 坐标对它们进行排序,在适当的地方添加空格,并将它们合并到文本行中。
最后 return 是这些行的串联(中间有换行符)。
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.
本质上它也是一个双遍策略,在第一遍中收集所有带有坐标的文本块,在第二遍中将它们排列成行。不过,此策略考虑了块基线的方向,并首先按基线角度排序。
在具有相同基线角度的块中,如果它们的(有界)基线在同一(无界)行上,它认为块属于同一文本行。
然后将被认为属于同一文本行的块按书写方向排序,并在适当的地方插入空格。
此策略进行的比较均基于 int
值,因此允许有微小差异