O PDFlibPas converte conteúdo de PDF em dois formatos editáveis sem automação do Office. ExportPageMarkdown e ExportDocumentMarkdown retornam Markdown semântico com títulos inferidos, listas ordenadas e não ordenadas e tabelas em formato pipe, enquanto SaveDOCXToFile e SaveDOCXToStream gravam um pacote WordprocessingML contendo parágrafos, títulos, numeração de lista nativa, tabelas detectadas, estilo de fonte, quebras de página e imagens PNG posicionadas
Ambos rodam inteiramente em Pascal, em um servidor, sem o Word instalado e sem COM. Essa restrição é o motivo pelo qual o recurso existe em uma biblioteca de PDF, e não em uma ferramenta desktop
Por que "PDF para Word" é genuinamente difícil?
Porque uma página de PDF não contém parágrafos. Ela contém operadores de exibição de texto que posicionam runs de glifos em coordenadas, na ordem em que o produtor os emitiu, sem nenhuma obrigação de indicar que duas runs pertencem à mesma frase, muito menos ao mesmo item de lista. O formato foi projetado para descrever uma página impressa com exatidão, e ele consegue isso descartando a estrutura que produziu a página
Então todo conversor precisa reconstruir o que o gerador descartou. O agrupamento de linhas vem do espaçamento vertical e do alinhamento de baseline. Os limites de parágrafo vêm de mudanças de espaçamento e de recuo. Um título é uma linha cuja fonte é maior ou mais pesada do que o corpo do texto e que se destaca do que vem depois. Uma lista é uma sequência de parágrafos começando com um caractere de marcador ou um padrão numérico. Uma tabela é uma grade de blocos de texto cujas bordas se alinham ao longo de linhas e colunas. Cada uma dessas é uma inferência, e inferência significa um bom resultado em documentos que seguem convenções tipográficas comuns e um resultado medíocre em documentos que não seguem
PDFs tagueados são a exceção, e uma exceção grande. Quando o documento carrega uma árvore de estrutura, os papéis de parágrafo, título, lista e tabela são registrados em vez de adivinhados, e é por isso que o trabalho de acessibilidade descrito em estrutura de acessibilidade de PDF tagueado também compensa na qualidade da conversão. Se você controla o produtor, tagear sua saída é a coisa de maior alavancagem que você pode fazer por qualquer um que mais tarde precise convertê-la
Exportação em Markdown, uma página por vez
O caminho de Markdown é o indicado quando o destino é um pipeline de texto: um site de documentação, um índice de busca, um corpus de retrieval para um assistente. As opções são uma bit mask: PDF_MARKDOWN_INCLUDE_PAGE_MARKERS, PDF_MARKDOWN_DETECT_HEADINGS, PDF_MARKDOWN_PRESERVE_STYLES, com PDF_MARKDOWN_DEFAULT combinando as três
var
Pdf: TPDFlib;
Md: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.LoadFromFile('handbook.pdf', '');
// Uma página, como string
Md := Pdf.ExportPageMarkdown(1, PDF_MARKDOWN_DEFAULT);
// Um intervalo de páginas, gravado em disco em streaming como UTF-8 sem BOM
Pdf.SaveMarkdownToFile('1-40',
PDF_MARKDOWN_DETECT_HEADINGS or PDF_MARKDOWN_PRESERVE_STYLES,
'handbook.md');
finally
Pdf.Free;
end;
end;
Os marcadores de página se justificam em trabalho de retrieval. Um trecho de texto que carrega a página de onde veio pode ser citado com precisão, e um leitor que segue a citação chega exatamente onde a afirmação está. Desative-os quando o Markdown for destinado à leitura humana, onde os limites de página do layout de origem são apenas ruído
Os pontos de entrada de streaming importam para documentos grandes. SaveMarkdownToStream e SaveMarkdownToFile gravam UTF-8 uma página por vez e não armazenam em buffer a saída completa, então um manual de 900 páginas não vira antes uma string de 900 páginas na memória. A ausência de uma byte-order mark também é deliberada: um BOM em um arquivo Markdown confunde um número surpreendente de geradores de sites estáticos e ferramentas de diff
DOCX sem Office na máquina
O gravador de DOCX produz o pacote por conta própria: entradas ZIP gravadas como Deflate bruto com verificações CRC, as partes WordprocessingML, e os relacionamentos que as ligam. Nada chama o Word, o que significa que a conversão roda em um servidor headless, dentro de uma conta de serviço, em um container, em todos os lugares onde a automação do Office é sem licença, instável ou proibida
var
Pdf: TPDFlib;
Target: TFileStream;
begin
Pdf := TPDFlib.Create;
Target := TFileStream.Create('handbook.docx', fmCreate);
try
Pdf.LoadFromFile('handbook.pdf', '');
Pdf.SaveDOCXToStream('1-40',
PDF_DOCX_INCLUDE_IMAGES or PDF_DOCX_DETECT_HEADINGS or
PDF_DOCX_PRESERVE_STYLES or PDF_DOCX_PRESERVE_PAGE_BREAKS,
Target);
finally
Target.Free;
Pdf.Free;
end;
end;
Os dados de imagem são gravados à medida que cada página é processada, em vez de coletados e anexados no final, então o pico de memória acompanha uma página, e não o documento inteiro. A ordem explícita das páginas é preservada, e a página de PDF selecionada é restaurada depois, o que importa quando a exportação é uma etapa dentro de um job mais longo que tinha uma página selecionada por outros motivos
O que o empacotamento determinístico traz de benefício?
Reprodutibilidade byte a byte. Duas conversões da mesma entrada com as mesmas opções produzem o mesmo pacote, o que significa que você pode calcular o hash da saída para detectar mudanças, comparar dois builds de um documento gerado, e usar cache de forma agressiva sem se preocupar que uma entrada idêntica tenha produzido um artefato diferente
A automação do Office não pode prometer isso. Ela incorpora timestamps, identificadores de revisão e metadados dependentes da máquina, então o mesmo documento convertido duas vezes difere de formas que inviabilizam o hashing. O mesmo raciocínio motiva os identificadores de arquivo determinísticos discutidos em IDs de PDF determinísticos para builds reproduzíveis: quando a saída é reproduzível, a verificação vira uma comparação em vez de uma inspeção
Onde a saída é boa, e onde não é
Seja honesto com seus usuários sobre isso, porque a qualidade da conversão varia mais com a entrada do que com o conversor. PDFs tagueados e documentos comerciais gerados de forma limpa, notas fiscais, relatórios, contratos, convertem bem: títulos viram títulos, tabelas sobrevivem, listas são renumeradas corretamente no Word. Layouts acadêmicos de duas colunas convertem de forma aceitável se a geometria das colunas for regular. Tabelas que atravessam quebras de página são remontadas por inferência e às vezes ficam divididas. Material de marketing fortemente desenhado, onde o texto é posicionado por efeito visual em vez de ordem de leitura, converte mal, e nenhuma quantidade de inferência corrige isso
Documentos digitalizados são um caso totalmente separado. Uma página que é uma única imagem grande não contém nenhum objeto de texto, então não há nada para exportar até que exista uma camada de texto; o caminho de OCR que produz essa camada é um pré-requisito, não uma opção. Antes de rodar um lote grande, amostre uma dúzia de arquivos representativos e observe a saída, e considere enumerar os elementos da página primeiro, como descrito em busca de texto e enumeração de elementos de página, para ver o que as páginas realmente contêm
Para pipelines de assistentes e de retrieval, o caminho de Markdown costuma ser o alvo melhor: títulos viram limites de chunk, tabelas continuam legíveis como tabelas pipe, e os marcadores de página dão a cada chunk uma localização citável. Para edição humana, DOCX é a resposta, porque o que o usuário quer não é o texto, e sim a capacidade de alterá-lo
O PDFlibPas é uma biblioteca de PDF para Delphi, C++Builder e Lazarus com interfaces DLL e ActiveX correspondentes, de modo que as mesmas chamadas de exportação estão disponíveis a partir de C#, C++ ou hosts de script. A documentação completa e uma versão de teste estão na página da biblioteca PDFlibPas Delphi para PDF