Question

Mon programme génère des documents PDF relativement simples à la demande, mais je rencontre des problèmes avec les caractères Unicode, tels que les kanji ou les symboles mathématiques impairs. Pour écrire une chaîne normale en PDF, placez-la entre crochets:

(something)

Il existe également la possibilité d'échapper un caractère avec des codes octaux:

(\527)

mais cela ne fait que 512 caractères. Comment encodez-vous ou échappez-vous à des caractères plus élevés? J'ai déjà vu des références à des flux d'octets et à des chaînes codées en hexadécimal, mais aucune des références que j'ai lues ne semble vouloir me dire comment le faire.

Modifier: Vous pouvez également me diriger vers une bonne bibliothèque Java PDF qui fera le travail à ma place. Celui que j'utilise actuellement est une version de gnujpdf (dans laquelle j'ai corrigé plusieurs bugs, car l'auteur original semble avoir disparu), qui vous permet de programmer par rapport à une interface graphique AWT. Idéalement, tout remplacement devrait en faire le même.

Les alternatives semblent être soit HTML - > PDF, ou un modèle programmatique basé sur des paragraphes et des zones qui ressemble beaucoup à HTML. iText est un exemple de ce dernier. Cela signifierait réécrire mon code existant, et je ne suis pas convaincu qu'ils me donneraient la même souplesse dans la mise en page.

Éditer 2: Je ne m'en étais pas rendu compte auparavant, mais la bibliothèque iText possède une API Graphics2D et semble gérer parfaitement l'unicode. C'est donc ce que je vais utiliser. Bien que ce ne soit pas une réponse à la question posée, cela résout le problème pour moi.

Modifier 3: iText fonctionne correctement pour moi. Je pense que la leçon à retenir est que, face à quelque chose qui semble inutile et inutilement difficile, cherchez quelqu'un qui en sait plus que vous sur ce sujet.

Était-ce utile?

La solution

La réponse simple est qu’il n’ya pas de réponse simple. Si vous regardez la spécification PDF, vous verrez un chapitre entier & # 8212; et un long à ce & # 8212; consacré aux mécanismes d'affichage du texte. J'ai mis en œuvre tout le support PDF de mon entreprise et la gestion du texte était de loin la partie la plus complexe de l'exercice. La solution que vous avez découverte & # 8212; utilisez une bibliothèque tierce pour faire le travail à votre place & # 8212; & nbsp; est vraiment le meilleur choix, sauf si vous avez des exigences très spécifiques et spécifiques à vos fichiers PDF.

Autres conseils

Dans la référence PDF du chapitre 3, voici ce qu'ils disent à propos de Unicode:

  

Les chaînes de texte sont codées dans   PDFDocEncoding ou codage de caractères Unicode. PDFDocEncoding est un   ensemble de codage ISO Latin 1 et est documenté dans l’annexe D. Unicode   est décrit dans la norme Unicode par le consortium Unicode (voir la bibliographie).   Pour les chaînes de texte codées en Unicode, les deux premiers octets doivent être 254, suivis de   255. Ces deux octets représentent le marqueur d'ordre d'ordre des octets Unicode, U + FEFF, indiquant   que la chaîne est codée dans le schéma de codage UTF-16BE (big-endian) spécifié   dans la norme Unicode. (Ce mécanisme empêche de commencer une chaîne en utilisant   PDFDocEncodage avec les deux caractères thorn ydieresis, qui est peu probable   être un début significatif pour un mot ou une phrase).

La réponse de

Algoman est erronée à bien des égards. Vous pouvez créer un document PDF avec unicode "et ce n'est pas une science sidérurgique, même si cela nécessite du travail. Oui, il a raison. Pour utiliser plus de 255 caractères dans une police, vous devez créer un objet pdf de police composite (CIDFont). Ensuite, vous venez de mentionner la police TrueType que vous souhaitez utiliser comme entrée DescendatFont de CIDFont. L'astuce consiste à utiliser ensuite les indices de glyphes d'une police à la place des codes de caractères. Pour obtenir cette carte des indices, vous devez analyser la section cmap d'une police - obtenir le contenu de la police avec la fonction GetFontData et prendre en main la spécification TTF. Et c'est tout! Je viens de le faire et maintenant j'ai un pdf unicode!

Vous trouverez un exemple de code pour l'analyse de la section <=>: https://support.microsoft .com / fr-us / kb / 241020

Et oui, n'oubliez pas l'entrée / ToUnicode comme l'a souligné @ user2373071 sinon l'utilisateur ne pourra pas rechercher votre PDF ni en copier le texte.

Comme l'a souligné dredkin, vous devez utiliser les index de glyphes au lieu de la valeur de caractère Unicode dans le flux de contenu de la page. Cela suffit pour afficher du texte Unicode dans un fichier PDF, mais le texte Unicode ne serait pas interrogeable. Pour rendre le texte consultable ou pour que le copier / coller fonctionne, vous devez également inclure un flux / ToUnicode. Ce flux doit traduire chaque glyphe du document en caractère Unicode réel.

Voir l'Annexe D (page 995) de la spécification PDF. Le nombre de polices et de jeux de caractères prédéfinis dans une application consommateur PDF est limité. Pour afficher d'autres caractères, vous devez incorporer une police qui les contient. Il est également préférable d’incorporer uniquement un sous-ensemble de la police, comprenant uniquement les caractères requis, afin de réduire la taille du fichier. Je travaille également sur l'affichage des caractères Unicode au format PDF, ce qui est un problème majeur.

Découvrez PDFBox ou iText.

http://www.adobe.com/devnet/pdf/pdf_reference.html

Je travaille depuis plusieurs jours sur ce sujet et ce que j’ai appris, c’est que l’unicode est (et) aussi impossible en pdf. Utiliser des caractères à 2 octets de la manière décrite par socle ne fonctionne qu'avec les polices CID.

apparemment, CID-Fonts est une construction interne à pdf et ce ne sont pas vraiment des polices dans ce sens - elles ressemblent davantage à des sous-routines graphiques, qui peuvent être invoquées en les adressant (avec des adresses 16 bits).

Donc, utiliser unicode en pdf directement

  1. vous devez convertir les polices normales en polices CID, ce qui est probablement très difficile - vous devez générer les routines graphiques à partir de la police d'origine (?), extraire les métriques de caractères, etc.
  2. vous ne pouvez pas utiliser les polices CID comme des polices normales - vous ne pouvez pas les charger ou les mettre à l'échelle de la façon dont vous chargez et mettez à l'échelle les polices normales
  3. De plus, les caractères 2 octets ne couvrent même pas tout l'espace Unicode

IMHO, ces points rendent absolument impossible l'utilisation d'unicode directement .

Ce que je fais maintenant, c’est d’utiliser les caractères indirectement de la manière suivante: Pour chaque police, je génère une page de codes (et une table de correspondance pour les recherches rapides) - en c ++, cela ressemble à quelque chose comme

std::map<std::string, std::vector<wchar_t> > Codepage;
std::map<std::string, std::map<wchar_t, int> > LookupTable;

alors, chaque fois que je veux mettre une chaîne unicode sur une page, j'itère ses caractères, je les cherche dans la table de recherche et, s'ils sont nouveaux, je les ajoute à la page de code comme suit:

for(std::wstring::const_iterator i = str.begin(); i != str.end(); i++)
{                
    if(LookupTable[fontname].find(*i) == LookupTable[fontname].end())
    {
        LookupTable[fontname][*i] = Codepage[fontname].size();
        Codepage[fontname].push_back(*i);
    }
}

alors, je génère une nouvelle chaîne, où les caractères de la chaîne d'origine sont remplacés par leurs positions dans la page de code comme suit:

static std::string hex = "0123456789ABCDEF";
std::string result = "<";
for(std::wstring::const_iterator i = str.begin(); i != str.end(); i++)
{                
    int id = LookupTable[fontname][*i] + 1;
    result += hex[(id & 0x00F0) >> 4];
    result += hex[(id & 0x000F)];
}
result += ">";

