如何在PDFTextStripperByArea中定义区域?

时间:2014-04-30 00:16:56

标签: java apache pdf pdfbox

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

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

Rectangle rec = new Rectangle();
# init rec...
PDFTextStripperByArea stripper = new PDFTextStripperByArea();
stripper.addRegion("cropbox", rec); 
stripper.setSortByPosition(true);

有人可以告诉我stripper.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在处理之前不会对文本标记进行排序。

PPS: @Tilman Hausherr:这是一个已知问题:-(

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

更新: 避免这些例外的一种可能方式是:

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

[1] https://issues.apache.org/jira/browse/PDFBOX-1512?focusedCommentId=13937402&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13937402

3 个答案:

答案 0 :(得分:1)

我查看了源代码,发现他们的TextPositionComparatorComparator用于排序文本位置)似乎违反了合同。 (在这种情况下,TimSort [java 7+]可能会抛出异常; PDFBox似乎仍然与java 4兼容,并且他们计划更新到Java 6 for version 2.0,因此它们可能不是最新的...)

您最好告知开发人员(PDFBox)该错误。但是,您可以下载源代码并自行更改比较器。我很确定错误在TextPositionComparator的第63行(修订版1575836)中。

他们允许y值有一些容差。您可以提出违反Comparator界面合同一部分的TextPosition:

实现者还必须确保关系是传递的:((compare(x,y)> 0)&&(compare(y,z)> 0))暗示比较(x, Z)> 0

要显示违反此条件的行为:选择TextPosition.getYDirAdj()(posYBottom)为0,0.05和0.11,并确保第64,65行中的条件为false并且您可以通过正确选择x位置来选择3个compare结果中的1个。

答案 1 :(得分:0)

此问题与Collections.sort(List<E> list)方法有关,该方法已被JDK7取代。对于进一步的信息看 here

  

区域:API:实用程序概要:更新了阵列和的排序行为   集合可能抛出IllegalArgumentException描述:   java.util.Arrays.sort使用的排序算法和(间接)by   java.util.Collections.sort已被替换。新的排序   如果检测到,实现可能会抛出IllegalArgumentException   违反可比较合同的可比较。以前的   实施默默地忽略了这种情况。如果是以前的   行为是理想的,你可以使用新的系统属性,   java.util.Arrays.useLegacyMergeSort,用于恢复以前的mergesort   行为。不相容性:行为RFE:6804124

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

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

这会将排序算法设置为JDK7之前的行为。为我工作得很好......

答案 2 :(得分:0)

问:有人能告诉我stripper.setSortByPosition(true)究竟是什么意思吗?

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