2009-11-11 7 views
11

J'utilise une bibliothèque Java appelée PDFBox en essayant d'écrire du texte en format PDF. Cela fonctionne parfait pour le texte anglais, mais quand j'ai essayé d'écrire du texte russe dans le PDF, les lettres sont apparues si étranges. Il semble que le problème est dans la police utilisée, mais je ne suis pas si sûr à ce sujet, donc j'espère que n'importe qui pourrait me guider à travers cela. Voici les grandes lignes de code:Utilisation de la bibliothèque Java PDFBox pour écrire le PDF en russe

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. 

Le code source est WinAnsiEncoding: Click here

--------------------- Modifier le 18 novembre 2009

Après enquête, je suis sûr qu'il est un problème de codage, cela pourrait être résolu en définissant mon propre encodage en utilisant la classe utile de PDFBox appelé DictionaryEncoding.

Je ne sais pas comment l'utiliser, mais voici ce que j'ai essayé jusqu'à présent:

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

Cela ne fonctionne pas, car il semble que je suis remplissais le dictionnaire d'une mauvaise façon, quand je écrire une page PDF en utilisant cela, il apparaît vide.

Le code source est DictionaryEncoding: Click here

+1

N'est-ce pas évident? Vous définissez la police à nouveau WinAnsiEncoding(). Win + Ansi! = Capable de montrer le russe. – jitter

+0

J'ai essayé tous les encodages disponibles mais aucun n'a fonctionné, Les encodages disponibles sont sous-classés ici: 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 Donc, le problème n'est pas dans la police, mais dans le codage? – Brad

+1

12.0.0.1:51381? localhost? cela ne fonctionnera pour personne sauf vous – jitter

Répondre

0

Peut-être la classe russe de codage doivent être écrites, il devrait ressembler à l'un WinAnsiEncoding, je suppose.
Maintenant, je n'ai aucune idée de ce qu'il faut mettre là! Ou, si ce n'est pas déjà fait, vous devriez peut-être encoder votre fichier source en UTF-8 et utiliser un encodage par défaut.
J'ai vu quelques messages liés à des problèmes d'extraction de texte russe à partir de fichiers PDF existants (en utilisant PDFBox bien sûr) mais je ne sais pas si la sortie est liée.
Vous pouvez également écrire dans la liste de diffusion PDFBox.

+0

Eh bien, l'extraction de texte russe fonctionne très bien en utilisant PDFBox, le problème est en écrivant le texte russe dans un fichier PDF. – Brad

+0

Pour écrire le codage Rusian, il y a la classe DictionaryEncoding que je pense peut me permettre de définir mon propre encodage ... Mais il semble un labyrinthe pour moi: http://kickjava.com/src/org/pdfbox/encoding/ DictionaryEncoding.java.htm – Brad

0

Il est très facile de tester s'il s'agit d'un problème de codage (passez simplement au codage UTF16).

Je suppose que vous avez essayé d'utiliser un éditeur ou quelque chose avec la police VREMACCI et que vous avez confirmé que l'affichage est conforme à vos attentes. Vous voudrez peut-être essayer de faire la même chose dans iText juste pour avoir une idée de si le problème est lié à la bibliothèque PdfBox elle-même ... Si votre objectif principal est de générer des fichiers PDF, iText pourrait être une meilleure solution en tous cas.

EDIT - longue réponse aux commentaires:

ok - désolé pour le retour en arrière sur la question de l'encodage ... Votre question fondamentale (que vous saviez probablement déjà) est que le codage des octets en cours d'écriture le flux de contenu est différent du codage utilisé pour rechercher des glyphes. Maintenant, je vais essayer d'être utile:

J'ai regardé la classe d'encodage du dictionnaire dans PdfBox, et cela semble assez peu intuitif ... Le 'dictionnaire' en question est un dictionnaire PDF. Donc, ce que vous devez faire est de créer un objet dictionnaire Pdf (je pense que PdfBox appelle cela un type de COSObject), puis ajouter des entrées.

L'encodage d'une police est défini en PDF en tant que dictionnaire (voir page 266 de la spécification ci-dessus). Le dictionnaire contient un nom de codage de base, plus un tableau de différences optionnel. Techniquement, le tableau des différences ne devrait pas être utilisé avec les polices de type vrai (bien que je l'ai vu utilisé dans certains cas - ne l'utilisez pas, cependant).

Vous allez ensuite spécifier une entrée pour le cmap pour le codage. Ce cmap sera l'encodage de votre police.

Ma suggestion ici est de prendre un PDF existant qui fait ce que vous voulez, puis obtenir une image de la structure du dictionnaire pour la police afin que vous puissiez voir à quoi il ressemble.

Ce n'est certainement pas pour les faibles de cœur. Je peux fournir de l'aide - si vous avez besoin d'un vidage de dictionnaire, envoyez-moi un lien hypertexte avec un exemple de PDF et je l'utiliserai avec certains des algorithmes que j'utilise dans mon développement iText (je suis le mainteneur du sous-texte -système).

