Использование библиотеки Java PDFBox для написания русского PDF - PullRequest
11 голосов
/ 11 ноября 2009

Я использую библиотеку Java под названием PDFBox , пытаясь записать текст в PDF. Он отлично работает для английского текста, но когда я попытался написать русский текст внутри 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: Нажмите здесь

--------------------- Редактировать 18 ноября 2009 г.

После некоторого расследования я теперь уверен, что это проблема Кодирования, это можно решить, определив мою собственную Кодировку, используя полезный класс PDFBox, называемый DictionaryEncoding .

Я не уверен, как его использовать, но вот что я пробовал до сих пор:

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

Это не работает, так как кажется, что я неправильно заполняю словарь, когда я пишу PDF-страницу, используя это, она выглядит пустой.

Исходный код DictionaryEncoding: Нажмите здесь

Ответы [ 6 ]

5 голосов
/ 29 ноября 2012

Длинная история такова: чтобы выводить Unicode в PDF из шрифта TrueType, вывод должен включать тонну подробной и, казалось бы, лишней информации. Это сводится к следующему: внутри шрифта TrueType глифы хранятся как идентификаторы глифов. Эти идентификаторы глифов связаны с определенным символом Unicode (и IIRC, глиф Unicode внутренне может относиться к нескольким кодовым точкам - как & eacute; ссылаясь на e и острый акцент - моя память туманная). PDF действительно не поддерживает Unicode, кроме того, что существует сопоставление значений UTF16BE в строке с идентификаторами глифов в шрифте TrueType, а также сопоставление значений UTF16BE с Unicode - даже если это идентичность.

  • Словарь шрифтов подтипа Type0 с
    • массив 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
    • CIDToGIDMap, который отображается из идентификатора символа в идентификатор глифа

Вот тот же тест - это объект в массиве 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? Просто так: вывод Unicode в PDF, честно говоря, королевская боль в заднице. Acrobat был разработан до появления Unicode, и с самого начала было болезненно иметь CJK-кодировки без Unicode (я знаю - я тогда работал над Acrobat). Позже была добавлена ​​поддержка Unicode, но на самом деле казалось, что она не работает. Хотелось бы надеяться, что вы просто скажете / Encoding / Unicode и получите строки, которые начинаются с символов «шип» и «y-dieresis» и заканчиваются. Нет такой удачи. Если вы не включите все подробности (и в действительности Acrobat, внедряя программу PostScript для перевода в Unicode? WTH?), Вы получите пустую страницу в Acrobat. Клянусь, я не придумываю это.

На данный момент я пишу инструменты для создания PDF-файлов для отдельной компании (прямо сейчас .NET, поэтому она вам не поможет), и я поставил себе цель спрятать всю эту ерунду. Весь текст в кодировке Unicode - если вы используете только те коды символов, которые являются WinAnsi, это то, что вы получаете под капотом. Используйте что-нибудь еще, вы получите все эти другие вещи с ним. Я был бы удивлен, если PDFBox сделает это для вас - это серьезная проблема.

1 голос
/ 09 июля 2018

Решение очень простое.

1) Вы должны найти шрифты, совместимые с символами, которые вы хотите отобразить.
2) Загрузите локально .ttf файл шрифтов.
3) Загрузка шрифтов из вашего приложения

Например, вот что вам нужно сделать, если вы хотите использовать греческие символы:

content = new PDPageContentStream(document, page);
pdfFont = PDType0Font.load( document, new File( "arialuni.ttf" ) )
content.setFont(pdfFont, fontSize);
0 голосов
/ 04 июня 2018

Попробуйте использовать эту конструкцию:

PDFont font = PDType0Font.load( pdfFile, new File( "fonts/VREMACCI.TTF" ) );  // Windows Russian font imported to write the Russian text.
// Some code here to open the PDF & define a new page.
contentStream.beginText();
contentStream.setFont(font, 12);
contentStream.showText( "отделом компьютерной" ); // Write the Russian text.
contentStream.endText();
0 голосов
/ 02 мая 2010

Просто попробуйте это:

Phrase leftTitle = new Phrase ("САНКТ-ПЕТЕРБУРГ", FontFactory.getFont ("Tahoma", "Cp1251", true, 25));

Это будет работать по крайней мере с последней (5.0.1) iText

0 голосов
/ 12 ноября 2009

Проверка того, является ли это проблемой кодирования, должна быть довольно простой (просто переключитесь на кодировку UTF16).

Я предполагаю, что вы пытались использовать редактор или что-то с шрифтом VREMACCI и подтвердили, что он отображает то, что вы ожидаете?

Возможно, вы захотите попробовать сделать то же самое в iText, просто чтобы понять, связана ли проблема с самой библиотекой PdfBox ... Если ваша основная задача - создавать PDF-файлы, iText может быть лучшим решением в любом случае. .

РЕДАКТИРОВАТЬ - длинный ответ на комментарии:

хорошо - извините за перемотку вопроса о кодировке ... Ваша основная проблема (которую вы, вероятно, уже знали) заключается в том, что кодировка байтов, записываемых в поток контента, отличается от кодировки, используемой для просмотра до глифов. Теперь я постараюсь помочь:

Я взглянул на класс кодирования словаря в PdfBox, и он выглядит довольно не интуитивно понятным ... Рассматриваемый «словарь» - это словарь PDF. Итак, что вам в основном нужно сделать, это создать объект словаря Pdf (я думаю, что PdfBox называет это типом COSObject), а затем добавить в него записи.

Кодировка шрифта определяется в PDF как словарь (см. Стр. 266 приведенной выше спецификации). Словарь содержит имя базовой кодировки и необязательный массив различий. Технически массив различий не следует использовать со шрифтами истинного типа (хотя я видел, что он использовался в некоторых случаях - не используйте его).

Затем вы укажете запись для cmap для кодировки. Эта карта будет кодировать ваш шрифт.

Мое предложение здесь состоит в том, чтобы взять существующий PDF-файл, который делает то, что вы хотите, а затем получить дамп структуры словаря для шрифта, чтобы вы могли видеть, как он выглядит.

Это определенно не для слабонервных. Я могу оказать некоторую помощь - если вам нужен дамп словаря, пристрелите мне гиперссылку с примером PDF, и я провожу ее по некоторым алгоритмам, которые я использую в своей разработке iText (я поддерживаю подраздел извлечения текста iText -системы).

РЕДАКТИРОВАТЬ - 11/17/09

ОК - вот дамп словаря из файла 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? ;-) Я не говорю, что это сработает, просто это может стоить того).

Для справки: приведенный выше дамп словаря был получен с использованием класса com.lowagie.text.pdf.parser.PdfContentReaderTool

0 голосов
/ 11 ноября 2009

Возможно, русский класс кодирования должен быть написан, он должен выглядеть как WinAnsiEncoding один, я полагаю.
Теперь я понятия не имею, что там поставить!

Или, если это не то, что вы уже делаете, возможно, вам следует закодировать исходный файл в UTF-8 и использовать кодировку по умолчанию.
Я видел некоторые сообщения, связанные с проблемами извлечения русского текста из существующих файлов PDF (конечно, с использованием PDFBox), но я не знаю, связан ли вывод.
Вы также можете написать в список рассылки PDFBox.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...