2017-08-26 41 views
1

希望您对使用pdfbox 2.0.7从PDF中提取文本时出了什么问题有所了解。其结果是很奇怪:PDFBox 2.0.7 ExtractText不起作用,但1.8.13和PDFReader以及

使用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调试器显示在Root/Pages/Kids/[1]/Contents/[1]正确的文本,所以不知何故文本被正确读取,但没有正确导出。

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

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

下面是在文档中使用的字体(用2.0.7提取)的屏幕截图。这正是显然不进行字母的翻译:

font table from pdfbox PDFDebugger

入口ToUnicode说

%!PS-Adobe-3.0 Resource-CMap 
/CIDInit /ProcSet findresource begin 
12 dict begin 
begincmap 
/CIDSystemInfo 
<< /Registry (Adobe) 
/Ordering (UCS) 
/Supplement 0 
>> def 
/CMapName /AdHoc-UCS def 
/CMapType 2 def 
1 begincodespacerange 
<0000> <FFFF> 
endcodespacerange 
68 beginbfchar 
<0004> <0021> 
<0009> <0026> 
<000b> <0028> 
<000c> <0029> 
<000f> <002c> 
<0010> <002d> 
<0011> <002e> 
<0012> <002f> 
<0013> <0030> 
<0014> <0031> 
<0015> <0032> 
<0016> <0033> 
<0017> <0034> 
<0018> <0035> 
<0019> <0036> 
<001a> <0037> 
<001b> <0038> 
<001c> <0039> 
<001d> <003a> 
<001e> <003b> 
<0024> <0041> 
<0025> <0042> 
<0026> <0043> 
<0027> <0044> 
<0028> <0045> 
<0029> <0046> 
<002a> <0047> 
<002b> <0048> 
<002c> <0049> 
<002e> <004b> 
<0030> <004d> 
<0031> <004e> 
<0032> <004f> 
<0033> <0050> 
<0034> <0051> 
<0035> <0052> 
<0036> <0053> 
<0037> <0054> 
<0038> <0055> 
<0039> <0056> 
<003a> <0057> 
<003d> <005a> 
<0044> <0061> 
<0045> <0062> 
<0046> <0063> 
<0047> <0064> 
<0048> <0065> 
<0049> <0066> 
<004a> <0067> 
<004b> <0068> 
<004c> <0069> 
<004d> <006a> 
<004e> <006b> 
<004f> <006c> 
<0050> <006d> 
<0051> <006e> 
<0052> <006f> 
<0053> <0070> 
<0055> <0072> 
<0056> <0073> 
<0057> <0074> 
<0058> <0075> 
<0059> <0076> 
<005a> <0077> 
<005d> <007a> 
<006c> <00e4> 
<0081> <00fc> 
<0089> <00df> 
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 

这是你问的文件:在您的PDF https://wetransfer.com/downloads/214674449c23713ee481c5a8f529418320170827201941/b2bea6

+0

你说你*不能共享PDF文档*。没有一个可以观察问题的样本文件,但没有人能分析这个问题。正如我将假设文档包含关于编码或映射到Unicode的不完整信息,因此文本提取器只能猜测,以及pdfbox猜测的方式可能已更改。 – mkl

+0

我觉得奇怪的是,旧版本的pdfbox能够提取文本,但新版本不能。你不觉得这是意想不到的,@ tilman-hausherr?我无法共享文件,因为您可能已经看到它来自银行并且包含机密信息,或者是否有方法从此机密信息中删除PDF,@mkl?我希望有人对调试器中的内容有一些想法,无论是否存在某种编码问题或从版本1.8.13更改为2.0.7。 – stephanmunich

+0

@stephanmunich https://en.wikipedia.org/wiki/Software_regression Re:文件,试试Adobe Professional是否可以将个人信息更改为XXXX或其他。请小心使用“编辑”工具,其中一些工具不能正确执行此操作。确保从Adobe Reader复制并粘贴文本。 –

回答

3

有关问题的字体的信息是矛盾和部分破。根据某些软件的反应,它可能会或可能不会正确提取文本。


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

在另一方面,我们有一个ToUnicode地图这意味着潜在的编码是一些两字节编码(它有一个代码空间范围<0000> <ffff>),并且即使一个忽略两个字节的性质,它具有映射,特别是将数字ANSI代码映射为大写字母,将大写字母ANSI代码映射为其他小写字母,将小写'l'ANSI代码映射为'ä'的Unicode值。

当提取文本,PDFBox的2.0.x的似乎遵循破碎ToUnicode地图(解释两字节代码在TABEL作为一字节代码,忽略了上0)在可能的情况(导致垃圾)和否则将字符代码解释为ANSI(导致正确的文本)。 PDF 1.8.x似乎已经忽略了地图,Adobe Reader也是如此。


其实它看起来像ToUnicode地图已取得使用身份-H编码的字体。


如果你面对这样一个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

您应该执行该预处理尽早加载后t他通过文档来防止将包含错误的字体读入到文档字体缓存中的错误ToUnicode映射。

+0

谢谢你的提示。如果我从PDFDebugger显示的信息中正确理解,PDF由XEP(http://www.renderx.com/reference.html)生成。由于您似乎是专家@mkl,您是否知道或可以从该文档中看到XEP是否已知会生成破碎的ToUnicode映射?那么pdfbox 1.8.x如何能够绕过这个破碎的ToUnicode地图? pdfbox是否可能以某种方式检测ToUnicode地图是否被破坏,并根据该信息自动决定使用哪种编码?或者你有另一个关于如何解决这个问题的建议? – stephanmunich

+0

这些信息是矛盾的。因此,一个软件需要决定要信任哪些信息。不幸的是,还有很多PDF文件都带有完全不正确的** Encoding **值,所以更喜欢** Encoding **值也不是解决方案。您可能需要分析一个有代表性的文档集合,以确定XEP是否总是生成带有破坏的** ToUnicode **地图的PDF。如果是这样,您可以通过删除所有** ToUnicode **地图来处理XEP PDF。 – mkl

+0

虽然:可能不是XEP是罪魁祸首,而是一些后处理器操纵XEP文档,它根本不会将其名称放入元数据中...... – mkl

相关问题