PDFBox 2.0.7 ExtractText无效,但1.8.13和PDFReader也有效

希望您能够了解使用pdfbox 2.0.7从PDF中提取文本时出了什么问题。 结果很奇怪:

使用1.8.13,命令java -jar pdfbox-app-1.8.13.jar ExtractText -sort -nonSeq test.pdf导致

 Deutsche Bank Privat- und Geschäftskunden AG Bruttoertrag 43,80 USD 37,15 EUR Kapitalertragsteuer (KESt) - 5,36 USD - 4,55 EUR Solidaritätszuschlag auf KESt - 0,29 USD - 0,25 EUR Umrechnungskurs USD zu EUR 1,1791000000 Gutschrift mit Wert 15.08.2017 32,35 EUR 

使用2.0.7,命令java -jar pdfbox-app-2.0.7.jar ExtractText -sort test.pdf导致

 aeutsche Bank mrivat- und deschäftskunden Ad Bruttoertrag QPIUM rpa PTINR bro hapitaäertragsteuer EhbptF - RIPS rpa - QIRR bro poäidaritätszuschäag auf hbpt - MIOV rpa - MIOR bro rmrechnungskurs rpa zu bro NINTVNMMMMMM dutschrift mit tert NRKMUKOMNT POIPR bro 

使用java -jar pdfbox-app-2.0.7.jar PDFDebugger test.pdf的调试器java -jar pdfbox-app-2.0.7.jar PDFDebugger test.pdfRoot/Pages/Kids/[1]/Contents/[1]显示正确的文本,因此以某种方式正确读取文本但未正确导出。

我试图比较两个PDFDebugger应用程序中显示的信息,但它们看起来与我完全相同(虽然我不知道在哪里/究竟要查找什么)。 不幸的是,我不能分享PDF文档。

我会很高兴有任何关于如何解决甚至只是解决这个问题的提示,否则我不能使用更新版本的pdfbox。 在此先感谢您的时间!

以下是文档中使用的Font的屏幕截图(使用2.0.7提取)。 这正是字母的翻译,显然没有执行:

pdfbox PDFDebugger的字体表

条目ToUnicode说

 %!PS-Adobe-3.0 Resource-CMap /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo <> def /CMapName /AdHoc-UCS def /CMapType 2 def 1 begincodespacerange   endcodespacerange 68 beginbfchar                                                                                                                                         endbfchar endcmap CMapName currentdict /CMap defineresource pop end end 

PDF的第2页的TextView已经显示了正确的文本,但是在上面显示的这些替换表在pdfbox导出之前似乎错误地修改了文本内容:

 Root/Pages/Kids/[1]/Contents/[1]: ================================= 0 Tw 0 Tc 0 0 0 rg 0 0 0 RG BT /F1 10 Tf 1 0 0 1 69.449 697.11 Tm (Wir) Tj 1 0 0 1 87.199 697.11 Tm (\374berweisen) Tj 1 0 0 1 141.099 697.11 Tm (den) Tj 1 0 0 1 160.549 697.11 Tm (Betrag) Tj 1 0 0 1 192.759 697.11 Tm (von) Tj 1 0 0 1 211.649 697.11 Tm (32,35) Tj 1 0 0 1 239.429 697.11 Tm (EUR) Tj 1 0 0 1 263.299 697.11 Tm (auf) Tj 1 0 0 1 279.959 697.11 Tm (Ihr) Tj 1 0 0 1 294.389 697.11 Tm (Konto) Tj 1 0 0 1 323.269 697.11 Tm (XXXXXXX) Tj 1 0 0 1 364.959 697.11 Tm (XX) Tj 1 0 0 1 376.079 697.11 Tm (.) Tj 0 G 0 g ET 69.449 669.448 m 69.449 669.698 l 549.921 669.698 l 549.921 669.448 l 549.921 669.198 l 69.449 669.198 l h f 0 0 0 rg 0 0 0 RG BT /F1 6 Tf 1 0 0 1 249.022 658.948 Tm (Kapitalertr\344ge) Tj 1 0 0 1 288.016 658.948 Tm (sind) Tj 1 0 0 1 300.682 658.948 Tm (einkommensteuerpflichtig!) Tj 1 0 0 1 213.865 652.783 Tm (Diese) Tj 1 0 0 1 230.863 652.783 Tm (Mitteilung) Tj 1 0 0 1 258.187 652.783 Tm (wurde) Tj 1 0 0 1 276.187 652.783 Tm (maschinell) Tj 1 0 0 1 306.187 652.783 Tm (erstellt) Tj 1 0 0 1 325.507 652.783 Tm (und) Tj 1 0 0 1 337.177 652.783 Tm (wird) Tj 1 0 0 1 349.837 652.783 Tm (nicht) Tj 1 0 0 1 364.165 652.783 Tm (unterschrieben.) Tj 0 G 0 g ET q 1 0 0 1 504.562 772.646 cm 1 0 0 1 0 0 cm q 0 Tw 0 Tc 45.36 0 0 45.36 0 0 cm /I0 Do Q Q 0 0 0 rg 0 0 0 RG BT /F1 10.5 Tf 1 0 0 1 552.756 23.464 Tm (2) Tj 1 0 0 1 558.594 23.464 Tm (/) Tj 1 0 0 1 561.503 23.464 Tm (2) Tj ET Q q 0 0 m 0 841.89 l 595.276 841.89 l 595.276 0 l h 0 0 m 595.276 0 l 595.276 841.89 l 0 841.89 l h W n Q 

