2009-11-11 14 views
11

Używam biblioteki Java o nazwie PDFBox próbującej napisać tekst do pliku PDF. Działa idealnie na tekst w języku angielskim, ale kiedy próbowałem pisać rosyjski tekst w pliku PDF, litery wydawały się takie dziwne. Wygląda na to, że problem tkwi w używanej czcionce, ale nie jestem tego pewien, więc mam nadzieję, że ktoś mógłby mnie przez to przeprowadzić. Oto ważne linie kodu:Używanie biblioteki Java PDFBox do pisania rosyjskiego pliku 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. 

Kod źródłowy WinAnsiEncoding brzmi: Click here

--------------------- Edycja na 18 listopada 2009

Po pewnym dochodzenia, teraz jestem pewien, że jest to problem, Kodowanie, to może być rozwiązany poprzez zdefiniowanie własne kodowanie używając jako klasę PDFBox nazwie DictionaryEncoding.

nie jestem pewien, jak go używać, ale tutaj jest to, co próbowałem do tej pory:

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

ten nie działa, jak się wydaje jestem wypełniania słownika w niewłaściwy sposób, kiedy napisz stronę w formacie PDF, używając tego, że wydaje się pusta.

Kod źródłowy DictionaryEncoding jest: Click here

+1

Czy to nie oczywiste? Twój ustawia czcionkę na nową WinAnsiEncoding(). Win + Ansi! = Potrafi pokazać rosyjski. – jitter

+0

Próbowałem wszystkich dostępnych kodowań, ale żaden z nich nie działał, dostępne kodowanie jest podklasowane tutaj: 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 Problem nie leży w czcionce, ale w kodowaniu? – Brad

+1

12.0.0.1:51381? Lokalny Gospodarz? to nie zadziała dla nikogo poza Tobą. – jitter

Odpowiedz

0

Prawdopodobnie rosyjska klasa kodowania muszą być napisane, powinna ona wyglądać WinAnsiEncoding jednego, jak sądzę.
Teraz nie mam pojęcia, co tam umieścić!

Lub, jeśli nie jest to już to, co robisz, być może powinieneś zakodować plik źródłowy w UTF-8 i użyć domyślnego kodowania.
Widziałem niektóre wiadomości związane z problemami z wyodrębnianiem rosyjskiego tekstu z istniejących plików PDF (oczywiście przy użyciu PDFBox), ale nie wiem, czy dane wyjściowe są ze sobą powiązane.
Możesz także pisać na liście mailingowej PDFBox.

+0

Cóż, wydobywanie rosyjskiego tekstu działa dobrze przy użyciu PDFBox, problem polega na pisaniu rosyjskiego tekstu w pliku PDF. – Brad

+0

Do pisania kodowania w języku rosyjskim istnieje klasa DictionaryEncoding, która może pozwolić mi zdefiniować własne kodowanie ... Ale wydaje mi się, że to labirynt: http://kickjava.com/src/org/pdfbox/encoding/ DictionaryEncoding.java.htm – Brad

0

Testowanie, czy jest to problem z kodowaniem, powinno być całkiem łatwe (wystarczy przejść do kodowania UTF16).

Zakładam, że próbowałeś użyć edytora lub czegoś z czcionką VREMACCI i potwierdziłeś, że wyświetla on tak, jak tego oczekujesz?

Możesz spróbować zrobić to samo w iText, aby dowiedzieć się, czy problem dotyczy samej biblioteki PdfBox ... Jeśli Twoim głównym celem jest generowanie plików PDF, iText może być lepszym rozwiązaniem tak czy inaczej.

EDIT - długa odpowiedź na komentarze:

ok - przepraszam za plecami i naprzód w kwestii kodowania ... Twój rdzeń problem (który prawdopodobnie już wiedział) jest to, że kodowanie bajty są zapisywane strumień treści różni się od kodowania używanego do wyszukiwania znaków. Teraz postaram się być pomocny:

Przyjrzałem się klasie kodowania słownika w PdfBox i wygląda to dość nieintuicyjnie ... "Słownik" to słownik PDF. Więc zasadniczo musisz zrobić to stworzyć obiekt słownika Pdf (chyba PdfBox nazywa to typ COSObject), a następnie dodać do niego wpisy.

Kodowanie czcionki jest zdefiniowane w formacie PDF jako słownik (patrz strona 266 powyższej specyfikacji). Słownik zawiera podstawową nazwę kodowania oraz opcjonalną tablicę różnic. Technicznie, tablica różnic nie powinna być używana z czcionkami prawdziwymi (chociaż widziałem, że była używana w niektórych przypadkach - nie używaj jej jednak).

Następnie należy podać wpis dla cmap dla kodowania. Ten cmap będzie kodowaniem twojej czcionki.

Moja propozycja polega na pobraniu istniejącego pliku PDF, który robi to, co chcesz, a następnie pobierz zrzut struktury słownika czcionki, aby zobaczyć, jak to wygląda.

To zdecydowanie nie dla osób o słabym sercu. Mogę zapewnić pomoc - jeśli potrzebujesz zrzutów słownikowych, zastrzel mi hiperłącze z przykładowym plikiem PDF, a uruchomię go za pomocą niektórych algorytmów używanych w moim opracowaniu iText (jestem opiekunem ekstrakcji tekstu iText -system).

EDIT - 11/17/09

