2009-11-11 112 views
11

我正在使用稱爲的Java庫嘗試將文本寫入PDF的PDFBox。它適用於英文文本,但是當我試圖在PDF中寫入俄文文本時,這些字母顯得很奇怪。看來問題出在使用的字體上,但我不太確定,所以我希望有人能指導我完成這個任務。下面是重要的代碼行:使用Java PDFBox庫編寫俄語PDF

PDTrueTypeFont font = PDTrueTypeFont.loadTTF(pdfFile, new File("fonts/VREMACCI.TTF")); // Windows Russian font imported to write the Russian text. 
font.setEncoding(new WinAnsiEncoding()); // Define the Encoding used in writing. 
// Some code here to open the PDF & define a new page. 
contentStream.drawString("отделом компьютерной"); // Write the Russian text. 

的WinAnsiEncoding源代碼是:Click here

---------------------編輯上18 2009年11月

經過一番調查,我現在確定它是一個編碼的問題,這可以通過使用一種稱爲樂於助人的PDFBox的類DictionaryEncoding定義自己的編碼來解決。

我不知道如何使用它,但這裏是我試過至今:

COSDictionary cosDic = new COSDictionary(); 
cosDic.setString(COSName.getPDFName("Ercyrillic"), "0420 "); // Russian letter. 
font.setEncoding(new DictionaryEncoding(cosDic)); 

這是不行的,因爲它似乎我正在填充字典以錯誤的方式,當我用這個寫一個PDF頁面,它顯示爲空白。

的DictionaryEncoding源代碼爲:Click here

+1

這不是很明顯嗎?您正在將字體設置爲新的WinAnsiEncoding()。 Win + Ansi!=能夠顯示俄語。 – jitter 2009-11-11 08:18:08

+0

我嘗試了所有可用的編碼,但都沒有工作,可用的編碼在這裏被分類: http://127.0.0.1:51381/help/nftopic/jar:file:/C:/Programs/Java/Libraries/PDFBox%20v0 .8/javadoc%20v0.8.zip!/org/apache/pdfbox/encoding/Encoding.html 所以問題不在於字體,而是在編碼? – Brad 2009-11-11 08:24:11

+1

12.0.0.1:51381?本地主機?除了你以外,任何人都不能使用 – jitter 2009-11-11 08:32:43

回答

0

也許俄羅斯編碼類需要寫入,它應該看起來像一個WinAnsiEncoding,我想。
現在,我不知道該放什麼東西!或者,如果這不是你已經做的,或許你應該用UTF-8編碼你的源文件,並使用默認編碼。
我看到了一些與從現有PDF文件中提取俄文文本相關的消息(當然使用PDFBox),但我不知道輸出是否相關。
您也可以寫入PDFBox郵件列表。

+0

好吧,提取俄文文本使用PDFBox可以正常工作,問題在於將PDF文件寫入俄文文本。 – Brad 2009-11-11 10:35:21

+0

對於編寫俄羅斯編碼,有一個DictionaryEncoding類,我認爲它可以讓我定義自己的編碼...但它對我來說似乎是一個迷宮: http://kickjava.com/src/org/pdfbox/encoding/ DictionaryEncoding.java.htm – Brad 2009-11-11 11:38:12

0

測試這是否是一個編碼問題應該很容易做(只需切換到UTF16編碼)。

我假設您已經嘗試過使用編輯器或VREMACCI字體,並確認它顯示您期望的方式?

您可能想嘗試在iText中做同樣的事情,只是爲了感受問題是否與PdfBox庫本身有關......如果您的主要目標是生成PDF文件,iText可能是更好的解決方案無論如何。

編輯 - 長回答評論:

OK - 上編碼的問題比較遺憾的是來回...您的核心問題(你可能已經知道)是一個字節的編碼被寫入內容流與用於查找字形的編碼不同。現在我將嘗試實際上有幫助:

我看了一下PdfBox中的字典編碼類,它看起來相當不直觀......問題中的'字典'是一個PDF字典。所以你基本上需要做的是創建一個PDF字典對象(我認爲PdfBox稱這是一種COSObject類型),然後向它添加條目。

字體的編碼在PDF中定義爲字典(參見上述規範的第266頁)。該字典包含一個基本編碼名稱,以及一個可選的差異數組。從技術上講,差異數組不應該與真正的字體一起使用(儘管我曾經在某些情況下使用它 - 不要使用它)。

