Java 如何在PDFTextStripperByArea中定义区域?

Java 如何在PDFTextStripperByArea中定义区域?,java,apache,pdf,pdfbox,Java,Apache,Pdf,Pdfbox,我正在使用PDFBox从PDF文件中提取文本。我面临的一个问题是:PDFBox将主要内容与我想忽略的PDF页脚/页眉部分混为一谈 我被告知以下代码将有所帮助: Rectangle rec = new Rectangle(); # init rec... PDFTextStripperByArea stripper = new PDFTextStripperByArea(); stripper.addRegion("cropbox", rec); stripper.setSortByPositi

我正在使用PDFBox从PDF文件中提取文本。我面临的一个问题是:PDFBox将主要内容与我想忽略的PDF页脚/页眉部分混为一谈

我被告知以下代码将有所帮助:

Rectangle rec = new Rectangle();
# init rec...
PDFTextStripperByArea stripper = new PDFTextStripperByArea();
stripper.addRegion("cropbox", rec); 
stripper.setSortByPosition(true);
谁能告诉我剥离器.setSortByPosition(true)的确切含义是什么?我阅读了文档,但仍然感到困惑:

当我使用上述代码从PDF文件中提取文本时,我得到了以下错误:

Exception in thread "main" java.lang.IllegalArgumentException:
Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:747)
at java.util.TimSort.mergeAt(TimSort.java:483)
at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at org.apache.pdfbox.util.PDFTextStripper.writePage(PDFTextStripper.java:565)
at org.apache.pdfbox.util.PDFTextStripperByArea.writePage(PDFTextStripperByArea.java:190)
at org.apache.pdfbox.util.PDFTextStripper.processPage(PDFTextStripper.java:457)
at org.apache.pdfbox.util.PDFTextStripperByArea.extractRegions(PDFTextStripperByArea.java:153)
有人能帮我修一下吗

PS:以下是
setSortByPosition
的文档,供您参考:

PDF文件中文本标记的顺序可能与屏幕上显示的顺序不同。例如,PDF编写器可能会按字体写出所有文本,也就是所有粗体或更大的文本,然后进行第二次传递并写出正常文本

默认情况下,不按位置排序

PDF编写器可以选择以不同的顺序编写每个字符。默认情况下,由于性能原因,PDFBox在处理文本标记之前不会对其进行排序

缴费灵: @蒂尔曼·豪瑟:这是一个已知的问题:-(

请参阅:issues.apache.org/jira/browse/PDFBOX-1512

更新: 避免这些例外情况的一种可能方法[1]是:

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

[1]

我查看了源代码,发现他们的
TextPositionComparator
Comparator
用于对文本位置进行排序)似乎违反了合同在这种情况下可能会引发异常;PDFBox似乎仍然与java 4兼容,并且他们计划更新到java 6的版本2.0,因此可能不是最新版本……)

您最好将这个错误告知开发者()。但是您可以下载源代码并自己更改比较器。我很确定错误在代码的第63行(版本1575836)

在那里,它们允许y值有一定的公差。您可以找到违反
比较器
接口契约部分的文本位置:

实现者还必须确保关系是可传递的:((compare(x,y)>0)&(compare(y,z)>0))意味着compare(x,z)>0


显示违反条件是可能的:选择
TextPosition.getYDirAdj()
(posYBottom)设置为0、0.05和0.11,并确保第64行和第65行中的条件为false,通过选择正确的x位置,您可以从3个
比较
结果中选择1个。

此问题与已被JDK7替换的
Collections.sort(List)
方法有关。有关详细信息,请参阅 :

领域:API:实用程序概要:更新了数组和 集合可能会抛出IllegalArgumentException描述: java.util.Arrays.sort使用的排序算法和(间接)通过 已替换java.util.Collections.sort。新的排序 如果实现检测到异常,它可能会抛出IllegalArgumentException 可比的违反可比合同的。先前的 实现过程默认忽略了这种情况 如果需要行为,可以使用新的系统属性, java.util.Arrays.useLegacyMergeSort,以还原以前的mergesort 行为。不相容性的性质:行为RFE:6804124

要解决此问题,请使用该代码:

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

这将把排序算法设置为JDK7之前的行为。对我来说非常有效…

Q:有人能告诉我stripper.setSortByPosition(true)的确切含义吗


答:我对PDF格式的理解是它由字符组成(这里只讨论文本)使用相对于页面左下角的坐标精确放置。在编写PDF时,这些字符不必以一个不间断的顺序插入,而是从左到右、从上到下插入。因此,通过将SortByPosition设置为true,您告诉PdfBox尝试使用顺序对字符进行排序w将字符显示在屏幕上,而不是PDF文件中字符的顺序。

这是正确的,但是请参见Uwe在PDFBOX-1512中的评论:“解决方法的问题是需要在应用程序之外完成”。无论如何,它将在即将发布的版本1.8.8:-)中得到解决,这是个好消息!什么时候发布?仅出于您的兴趣:我使用了25本书的样本,只有几页出现了问题。出现问题的所有页面都是带有以下内容的页面:数字、表格、图表或数学公式(简单的文本页面对我来说不会引发问题)。它将在1.8.8版(可能是今年)中修复。将来对此进行更新:PDFBox中不再出现此错误,因为他们切换到了自己的快速排序算法,这实际上与设置“useLegacyMergeSort”相同,但在PDFBox中使用它会影响可能确实希望执行这些检查的其他排序。比较器与以往一样。这里有更多关于这方面的讨论: