Pregunta

Mi programa genera documentos PDF relativamente simples a pedido, pero tengo problemas con los caracteres Unicode, como kanji o símbolos matemáticos impares.Para escribir una cadena normal en PDF, la colocas entre paréntesis:

(something)

También existe la opción de escapar de un carácter con códigos octales:

(\527)

pero esto sólo llega a 512 caracteres.¿Cómo se codifican o escapan caracteres superiores?He visto referencias a flujos de bytes y cadenas codificadas en hexadecimal, pero ninguna de las referencias que he leído parece estar dispuesta a decirme cómo hacerlo realmente.


Editar: Alternativamente, indíqueme una buena biblioteca PDF de Java que hará el trabajo por mí.La que estoy usando actualmente es una versión de gnujpdf (en la que he solucionado varios errores, ya que el autor original parece haberse ausentado sin permiso), que le permite programar en una interfaz de gráficos AWT, e idealmente cualquier reemplazo debería funcionar. lo mismo.

Las alternativas parecen ser HTML -> PDF o un modelo programático basado en párrafos y cuadros que se parece mucho a HTML.iText es un ejemplo de esto último.Esto significaría reescribir mi código existente y no estoy convencido de que me brinden la misma flexibilidad a la hora de diseñarlo.


Edición 2: No me di cuenta antes, pero la biblioteca iText tiene una API Graphics2D y parece manejar Unicode perfectamente, así que eso es lo que usaré.Aunque no es una respuesta a la pregunta formulada, me resuelve el problema.


Edición 3: iText está funcionando muy bien para mí.Supongo que la lección es que, cuando te enfrentas a algo que parece inútilmente difícil, busca a alguien que sepa más sobre ello que tú.

¿Fue útil?

Solución

La respuesta simple es que no hay una respuesta simple. Si echa un vistazo a la especificación PDF, verá un capítulo completo & # 8212; y uno largo en ese & # 8212; dedicado a los mecanismos de visualización de texto. Implementé todo el soporte de PDF para mi empresa, y manejar el texto fue, con mucho, la parte más compleja del ejercicio. La solución que descubrió & # 8212; usar una biblioteca de terceros para hacer el trabajo por usted & # 8212; & nbsp; es realmente la mejor opción, a menos que tenga requisitos muy específicos y especiales para sus archivos PDF.

Otros consejos

En la referencia en PDF del capítulo 3, esto es lo que dicen sobre Unicode:

  

Las cadenas de texto están codificadas en   ya sea PDFDocEncoding o codificación de caracteres Unicode. PDFDocEncoding es un   superconjunto de la codificación ISO Latin 1 y está documentado en el Apéndice D. Unicode   se describe en el Estándar Unicode por el Consorcio Unicode (ver la Bibliografía).   Para las cadenas de texto codificadas en Unicode, los primeros dos bytes deben ser 254 seguidos de   255. Estos dos bytes representan el marcador de orden de bytes Unicode, U + FEFF, que indica   que la cadena está codificada en el esquema de codificación UTF-16BE (big-endian) especificado   en el estándar Unicode. (Este mecanismo impide comenzar una cadena usando   PDFDocEncoding con los dos caracteres thorn ydieresis, que es poco probable que   ser un comienzo significativo de una palabra o frase).

La respuesta de Algoman es equivocado en muchas cosas.Tú poder crear documentos PDF con Unicode y no es una ciencia espacial, aunque necesita algo de trabajo.Sí, tiene razón, para utilizar más de 255 caracteres en una fuente, debe crear un objeto pdf de fuente compuesta (CIDFont).Luego simplemente menciona la fuente TrueType real que desea usar como entrada DescendatFont de CIDFont.El truco es que después de eso tienes que usar índices de glifos de una fuente en lugar de códigos de caracteres.Para obtener este mapa de índices tienes que analizar cmap sección de una fuente: obtenga el contenido de la fuente con GetFontData funcionar y asumir la especificación TTF.¡Y eso es!¡Lo acabo de hacer y ahora tengo un pdf Unicode!

Código de muestra para análisis cmap La sección está aquí: https://support.microsoft.com/en-us/kb/241020

Y sí, no olvide la entrada /ToUnicode como señaló @user2373071 o el usuario no podrá buscar su PDF ni copiar texto del mismo.

Como señaló dredkin, debe usar los índices de glifos en lugar del valor de caracteres Unicode en la secuencia de contenido de la página. Esto es suficiente para mostrar el texto Unicode en PDF, pero el texto Unicode no se podrá buscar. Para que el texto se pueda buscar o para que funcione copiar / pegar, también deberá incluir una secuencia / ToUnicode. Esta secuencia debe traducir cada glifo del documento al carácter Unicode real.

Consulte el Apéndice D (página 995) de la especificación PDF. Hay una cantidad limitada de fuentes y juegos de caracteres predefinidos en una aplicación de consumidor PDF. Para mostrar otros caracteres, debe incrustar una fuente que los contenga. También es preferible incrustar solo un subconjunto de la fuente, incluidos los caracteres necesarios, para reducir el tamaño del archivo. También estoy trabajando en mostrar caracteres Unicode en PDF y es una molestia importante.

Consulte PDFBox o iText.

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

He trabajado varios días en este tema ahora y lo que he aprendido es que unicode es (tan bueno) como imposible en pdf. El uso de caracteres de 2 bytes de la manera en que se describe el zócalo solo funciona con fuentes CID.

aparentemente, las fuentes CID son una construcción interna de pdf y en realidad no son fuentes en ese sentido; parecen ser más como subrutinas gráficas, que se pueden invocar dirigiéndolas (con direcciones de 16 bits).

Entonces, para usar Unicode en pdf directly

  1. tendrías que convertir las fuentes normales a fuentes CID, lo que probablemente sea extremadamente difícil: tendrías que generar las rutinas gráficas a partir de la fuente original (?), extraer las métricas de caracteres, etc.
  2. no puede usar las fuentes CID como las fuentes normales: no puede cargarlas o escalarlas de la forma en que carga y escala las fuentes normales
  3. también, los caracteres de 2 bytes ni siquiera cubren todo el espacio Unicode

En mi humilde opinión, estos puntos hacen que sea absolutamente inviable utilizar unicode directamente .



Lo que estoy haciendo ahora es usar los caracteres indirectamente de la siguiente manera: Para cada fuente, genero una página de códigos (y una tabla de búsqueda para búsquedas rápidas) - en c ++ esto sería algo así como

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

luego, cada vez que quiero poner una cadena Unicode en una página, itero sus caracteres, los busco en la tabla de búsqueda y, si son nuevos, los agrego a la página de códigos de esta manera:

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);
    }
}

entonces, genero una nueva cadena, donde los caracteres de la cadena original se reemplazan por sus posiciones en la página de códigos como esta:

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 += ">";

por ejemplo, " H & # 8364; llo World! " podría convertirse en < 01020303040506040703080905 > y ahora puedes poner esa cadena en el pdf e imprimirla, usando el operador Tj como de costumbre ...

pero ahora tiene un problema: el pdf no sabe que quiere decir " H " por un 01. Para resolver este problema, también debe incluir la página de códigos en el archivo pdf. Esto se hace agregando un / Codificación al objeto Fuente y configurando sus Diferencias

Para el " H & # 8364; llo World! " ejemplo, este Font-Object funcionaría:

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 

Lo genero con este código:

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";

Tenga en cuenta que uso un registro de fuente global: uso los mismos nombres de fuente / F1, / F2, ... en todo el documento pdf. Se hace referencia al mismo objeto de registro de fuente en la entrada / Resources de todas las páginas. Si hace esto de manera diferente (por ejemplo, usa un registro de fuente por página), es posible que deba adaptar el código a su situación ...

Entonces, ¿cómo encuentras los nombres de los glifos (/ Euro para " & # 8364; " ;, / exclam for "! " etc. )? En el código anterior, esto se hace simplemente llamando a & Quot; GlyphName (* j) & Quot ;. He generado este método con un BASH-Script de la lista que se encuentra en

http://www.jdawiseman.com/papers/trivia/character- entidades.html

y se ve así

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

Un problema importante que he dejado abierto es que este solo funciona siempre que use como máximo 254 caracteres diferentes de la misma fuente. Para usar más de 254 caracteres diferentes, deberá crear varias páginas de códigos para la misma fuente.

Dentro del pdf, las diferentes páginas de códigos están representadas por diferentes fuentes, por lo que para cambiar entre páginas de códigos, tendría que cambiar las fuentes, lo que teóricamente podría hacer explotar un poco su PDF, pero por mi parte, puedo vivir con eso ... .

No soy un experto en PDF, y (como dijo Ferruccio) las especificaciones de PDF en Adobe deberían decirle todo, pero un pensamiento surgió en mi mente:

¿Está seguro de que está utilizando una fuente que admite todos los caracteres que necesita?

En nuestra aplicación, creamos PDF a partir de páginas HTML (con una biblioteca de terceros), y tuvimos este problema con los caracteres cirílicos ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top