Pergunta

O meu programa gera documentos PDF relativamente simples, a pedido, mas eu estou tendo problemas com caracteres Unicode, como kanji ou símbolos matemáticos ímpares. Para escrever uma string normal em PDF, você colocá-lo entre parênteses:

(something)

Há também a opção para escapar de um personagem com códigos octais:

(\527)

mas isso só vai até 512 caracteres. Como você codificar ou escapar caracteres superiores? Já vi referências aos fluxos de bytes e strings codificadas em hexadecimal, mas nenhuma das referências que li parece estar disposto a me dizer como realmente fazê-lo.


Editar: Como alternativa, me aponte para um bom Java biblioteca de PDF que irá fazer o trabalho para mim. O que eu estou usando atualmente é uma versão do gnujpdf (que eu tenho fixa vários bugs em, uma vez que o autor original parece ter AWOL ido), que permite que você programa contra uma interface AWT Graphics, e, idealmente, qualquer substituição deve fazer o mesmo.

As alternativas parecem ser HTML -> PDF, ou um modelo programático baseado em parágrafos e caixas que se sente muito parecido com HTML. iText é um exemplo do último. Isto significaria reescrever meu código existente, e eu não estou convencido de que eles me daria a mesma flexibilidade no layout de.


Editar 2: Eu não tinha percebido antes, mas a biblioteca iText tem uma API Graphics2D e parece lidar com unicode perfeitamente, então é isso que eu vou estar usando. Embora não seja uma resposta para a pergunta como solicitado, ele resolve o problema para mim.


Editar 3: iText está trabalhando muito bem para mim. Eu acho que a lição é, quando confrontados com algo que parece inutilmente difícil, olhar para alguém que sabe mais sobre ele do que você.

Foi útil?

Solução

A resposta simples é que não há nenhuma resposta simples. Se você der uma olhada na especificação PDF, você verá um capítulo inteiro - e um longo naquele - dedicada aos mecanismos de apresentação de texto. I implementado todo o suporte PDF para a minha empresa e texto manipulação foi de longe a parte mais complexa do exercício. A solução que você descobriu - use uma biblioteca parte 3 para fazer o trabalho para você -. É realmente a melhor escolha, a menos que você tem, requisitos muito específicos para fins especiais para seus arquivos PDF

Outras dicas

Na referência PDF no capítulo 3, isto é o que eles dizem sobre Unicode:

As cadeias de texto são codificados em quer PDFDocEncoding ou codificação de caracteres Unicode. PDFDocEncoding é um superset da ISO Latina uma codificação e está documentado no Apêndice D. Unicode é descrito na Norma Unicode pelo Unicode Consortium (ver a Bibliografia). Para cadeias de texto codificado em Unicode, os primeiros dois bytes devem ser seguidos por 254 255. Estes dois bytes representam o marcador Unicode ordem de byte, L + FEFF, indicando que a cadeia é codificado no UTF-16BE (big-endian) que codifica esquema especificado no padrão Unicode. (Este mecanismo opõe começando uma cadeia utilizando PDFDocEncoding com os dois personagens espinho ydieresis, o que é pouco provável que ser um início significativa de uma palavra ou frase).

A resposta de Algoman é errado em muitas coisas. Você pode Faça um documentos PDF com unicode nele' e não é uma ciência de foguetes, embora ele precisa de algum trabalho. Sim, ele está certo, usar mais de 255 caracteres de uma fonte que você tem que criar um pdf objeto fonte composta (CIDFont). Então você acabou de mencionar a fonte TrueType real que você deseja usar como uma entrada DescendatFont de CIDFont. O truque é que depois que você tem que usar glifo índices de uma fonte em vez de códigos de caracteres. Para obter esta índices mapear você tem seção cmap de uma fonte para analisar - obter conteúdo da fonte com a função GetFontData e tomar as mãos na especificação TTF. E é isso! Eu só fiz isso e agora eu tenho um pdf unicode!

Código de exemplo para analisar seção cmap está aqui: https://support.microsoft.com / en-us / kb / 241020

E sim, não se esqueça / entrada ToUnicode como @ user2373071 fora pontas ou usuário não será capaz de pesquisar o seu PDF ou copiar texto a partir dele.

Como dredkin apontou, você tem que usar os índices de glifo em vez do valor de caracteres Unicode no fluxo de conteúdo da página. Isto é suficiente para exibir o texto Unicode em PDF, mas o texto Unicode não seria pesquisável. Para tornar o texto pesquisável ou ter copiar / colar trabalhar sobre ela, você também terá de incluir um fluxo / ToUnicode. Este fluxo deve traduzir cada glifo no documento para o personagem real Unicode.