然後,您將爲編碼指定cmap的條目。這個cmap將是你的字體的編碼。

我在這裏的建議是採取現有的PDF,做你想做的,然後得到字體的字典結構轉儲,所以你可以看到它的樣子。

這絕對不是心靈的隱隱。我可以提供一些幫助 - 如果你需要字典轉儲,請給我一個帶有示例PDF的超鏈接,然後通過我在iText開發中使用的一些算法運行它(我是iText文本提取子的維護者) -系統)。

編輯 - 09年11月17日

OK - 下面是來自russian.pdf文件字典轉儲(子字典列出縮進,和他們的順序在包含字典出現):

(/CropBox=[0, 0, 595, 842], /Parent=Dictionary of type: /Pages, /Type=/Page, /Contents=[209 0 R, 210 0 R, 211 0 R, 214 0 R, 215 0 R, 216 0 R, 222 0 R, 223 0 R], /Resources=Dictionary, /MediaBox=[0, 0, 595, 842], /StructParents=0, /Rotate=0) 
    Subdictionary /Parent = (/Type=/Pages, /Count=6, /Kids=[195 0 R, 1 0 R, 3 0 R, 5 0 R, 7 0 R, 9 0 R]) 
    Subdictionary /Resources = (/ExtGState=Dictionary, /ProcSet=[/PDF, /Text], /ColorSpace=Dictionary, /Font=Dictionary, /Properties=Dictionary) 
     Subdictionary /ExtGState = (/GS0=Dictionary of type: /ExtGState) 
      Subdictionary /GS0 = (/OPM=1, /op=false, /Type=/ExtGState, /SA=false, /OP=false, /SM=0.02) 
     Subdictionary /ColorSpace = (/CS0=[/ICCBased, 228 0 R]) 
     Subdictionary /Font = (/C2_1=Dictionary of type: /Font, /C2_2=Dictionary of type: /Font, /C2_3=Dictionary of type: /Font, /C2_4=Dictionary of type: /Font, /TT2=Dictionary of type: /Font, /TT1=Dictionary of type: /Font, /TT0=Dictionary of type: /Font, /C2_0=Dictionary of type: /Font, /TT3=Dictionary of type: /Font) 
      Subdictionary /C2_1 = (/DescendantFonts=[243 0 R], /BaseFont=/LDMIEC+TimesNewRomanPS-BoldMT, /Type=/Font, /Subtype=/Type0, /Encoding=/Identity-H, /ToUnicode=Stream) 
      Subdictionary /C2_2 = (/DescendantFonts=[233 0 R], /BaseFont=/LDMIBO+TimesNewRomanPSMT, /Type=/Font, /Subtype=/Type0, /Encoding=/Identity-H, /ToUnicode=Stream) 
      Subdictionary /C2_3 = (/DescendantFonts=[224 0 R], /BaseFont=/LDMIHD+TimesNewRomanPS-ItalicMT, /Type=/Font, /Subtype=/Type0, /Encoding=/Identity-H, /ToUnicode=Stream) 
      Subdictionary /C2_4 = (/DescendantFonts=[229 0 R], /BaseFont=/LDMIDA+Tahoma, /Type=/Font, /Subtype=/Type0, /Encoding=/Identity-H, /ToUnicode=Stream) 
      Subdictionary /TT2 = (/LastChar=58, /BaseFont=/LDMIFC+TimesNewRomanPS-BoldMT, /Type=/Font, /Subtype=/TrueType, /Encoding=/WinAnsiEncoding, /Widths=[250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 333], /FontDescriptor=Dictionary of type: /FontDescriptor, /FirstChar=32) 
       Subdictionary /FontDescriptor = (/Type=/FontDescriptor, /StemV=136, /Descent=-216, /FontWeight=700, /FontBBox=[-558, -307, 2000, 1026], /CapHeight=656, /FontFile2=Stream, /FontStretch=/Normal, /Flags=34, /XHeight=0, /FontFamily=Times New Roman, /FontName=/LDMIFC+TimesNewRomanPS-BoldMT, /Ascent=891, /ItalicAngle=0) 
      Subdictionary /TT1 = (/LastChar=187, /BaseFont=/LDMICP+TimesNewRomanPSMT, /Type=/Font, /Subtype=/TrueType, /Encoding=/WinAnsiEncoding, /Widths=[250, 0, 0, 0, 0, 833, 778, 0, 333, 333, 0, 0, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 0, 564, 0, 444, 0, 722, 667, 667, 722, 611, 556, 0, 722, 333, 389, 0, 611, 889, 722, 722, 556, 0, 667, 556, 611, 0, 722, 944, 0, 722, 0, 333, 0, 333, 0, 500, 0, 444, 500, 444, 500, 444, 333, 500, 500, 278, 0, 500, 278, 778, 500, 500, 500, 0, 333, 389, 278, 500, 500, 722, 0, 500, 444, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500], /FontDescriptor=Dictionary of type: /FontDescriptor, /FirstChar=32) 
       Subdictionary /FontDescriptor = (/Type=/FontDescriptor, /StemV=82, /Descent=-216, /FontWeight=400, /FontBBox=[-568, -307, 2000, 1007], /CapHeight=656, /FontFile2=Stream, /FontStretch=/Normal, /Flags=34, /XHeight=0, /FontFamily=Times New Roman, /FontName=/LDMICP+TimesNewRomanPSMT, /Ascent=891, /ItalicAngle=0) 
      Subdictionary /TT0 = (/LastChar=55, /BaseFont=/LDMIBN+TimesNewRomanPS-BoldItalicMT, /Type=/Font, /Subtype=/TrueType, /Encoding=/WinAnsiEncoding, /Widths=[250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 500, 500, 500, 0, 0, 0, 0, 500], /FontDescriptor=Dictionary of type: /FontDescriptor, /FirstChar=32) 
       Subdictionary /FontDescriptor = (/Type=/FontDescriptor, /StemV=116.867004, /Descent=-216, /FontWeight=700, /FontBBox=[-547, -307, 1206, 1032], /CapHeight=656, /FontFile2=Stream, /FontStretch=/Normal, /Flags=98, /XHeight=468, /FontFamily=Times New Roman, /FontName=/LDMIBN+TimesNewRomanPS-BoldItalicMT, /Ascent=891, /ItalicAngle=-15) 
      Subdictionary /C2_0 = (/DescendantFonts=[238 0 R], /BaseFont=/LDMHPN+TimesNewRomanPS-BoldItalicMT, /Type=/Font, /Subtype=/Type0, /Encoding=/Identity-H, /ToUnicode=Stream) 
      Subdictionary /TT3 = (/LastChar=169, /BaseFont=/LDMIEB+Tahoma, /Type=/Font, /Subtype=/TrueType, /Encoding=/WinAnsiEncoding, /Widths=[313, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 546, 0, 546, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 929], /FontDescriptor=Dictionary of type: /FontDescriptor, /FirstChar=32) 
       Subdictionary /FontDescriptor = (/Type=/FontDescriptor, /StemV=92, /Descent=-206, /FontWeight=400, /FontBBox=[-600, -208, 1338, 1034], /CapHeight=734, /FontFile2=Stream, /FontStretch=/Normal, /Flags=32, /XHeight=546, /FontFamily=Tahoma, /FontName=/LDMIEB+Tahoma, /Ascent=1000, /ItalicAngle=0) 
     Subdictionary /Properties = (/MC0=Dictionary of type: /OCMD) 
      Subdictionary /MC0 = (/Type=/OCMD, /OCGs=Dictionary of type: /OCG) 
       Subdictionary /OCGs = (/Usage=Dictionary, /Type=/OCG, /Name=HeaderFooter) 
        Subdictionary /Usage = (/CreatorInfo=Dictionary, /PageElement=Dictionary) 
         Subdictionary /CreatorInfo = (/Creator=Acrobat PDFMaker 6.0 äëÿ Word) 
         Subdictionary /PageElement = (/SubType=/HF) 