par exemple, " H & # 8364; Monde llo! " pourrait devenir < 01020303040506040703080905 > et maintenant vous pouvez simplement mettre cette chaîne dans le pdf et la faire imprimer, en utilisant l'opérateur Tj comme d'habitude ...

mais vous avez maintenant un problème: le pdf ne sait pas que vous voulez dire & "H &"; par un 01. Pour résoudre ce problème, vous devez également inclure la page de codes dans le fichier pdf. Pour ce faire, ajoutez un / codage à l'objet Police et définissez ses différences

.

Pour le " H & # 8364; Monde llo! " Par exemple, cet objet Font fonctionnerait:

5 0 obj 
<<
    /F1
    <<
        /Type /Font
        /Subtype /Type1
        /BaseFont /Times-Roman
        /Encoding
        <<
          /Type /Encoding
          /Differences [ 1 /H /Euro /l /o /space /W /r /d /exclam ]
        >>
    >> 
>>
endobj 

Je le génère avec ce code:

ObjectOffsets.push_back(stream->tellp()); // xrefs entry
(*stream) << ObjectCounter++ << " 0 obj \n<<\n";
int fontid = 1;
for(std::list<std::string>::iterator i = Fonts.begin(); i != Fonts.end(); i++)
{
    (*stream) << "  /F" << fontid++ << " << /Type /Font /Subtype /Type1 /BaseFont /" << *i;

    (*stream) << " /Encoding << /Type /Encoding /Differences [ 1 \n";
    for(std::vector<wchar_t>::iterator j = Codepage[*i].begin(); j != Codepage[*i].end(); j++)
        (*stream) << "    /" << GlyphName(*j) << "\n";
    (*stream) << "  ] >>";

    (*stream) << " >> \n";
}
(*stream) << ">>\n";
(*stream) << "endobj \n\n";

Notez que j'utilise un registre de polices global - les mêmes noms de polices / F1, / F2, ... sont utilisés dans tout le document pdf. Le même objet de registre de polices est référencé dans l'entrée / Resources de toutes les pages. Si vous faites cela différemment (par exemple, vous utilisez un registre de polices par page), vous devrez peut-être adapter le code à votre situation ...

Alors, comment trouvez-vous les noms des glyphes (/ Euro pour & "; & # 8364; &"; / / exclam pour & "!! &", etc. )? Dans le code ci-dessus, vous devez simplement appeler & "GlyphName (* j) &"; J'ai généré cette méthode avec un script BASH à partir de la liste située à

http://www.jdawiseman.com/papers/trivia/character- entités.html

et cela ressemble à ceci

const std::string GlyphName(wchar_t UnicodeCodepoint)
{
    switch(UnicodeCodepoint)
    {
        case 0x00A0: return "nonbreakingspace";
        case 0x00A1: return "exclamdown";
        case 0x00A2: return "cent";
        ...
    }
}

Un problème majeur que j'ai laissé ouvert est que cela ne fonctionne que si vous utilisez au plus 254 caractères différents à partir de la même police. Pour utiliser plus de 254 caractères différents, vous devez créer plusieurs pages de codes pour la même police.

Dans le fichier PDF, différentes pages de codes sont représentées par différentes polices. Par conséquent, pour passer d’une page de code à une autre, vous devez changer de police, ce qui pourrait théoriquement augmenter considérablement votre fichier PDF, mais je peux vivre avec cela .. .

Je ne suis pas un expert en PDF, et (comme l'a dit Ferruccio), les spécifications PDF d'Adobe devraient tout vous dire, mais une pensée me vient à l'esprit:

Êtes-vous sûr que vous utilisez une police qui prend en charge tous les caractères dont vous avez besoin?

Dans notre application, nous créons un fichier PDF à partir de pages HTML (avec une bibliothèque tierce), et nous avons eu ce problème avec les caractères cyrilliques ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top