Veja o Apêndice D (página 995) da especificação PDF. Há um número limitado de fontes e conjuntos de caracteres pré-definidos em uma aplicação PDF consumidor. Para exibir outros personagens que você precisa para incorporar uma fonte que os contém. Também é preferível incorporar apenas um subconjunto da fonte, incluindo apenas caracteres requeridos, a fim de reduzir o tamanho do ficheiro. Eu também estou trabalhando em exibição de caracteres Unicode em PDF e é um dos principais problemas.

Confira PDFBox ou iText.

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

Eu tenho trabalhado vários dias sobre este assunto agora e que eu aprendi é que unicode é (tão bom quanto) impossível em pdf. A utilização de caracteres de 2 bytes a maneira plinto descritos só funciona com CID-Fontes.

aparentemente, CID-fontes são uma construção pdf-interno e eles não são realmente fontes nesse sentido -. Eles parecem ser mais parecido com gráficos sub-rotinas, que podem ser invocadas por enfrentá-los (com endereços de 16 bits)

Assim, para uso unicode em pdf diretamente

  1. você teria que converter fontes normais para CID-Fonts, o que provavelmente é extremamente difícil - (?). Você tem que gerar as rotinas gráficas da fonte original, caráter extrato métricas etc
  2. você não pode usar CID-fontes como fontes normais - você não pode carregar ou escalá-los da maneira que você carregar e dimensionar fontes normais
  3. também, caracteres de 2 bytes não chega a cobrir todo o espaço Unicode

IMHO, esses pontos tornam absolutamente inviável usar unicode diretamente .



O que estou fazendo em vez agora está usando os caracteres indiretamente da seguinte maneira: Para cada tipo de letra, eu gerar uma página de código (e uma pesquisa de mesa para pesquisas rápidas) - em c ++ isso seria algo como

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

Então, sempre que eu quero colocar alguns unicode-string em uma página, I iterate seus personagens, procurá-los em tabela de pesquisa e - se eles são novos, eu adicioná-los ao código-página como esta:

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

então, eu gerar uma nova cadeia, onde os personagens do string original são substituídas por suas posições na página de código como este:

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 exemplo, "H € llo mundo!" pode se tornar <01020303040506040703080905> e agora você pode simplesmente colocar essa string para o pdf e tê-lo impresso, usando o operador Tj, como de costume ...

, mas agora você tem um problema: o pdf não sabe que você quer dizer "H" por um 01. Para resolver este problema, você também tem que incluir a página de códigos no arquivo pdf. Isto é feito através da adição de um / Encoding para o objeto Font e definindo seu Diferenças

Para o "H € llo mundo!" exemplo, este Font-objeto iria funcionar:

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 

Eu gerá-lo com 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";

Observe que eu uso uma fonte de registro global - Eu uso os mesmos nomes de fonte / F1, / F2, ... em todo o documento pdf. O mesmo objeto font-registo é referenciado no / Recursos A entrada de todas as páginas. Se você fizer isso de forma diferente (por exemplo, você usar um font-registo por página) - você pode ter que adaptar o código para a sua situação ...

Assim como você encontra os nomes dos glifos (/ Euro para "€", / exclam para "!" Etc.)? No código acima, isso é feito simplesmente chamando "GlyphName (* j)". I geraram este método com uma festança-Script da lista encontrada no site

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

e parece que este

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

A grande problema eu deixei aberta é que este só funciona enquanto você usar, no máximo, 254 caracteres diferentes a partir da mesma fonte. Para usar mais de 254 caracteres diferentes, você teria que criar várias páginas de código para a mesma fonte.

Dentro do pdf, diferentes páginas de código são representadas por diferentes fontes, de modo a alternar entre páginas de código, você teria que mudar fontes, o que teoricamente poderia explodir sua pdf-se um pouco, mas eu, pelo menos, posso viver com isso .. .

Eu não sou um especialista em PDF, e (como disse Ferruccio) as especificações PDF da Adobe deve dizer-lhe tudo, mas um pensamento surgiu em minha mente:

Você tem certeza de que você está usando uma fonte que suporta todos os caracteres que você precisa?

Em nossa aplicação, criamos PDF de páginas HTML (com uma biblioteca de terceiros), e tivemos este problema com caracteres cirílicos ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top