EDIT - 11/17/09

OK - voici la décharge dictionnaire à partir du fichier russian.pdf (sous-dictionnaires sont répertoriés en retrait, et dans l'ordre d'apparition dans le dictionnaire contenant):

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

Il y a beaucoup de pièces mobiles ici. vous pourriez vouloir assembler un document de test qui n'a que 3 ou 4 caractères dans la police en question ... Il y a beaucoup de polices de caractères de type 1 utilisées ici (en plus des polices TT), donc c'est difficile à dire ce qui est impliqué dans votre problème particulier.

(Etes-vous sûr que vous ne voulez pas au moins essayer ceci avec iText? ;-) Je ne dis pas que ça va marcher, juste que ça vaut le coup).

Pour référence, la décharge de dictionnaire ci-dessus a été obtenu en utilisant la classe com.lowagie.text.pdf.parser.PdfContentReaderTool

+0

Il n'y a pas de classe dans PDFBox qui supporte UTF8 ou UTF16, mais je pense que oui, c'est un problème d'encodage. Je sais que iText est une excellente bibliothèque, mais j'ai déjà commencé mon travail avec PDFBox et c'est bon jusqu'à présent, donc je veux rester avec PDFBox. – Brad

+0

Ugh. Si vous utilisez PDFBox pour analyser le contenu que vous avez créé, êtes-vous capable de récupérer le texte? Si oui, alors ce n'est probablement pas une limitation de l'encodage, pré-se ... Peut-être c'est juste un problème avec la façon dont PDFBox mappe les tuples octets aux glyphes? –

+0

Que voulez-vous dire en le récupérant? Je peux écrire d'autres langues étrangères comme le français, l'allemand, ... Mais d'autres comme le russe semblent être un problème. C'est un problème d'encodage, j'en suis sûr. Et la classe DictionaryEncoding a été créée pour permettre l'extension d'autres encodages non supportés mais je n'arrive toujours pas à comprendre comment l'utiliser. – Brad

-1

juste essayer celui-ci:

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

Cela fonctionne au moins avec le dernier (5.0.1) iText

5

La longue histoire est - pour faire sortie unicode au format PDF à partir d'une police TrueType, la sortie doit inclure une tonne de détails et apparemment informations superflues. Qu'est-ce qu'il se résume à ceci: à l'intérieur d'une police TrueType, les glyphes sont stockés sous forme de glyphes. Ces identifiants de glyphes sont associés à un caractère unicode particulier (et IIRC, un glyphe unicode peut se référer en interne à plusieurs points de code - comme & eacute; se référant à e et un accent aigu - ma mémoire est brumeuse). PDF n'a pas vraiment de support Unicode, sauf pour dire qu'il existe un mappage de valeurs UTF16BE dans une chaîne à glyph ids dans une police TrueType ainsi qu'un mappage des valeurs UTF16BE à Unicode - même si c'est l'identité.

  • un dictionnaire de polices de Subtype Type0 avec
    • un réseau DescendantFonts avec une entrée décrit ci-dessous
    • une entrée de ToUnicode qui mappe des valeurs de UTF16BE à unicode
    • un codage fixé à Identity-H

sortie d'un de mes tests unitaires sur mes propres outils ressemble à ceci:

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% Notez que le formatage est mauvais pour le flux

  • un dictionnaire de police de Subtype CIDFontType2 avec
    • un CIDSsytemInfo
    • un FontDescriptor
    • DW et W
    • un CIDToGIDMap qui mappe de l'ID de caractère à l'ID de glyphe

est ici celui du même test - ce qui est l'objet dans le tableau 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 

Pourquoi est-ce que je vous dis cela? Qu'est-ce que cela a à voir avec PDFBox? Juste ceci: sortie Unicode en PDF est, franchement, une douleur royale dans la crosse. Acrobat a été développé avant Ilicode et il était douloureux dès le départ d'avoir des codages CJK sans Unicode (je sais - j'ai travaillé sur Acrobat à l'époque). Plus tard, le support Unicode a été ajouté, mais il a vraiment eu l'impression d'être survenu. On espère que vous diriez juste/Encoding/Unicode et avoir des chaînes qui commencent par les caractères épine et y-dieresis et vous partez. Pas de chance. Si vous ne mettez pas dans chaque détail (et vraiment, Acrobat, en intégrant un programme PostScript à traduire en Unicode? WTH?), Vous obtenez une page vierge dans Acrobat. Je le jure, je ne le fais pas. À ce stade, j'écris des outils de génération PDF pour une entreprise séparée (.NET en ce moment, donc ça ne vous aidera pas), et j'ai fait un objectif de conception pour cacher tout ce non-sens. Tout le texte est unicode - si vous utilisez uniquement les codes de caractères qui sont les mêmes qu'un WinAnsi, c'est ce que vous obtenez sous le capot. Utilisez n'importe quoi d'autre, vous obtenez tous ces autres trucs avec. Je serais surpris si PDFBox fait ce travail pour vous - c'est un problème sérieux.

Questions connexes