2017-08-04 142 views
1

嘗試使用Apache PDFBox 2.0.2版替換文本(使用下面的代碼)會生成一個輸出,其中很少的字符不會顯示,大多數情況下是大寫Case字符。例如,用「ABCDEFGHIJKLMNOPQRSTUVWXYZ」替換「pdf」中的輸出爲「ABCDEF HIJKLM OP RST W Y」。這是一些錯誤?或者我們有一些解決方法來處理這些字符。Apache PDFBox替換文本結果中的幾個字符錯過

public static PDDocument replaceText(PDDocument document, String searchString, String replacement) throws IOException { 
    if (StringUtils.isEmpty(searchString) || StringUtils.isEmpty(replacement)) { 
     return document; 
    } 
    PDPageTree pages = document.getDocumentCatalog().getPages(); 
    for (PDPage page : pages) { 
     PDFStreamParser parser = new PDFStreamParser(page); 
     parser.parse(); 
     List tokens = parser.getTokens(); 
     for (int j = 0; j < tokens.size(); j++) { 
      Object next = tokens.get(j); 
      if (next instanceof Operator) { 
       Operator op = (Operator) next; 
       //Tj and TJ are the two operators that display strings in a PDF 
       if (op.getName().equals("Tj")) { 
        // Tj takes one operator and that is the string to display so lets update that operator 
        COSString previous = (COSString) tokens.get(j - 1); 
        String string = previous.getString(); 
        string = string.replaceFirst(searchString, replacement); 
        previous.setValue(string.getBytes()); 
       } else if (op.getName().equals("TJ")) { 
        COSArray previous = (COSArray) tokens.get(j - 1); 
        for (int k = 0; k < previous.size(); k++) { 
         Object arrElement = previous.getObject(k); 
         if (arrElement instanceof COSString) { 
          COSString cosString = (COSString) arrElement; 
          String string = cosString.getString(); 
          string = StringUtils.replaceOnce(string, searchString, replacement); 
          cosString.setValue(string.getBytes()); 
         } 
        } 
       } 
      } 
     } 
     // now that the tokens are updated we will replace the page content stream. 
     PDStream updatedStream = new PDStream(document); 
     OutputStream out = updatedStream.createOutputStream(); 
     ContentStreamWriter tokenWriter = new ContentStreamWriter(out); 
     tokenWriter.writeTokens(tokens); 
     page.setContents(updatedStream); 
     out.close(); 
    } 
    return document; 
} 
+1

您的問題與[此問題]相同(https://stackoverflow.com/q/34239106/1729265),其中使用的PDF庫有iText。 [我的答案](https://stackoverflow.com/a/34315962/1729265)中的大部分也適用於此。 – mkl

+0

感謝@mkl,很好,精心製作了一個..我試圖處理你的建議,如果可能的話,仍然想用PDFbox解決方案。 –

+0

我不想讓你用iText代替PDFBox。我的意思是「我的許多答案也適用於此。」是解釋問題發生的原因,這些解釋是獨立於圖書館的,它們基於PDF的工作原理。 – mkl

回答

1

https://pdfbox.apache.org/2.0/migration.html

爲什麼被引用的例子ReplaceText去掉?

ReplaceText示例已被刪除,因爲它給出了可以輕鬆替換文本的不正確錯覺。話往往拆分,通過這個片段的內容流的所看到:

[(DO)-29(C)-1(umen)30(塔季翁)] TJ

其他問題將與字體子集出現:例如,如果僅使用a,b和c的字形,則這些字符將被編碼爲十六進制0,1和2,因此您不會找到「abc」。另外,你不能用「d」替換「c」,因爲它不是子集的一部分。

您也可能有連字的問題,例如, 「ff」,「fl」,「fi」,「ffi」,「ffl」,它可以用許多字體中的單個代碼表示。要自己理解這一點,請使用PDFDebugger查看任何文件,並查看頁面的「內容」條目。

============================================== ========================

您的描述建議初始文件一直使用字體子集,即缺少字符G,N ,Q,V和Y.

不,沒有簡單的解決方法。您將不得不從內容流中刪除不想要的文本,然後在正確的位置將新的內容流與新文本一起添加到您想要的文本中。

P.S.目前的PDFBox版本是2.0.7,而不是2.0.2。

+0

謝謝@Tilman,我試着使用最新的2.0.7版本,但問題仍然存在。建議您可以幫助我使用任何代碼示例從內容流中刪除特定文本並添加文本到新內容流中.Would有很大的幫助.. –

+0

我沒有聲稱它會在2.0.7中工作。我只提到2.0.7,因爲使用過時的軟件是不好的做法。要刪除特定的文本,請查看RemoveAllText.java示例,您需要對其進行修改,以使其適用於您的文件。 (該文本在'newTokens.get(newTokens.size() - 1)'中,所以檢查它匹配,由於編碼可能會很棘手)。在新內容流中附加文本,請參閱源代碼下載中的AddMessageToEachPage.java示例。 –

+0

感謝代碼示例,刪除標記方法是可行的,但對於寫入,我的情況需要在特定位置(具有一些x,y座標)的文本插入。讀取矩形區域時,x,y座標和寬度,高度都能很好地工作,所以想知道是否可以寫入類似的東西。 –