這裏有很多移動部件。您可能需要將相關字體中僅包含3個或4個字符的測試文檔放在一起...此處使用了很多1類字體(除TT字體外),因此很難說明你的特定問題涉及什麼。

(你確定你不想用iText試試這個嗎?;-)我不是說它可以工作,只是它可能值得一試)。

短語leftTitle =新短語(「САНКТ-ПЕТЕРБУРГ:

爲了參考,使用com.lowagie.text.pdf.parser.PdfContentReaderTool類

+0

PDFBox中沒有支持UTF8或UTF16的類,但我想是的,這是一個編碼問題。 我知道iText是一個很棒的圖書館,但是我已經開始使用PDFBox開展工作了,直到現在,它還是很棒的,所以我想堅持使用PDFBox。 – Brad 2009-11-12 08:34:49

+0

呃。如果您使用PDFBox解析您創建的內容,您是否能夠恢復文本?如果是這樣,那麼它可能不是編碼的限制,pre-se ...也許這只是一個PDFBox如何將字節元組映射到字形的問題? – 2009-11-12 17:58:48

+0

恢復它意味着什麼?我可以寫一些其他外語,如法語,德語,......但像俄語這樣的其他人似乎是一個問題。這是一個編碼問題,我相信。 DictionaryEncoding類創建後允許擴展其他不受支持的Encodings,但我仍然無法確定如何使用它。 – Brad 2009-11-15 09:05:43

-1

剛剛嘗試這一個得到上述字典轉儲「,FontFactory.getFont(」Tahoma「,」Cp1251「,true,25));

