2017-08-26 24 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

相關問題