OK - oto słowniku zrzut z pliku russian.pdf (sub-słowniki są wymienione wcięte, w kolejności, w jakiej pojawiła się w słowniku zawierającym):

(/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) 

Jest tu wiele ruchomych części. może chcesz utworzyć dokument testowy, który ma tylko 3 lub 4 znaki w danej czcionce ... Jest tu wiele czcionek typu 1 (oprócz czcionek TT), więc trudno powiedzieć co jest związane z konkretnym problemem.

(Jesteś pewny, że nie chcesz tego przynajmniej wypróbować za pomocą iText? ;-) Nie twierdzę, że to zadziała, tylko że warto byłoby spróbować.

Dla porównania, powyższe słowniku wysypisko uzyskano przy użyciu klasy com.lowagie.text.pdf.parser.PdfContentReaderTool

+0

Nie ma klasy w PDFBox, która obsługuje UTF8 lub UTF16, ale myślę, że tak, jest to problem z kodowaniem. Wiem, że iText jest świetną biblioteką, ale już zacząłem moją pracę z PDFBox i to jest dobre do teraz, więc chcę trzymać się PDFBox. – Brad

+0

Ugh. Jeśli używasz PDFBox do analizy zawartości, którą stworzyłeś, czy możesz odzyskać tekst? Jeśli tak, to prawdopodobnie nie jest to ograniczenie kodowania, pre-se ... Może to tylko kwestia, w jaki sposób PDFBox mapuje bajty krotek na glify? –

+0

Co rozumiesz przez odzyskanie go? Mogę napisać kilka innych języków obcych, takich jak francuski, niemiecki, ... Ale inne, takie jak rosyjski, wydają się być problemem. To jest problem z kodowaniem, jestem pewien. A klasa DictionaryEncoding została stworzona, aby umożliwić rozszerzenie innych nieobsługiwanych kodowań, ale nadal nie mogę zrozumieć, jak z niej korzystać. – Brad

-1

Spróbuj tego:

wyrażenie leftTitle = new Zwrot ("САНКТ-ПЕТЕРБУРГ ", FontFactory.getFont (" Tahoma "," Cp1251 ", prawda, 25));

Będzie to działać przynajmniej z najnowszej (5.0.1) iText

5

Długa historia jest - w tym celu wyjście unicode w formacie PDF z czcionki TrueType, wyjście musi zawierać mnóstwo szczegółowych i pozornie zbędne informacje. Sprowadza się to do tego - wewnątrz czcionki TrueType glify są przechowywane jako identyfikatory glifów. Te identyfikatory glifów są powiązane z konkretnym znakiem Unicode (i IIRC, gatunek z Unicode wewnętrznie może odnosić się do kilku punktów kodowych - takich jak & eacute; odwołując się do e i ostrego akcentu - moja pamięć jest mglista). PDF nie ma obsługi Unicode poza stwierdzeniem, że istnieje odwzorowanie od wartości UTF16BE w łańcuchu na identyfikatory glifów w czcionce TrueType, a także mapowanie z wartości UTF16BE na Unicode - nawet jeśli jest to tożsamość.

  • słownika czcionki podtypu PLP typu 0, z
    • tablicy DescendantFonts wpisem opisanym poniżej
    • wjazd ToUnicode mapującą wartości UTF16BE do UNICODE
    • kodowania ustawiony Identity-H

Wyniki jednego z moich testów jednostkowych na moich własnych narzędziach wyglądają tak:

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% Należy zauważyć, że formatowanie złe dla strumienia

  • słownika czcionki podtypu CIDFontTYpe2 z
    • CIDSsytemInfo
    • FontDescriptor
    • DW i W
    • a CIDToGIDMap odwzorowująca identyfikator postaci na identyfikator glyph

Oto jeden z tego samego testu - jest to obiekt w tablicy 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 

Dlaczego opowiadam wam to? Co to ma wspólnego z PDFBox? Po prostu: Wynik w Unicode w formacie PDF jest, szczerze mówiąc, królewskim bólem w tyłku. Acrobat został opracowany przed pojawieniem się Unicode i na początku było bolesne kodowanie CJK bez Unicode (wiem - pracowałem wtedy nad Acrobatem). Później dodano wsparcie dla Unicode, ale wydawało się, że to było już wcześniej. Można mieć nadzieję, że po prostu powiesz/Kodowanie/Unicode i będziesz mieć ciągi zaczynające się od znaków ciernia i y-dieresis i gotowe. Bez takiego szczęścia. Jeśli nie umieścisz wszystkich szczegółowych informacji (a tak naprawdę, Acrobat, osadzanie programu PostScript do tłumaczenia na Unicode? WTH?), Otrzymasz pustą stronę w programie Acrobat. Przysięgam, nie wymyślam tego.

W tym momencie piszę narzędzia generowania plików PDF dla oddzielnej firmy (teraz .NET, więc to ci nie pomoże), a ja stawiam sobie za cel, aby ukryć wszystkie te bzdury. Cały tekst jest w Unicode - jeśli używasz tylko tych kodów znaków, które są tym samym WinAnsi, to właśnie dostajesz pod maską. Użyj czegokolwiek innego, otrzymasz wszystkie inne rzeczy. Byłbym zaskoczony, gdyby PDFBox to działał dla Ciebie - to poważny problem.

Powiązane problemy