這將至少工作與最新版本(5.0.1)的iText

5

長的故事是這樣的 - 爲了做unicode的輸出PDF從TrueType字體,輸出必須有一噸的細節,看似多餘的信息。它所涉及的是 - 在TrueType字體中,字形存儲爲glyph id。這些glyph id與特定的unicode字符相關聯(和IIRC,unicode glyph在內部可能指代若干代碼點 - 如eacute;指的是e和一個尖銳的重音 - 我的記憶是模糊的)。除了說一個字符串中的UTF16BE值到TrueType字體中的glyph id以及從UTF16BE值到Unicode的映射(即使是身份)之外,PDF並沒有真正支持Unicode。

  • 亞型類型0的字體字典與
    • 一個DescendantFonts陣列具有低於
    • 映射一個ToUnicode條目中描述的條目utf16be應按值UNICODE
    • 的編碼設定爲Identity-H

對我自己的工具的單元測試之一的輸出如下所示:

13 0 obj 
<< 
    /BaseFont /DejaVuSansCondensed 
    /DescendantFonts [ 4 0 R ] 
    /ToUnicode 14 0 R 
    /Type /Font 
    /Subtype /Type0 
    /Encoding /Identity-H 
>> endobj 

14 0 obj 
<< /Length 346 >> stream 
/CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << 
/Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def /CMapName /Adobe-Identity-UCS 
def /CMapType 2 def 1 begincodespacerange <0000> <FFFF> endcodespacerange 1 
beginbfrange <0000> <FFFF> <0000> endbfrange endcmap CMapName currentdict /CMap 
defineresource pop end end 

endstream%請注意格式是錯誤的流

  • 亞型CIDFontTYpe2的字體字典,
    • 一個CIDSsytemInfo
    • 一個FontDescriptor
    • DW和W
    • 從字符ID到字形ID映射的CIDToGIDMap ID

下面是相同的測試之一 - 這是DescendantFonts數組中的對象:

4 0 obj 
<< 
    /Subtype /CIDFontType2 
    /Type /Font 
    /BaseFont /DejaVuSansCondensed 
    /CIDSystemInfo 8 0 R 
    /FontDescriptor 9 0 R 
    /DW 1000 
    /W 10 0 R 
    /CIDToGIDMap 11 0 R 
>> 

8 0 obj 
<< 
    /Registry (Adobe) 
    /Ordering (UCS) 
    /Supplement 0 
>> 
endobj 

我爲什麼要告訴你呢?它與PDFBox有什麼關係?正因如此:坦率地說,PDF中的Unicode輸出是一個令人royal目結舌的王室痛苦。 Acrobat是在Unicode之前開發的,從一開始就讓CJK編碼沒有Unicode是很痛苦的(我知道 - 那時我使用Acrobat)。後來的Unicode支持被添加了,但它真的感覺就像是被踢了一邊。人們會希望你只會說/編碼/ Unicode,並且以刺和y-dieresis字符開頭的字符串,然後離開你。沒有這樣的運氣。如果你沒有把每一個細節都放進去(實際上是Acrobat,嵌入一個PostScript程序來轉換成Unicode?WTH?),你​​會在Acrobat中看到一個空白頁面。我發誓,我沒有這樣做。在這一點上,我爲一家單獨的公司編寫PDF生成工具(.NET現在,所以它不會幫助你),並且我將它設計爲一​​個隱藏所有廢話的設計目標。所有的文本都是unicode - 如果你只使用那些與WinAnsi相同的字符代碼,那就是你所得到的。使用其他任何東西,你會得到所有其他的東西。如果PDFBox能爲你工作,我會感到驚訝 - 這是一個嚴重的麻煩。