2009-11-11 109 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能为你工作,我会感到惊讶 - 这是一个严重的麻烦。