DEV Community

Cover image for Resolvendo Erros de Encoding e Texto Ilegível em PDFs:
Ramalho Jackson
Ramalho Jackson

Posted on • Edited on • Originally published at textlayerocr.com

Resolvendo Erros de Encoding e Texto Ilegível em PDFs:

Se você já tentou extrair texto de um PDF e acabou com lixo (□□□, (cid:45), ``, [$d­2&'Ç0]) ao colar o conteúdo (ou até mesmo viu este lixo na tela), entenda o motivo neste post.

Presumimos que se conseguimos ler algo na tela, o conteúdo associado a este texto deve existir ou estar válido, isso não é verdade. A realidade do formato PDF é um pouco mais complexa.

Vamos mergulhar um pouco no que está por trás disso:

Por que o texto aparece correto, mas está quebrado?

Semântica

Você vê o texto e consegue selecioná-lo, mas na área de transferência o conteúdo não corresponde ao que está sendo exibido. Ou, ao renderizar um PDF aparentemente normal em alguns visualizadores, o conteúdo é exibido corretamente,e em outros o texto é exibido com caracteres estranhos. Por que isso acontece?

Detalhamento:

O PDF possui glifos visuais, mas não carrega um mapa de tradução destes caracteres para para caracteres Unicode.

No PDF, o texto é desenhado com apontamento para índices de caracteres (CIDs ou 'Character IDs').

Para desenhar a letra "A", o PDF diz: "Use o desenho do índice 35 da fonte X", e assim por diante.

Para extrair um conteúdo de texto, o PDF precisa de uma tabela de mapeamento de CID para Unicode (ToUnicode Map) que diga: "O CID 35 é o símbolo U+0041 ('A')" do Unicode.

Quando esse mapa está ausente ou inválido, os visualizadores de PDF utilizam heurísticas próprias para desenhar os CIDs, e essa renderização pode estar correta em alguns viewers (principalmente fora dos browsers), mas invariavelmente o Copia e Cola irá retornar lixo, ou CIDs crus.

Esse tratamento difere entre visualizadores, por isso o mesmo arquivo que aparece correto no PDFium e Adobe Reader, por exemplo, pode exibir lixo em outro viewer. E sempre irá exibir lixo em renderizadores html, e em alguns interpretadores de PDF, como o GhostScript.

Por que mudar o 'Encoding' não resolve:

Não me engane dizendo que nunca tentou corrigir esse problema forçando uma decodificação, como se o PDF fosse um arquivo de texto UTF-8:

code snippet

Ou tentou (provavelmente em vão) encontrar alguma forma de adicionar o mapa de fonte posteriormente, querendo corrigir a renderização de fontes. Além de complicado, esses processos não são garantidos, e soluções de PDF são caras.

Porque Falha:
Não é uma questão de encoding incorreto (como UTF-8 ou ANSI). É uma questão de dados ausentes.

Se o leitor não sabe que o glifo desenhado é um "A", nenhuma configuração de encoding irá solucionar isso. O elo entre o visual e o significado está quebrado desde a criação do arquivo.

Muitas vezes isso ocorre no resultado de algum software legado que gera layout e ignora semântica.

A Solução Unificada: OCR (Optical Character Recognition)

A solução para PDFs escaneados/achatados e PDFs com mapas ToUnicode ausentes pode ser a mesma: Ignorar o conteúdo semântico e tratar da camada visual.

O Reconhecimento Óptico de Caracteres (OCR) funciona nesse cenário porque ele considera apenas o visual (a parte ainda correta), e reconstrói a semântica.

O Fluxo de Correção:

correction flow chart

Exemplo de Implementação (Node.js)

Esta abordagem em pseudo-codigo, resolveria tanto para documentos escaneados, quanto os com erros de mapeamento, pois converte tudo para imagem primeiro e reconstrói o conteúdo de texto.

code snippet

O Ponto Cego: Formulários e Widgets

Aqui está o grande problema. Ao usar bibliotecas de OCR padrão (como Tesseract ou soluções genéricas) todas elas tratam o documento apenas como uma imagem; Enquanto ele resolve o problema do PDF escaneado, ele quebra o formulário, e se ele retorna o formulário, ele mantém o erro na semântica (ainda renderiza errado, e o conteúdo copiado é lixo).

Se o PDF original possuía campos de formulário (os AcroForms de PDF), checkboxes e widgets interativos, etc., o processo tradicional de OCR irá 'achatá-los', você vai perder tudo. O resultado será um PDF com texto pesquisável, mas que perdeu a capacidade de preenchimento.

A única ferramenta atual que realiza esse processo de reconstrução da camada de texto mantendo a integridade de widgets originais é essa:
TextLayerOCR.

Ela processa a correção visual sem destruir os metadados interativos do documento. Vamos ver algumas estratégias para alcançar este resultado:

Estratégia Híbrida para Produção

Em sistemas reais, OCR é caro (pelo processamento pesado). Não deve ser feito em todos os casos. Uma estratégia inteligente de OCR detecta a quantidade de problemas semânticos antes de decidir usa-lo, identificando se alguma das fontes não possui mapeamento explicito.

code snippet


Conclusão

A renderização de um PDF depende da integridade interna do arquivo.

  1. Visual e semântico são duas coisas distintas: Ver o texto na tela não garante que o computador sabe o que está escrito.
  2. CIDs vs Unicode: Se o mapa ToUnicode não existe (ou está errado), o visualizador só consegue desenhar e não entender, (isso quando desenha alguma coisa).
  3. OCR é uma Solução: Para os casos de Scan ou Fontes Quebradas, a solução mais robusta é usar OCR para regenerar a camada semântica.
  4. Preservação: Se o seu fluxo exige formulários ativos, ferramentas de OCR comuns não funcionam (testamos todas as principais); você precisará de uma solução especializada.

TextLayer OCR - Teste a API que lida automaticamente com falhas de mapa Unicode e processa a correção visual sem destruir os metadados interativos do documento.


Threads relacionadas:
https://stackoverflow.com/questions/12857849/how-to-repair-a-pdf-file-and-embed-missing-fonts
https://github.com/dompdf/dompdf/issues/1717
https://github.com/Vanuan/unicodify_pdf
https://support.axes4.com/hc/en-us/articles/7371586760210-Edit-Unicode-Mapping
https://superuser.com/questions/1275337/resetting-unicode-mappings-in-pdf-text
... dentre várias.
TextLayer OCR - Teste a API que lida automaticamente com falhas de mapa Unicode.

Top comments (0)