1.8.13显示:

 Wir überweisen den Betrag von 32,35 EUR auf Ihr Konto XXXXXXX XX. Kapitalerträge sind einkommensteuerpflichtig! Diese Mitteilung wurde maschinell erstellt und wird nicht unterschrieben. 2/2 

2.0.7显示:

 tir überweisen den Betrag von POIPR bro auf fhr honto XXXXXXX XX hapitaäerträge sind einkommensteuerpfäichtig! aiese jitteiäung wurde maschineää ersteäät und wird nicht unterschriebenK O/O 

这是您要求的文件: https : //wetransfer.com/downloads/214674449c23713ee481c5a8f529418320170827201941/b2bea6

有关PDF中所用字体的信息是矛盾的,部分是破碎的 。 根据某些软件对其的反应,它可能会或可能不会正确提取文本。


一方面,该字体具有编码WinAnsiEncoding 。 这是可以的,并且匹配我们在内容流中看到的内容,一个包含许多ANSI代码的单字节编码。

另一方面,我们有一个ToUnicode映射,暗示底层编码是一些双字节编码(它有一个代码空间范围<0000> ),即使忽略了双字节性质,它也有映射其中特别是将数字ANSI代码映射为大写字母,将大写字母ANSI代码映射到其他小写字母,将小写字母“l”ANSI代码映射到“ä”的Unicode值。

在提取文本时,PDFBox 2.0.x似乎遵循破坏的ToUnicode映射(将表中的双字节代码解释为单字节代码,忽略大写0)尽可能(导致垃圾)并将字符代码解释为ANSI(产生正确的文本)。 PDF 1.8.x似乎忽略了ToUnicode地图,Adobe Reader也是如此。


实际上,看起来像是使用Identity-H编码为字体制作了ToUnicode映射。


如果您遇到这样的PDF并需要提取其文本,您可以预处理它并删除ToUnicode条目; 此后文本提取应返回正确的文本。 例如

 PDDocument document = PDDocument.load(SOURCE); for (int pageNr = 0; pageNr < document.getNumberOfPages(); pageNr++) { PDPage page = document.getPage(pageNr); PDResources resources = page.getResources(); removeToUnicodeMaps(resources); } PDFTextStripper stripper = new PDFTextStripper(); String text = stripper.getText(document); 

( ExtractText测试方法testNoToUnicodeTest2

使用辅助方法

 void removeToUnicodeMaps(PDResources pdResources) throws IOException { COSDictionary resources = pdResources.getCOSObject(); COSDictionary fonts = asDictionary(resources, COSName.FONT); if (fonts != null) { for (COSBase object : fonts.getValues()) { while (object instanceof COSObject) object = ((COSObject)object).getObject(); if (object instanceof COSDictionary) { COSDictionary font = (COSDictionary)object; font.removeItem(COSName.TO_UNICODE); } } } for (COSName name : pdResources.getXObjectNames()) { PDXObject xobject = pdResources.getXObject(name); if (xobject instanceof PDFormXObject) { PDResources xobjectPdResources = ((PDFormXObject)xobject).getResources(); removeToUnicodeMaps(xobjectPdResources); } } } COSDictionary asDictionary(COSDictionary dictionary, COSName name) { COSBase object = dictionary.getDictionaryObject(name); return object instanceof COSDictionary ? (COSDictionary) object : null; } 

(来自ExtractText )

您应该在加载文档后尽早执行此预处理,以防止包含错误的ToUnicode映射的字体被读入文档字体缓存。