ConvertToPDFA transforma um documento comum em um documento arquivável em uma única chamada: remove o que a parte escolhida proíbe, adiciona o que ela exige, declara a parte que o documento reivindica, e em seguida verifica o resultado. A reivindicação é reportada como atendida apenas quando a verificação passa, e GetPDFAConversionReport lista o que foi feito e o que ainda está no caminho
Essa última propriedade é a decisão de projeto que vale a pena examinar. Um conversor que carimba a reivindicação sem verificar é pior do que nenhum conversor, porque um arquivo que diz ser arquivável e não é passa direto pelos mesmos sistemas que de outro modo o teriam pegado. A falha aparece anos depois, em uma auditoria, em um documento que ninguém consegue regenerar
Por que um PDF aparentemente válido falha em uma verificação de PDF/A?
Na maioria das vezes porque os dois lugares em que um PDF diz quem o escreveu discordam. Um validador lê tanto o dicionário de informações do documento quanto o pacote XMP e rejeita um arquivo em que eles diferem — e a maioria dos arquivos que falham nesse ponto simplesmente nunca teve a metade XMP escrita
RepairDocumentMetadata traz os dois para um acordo e devolve quantas entradas reparou. Quando só uma metade carrega um valor, a outra é preenchida a partir dela, então nada do que já foi registrado é jogado fora. Ninguém precisa decidir qual cópia é autoritativa, porque na prática uma cópia está vazia
Há um segundo reparo na mesma chamada que pega um caso mais sutil. Um documento configurado para um modo PDF/A tem sua identificação de padrões restaurada se ela foi perdida, o que acontece sempre que um chamador fornece um pacote XMP próprio. Sem essa identificação um validador lê o arquivo como um PDF comum e relata todas as regras da parte reivindicada como não atendidas — uma falha de aparência espetacular com uma causa pequena
var
Lib: TPDFlib;
Repaired: Integer;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('incoming.pdf', '');
Repaired := Lib.RepairDocumentMetadata;
Log(Format('%d metadata entries brought into agreement', [Repaired]));
Lib.SaveToFile('incoming-fixed.pdf');
finally
Lib.Free;
end;
end;
Escolhendo a parte antes de converter
SetPDFAMode e ConvertToPDFA compartilham a mesma numeração de modo, e três dos valores são recentes. O modo 9 é PDF/A-4, a parte construída sobre PDF 2.0. O modo 10 é PDF/A-4e, que adicionalmente permite 3D e rich media, e o modo 11 é PDF/A-4f, que permite um arquivo embutido de qualquer formato
A parte 4 se identifica de modo diferente das anteriores: pelo número da parte e pelo ano em que foi publicada, sem letra de conformidade para o PDF/A-4 simples e com a letra E ou F para as duas extensões. A verificação reconhece a parte 4, julga seus arquivos contra PDF 2.0 em vez de 1.7, e relata um arquivo da parte 4 que não declara seu ano de revisão
Cada arquivo embutido em um documento da parte 4 declara como ele se relaciona com o documento, como as partes 3 e 4 exigem. Essa é a regra que costumava pegar anexos comuns: a relação era escrita apenas para anexos além do primeiro e nunca para o último, então um documento com um único anexo — o caso mais comum — não carregava relação alguma e falhava na validação exatamente nesse ponto
var
Verdict: Integer;
begin
Lib.LoadFromFile('report.pdf', '');
Verdict := Lib.ConvertToPDFA(9); // 9 = PDF/A-4, 10 = 4e, 11 = 4f
Memo1.Lines.Text := Lib.GetPDFAConversionReport;
if Verdict = 1 then
Lib.SaveToFile('report-pdfa4.pdf')
else
Log('conversion incomplete - see the report for what stands in the way');
end;
Para que serve o relatório de conversão
Para decidir o que fazer em seguida. Uma conversão que termina com sucesso não precisa de relatório; uma que não termina é toda a razão de o relatório existir. Alguns obstáculos são removíveis por um conversor e outros não — criptografia, conteúdo proibido que carrega significado, um programa de fonte que simplesmente não está em lugar algum da máquina. O relatório distingue o que foi feito do que restou, o que transforma "conversão falhou" em um item de trabalho
Trate o veredito como o portão em um pipeline de lote. Converta, leia o veredito eroteie o arquivo: arquive os que passaram, enfrente o restante para um humano com o relatório anexo. O que você não deve fazer é salvar a saída de uma conversão falha no arquivo porque ela parece melhor do que a entrada — ela agora carrega uma reivindicação que a verificação se recusou a confirmar
Lendo a marca que um arquivo já carrega
Antes de converter qualquer coisa, saiba o que o documento diz sobre si mesmo. Uma verificação de PDF/A que não consegue ler a marca de padrões existente julga todo arquivo contra a parte 1, não importando o que ele declare, o que significa que um documento PDF/A-2 ou PDF/A-3 perfeitamente válido é reportado como não carregando marca e como sendo de versão alta demais — o oposto da verdade
A marca é lida independentemente de o produtor tê-la escrito como um elemento XMP ou como um atributo. Ambas as formas são XMP comum, e aceitar só uma delas deixa arquivos de outros produtores parecendo não marcados. Se você já se perguntou por que um documento que valida em outro lugar falha no seu próprio pipeline, este é um bom ponto para olhar primeiro
Higienizar antes de arquivar, e o bug que vale a pena conhecer
Conversão arquivável e higienização costumam rodar juntas, porque o conteúdo que uma política de segurança quer remover se sobrepõe fortemente ao conteúdo que o PDF/A proíbe. SanitizeDocument remove JavaScript, e remover o último script também remove a árvore de nomes vazia que ela deixa para trás — uma árvore que de outro modo ainda diria a um leitor que o documento carregava scripts
Essa segunda metade foi aprendida da maneira difícil: um erro off-by-one na lista de pacotes fazia a higienização relatar a remoção de scripts enquanto não removia nenhum, então um documento que tinha sido higienizado ainda rodava seus scripts quando aberto. É um bom argumento para o princípio geral em que este artigo inteiro se apoia — verifique o resultado em vez de confiar na operação, no seu próprio pipeline tanto quanto na biblioteca
Para o trabalho arquivável ao redor, veja os guias de preflight de PDF/A e PDF/UA, redação real e remoção de conteúdo, e esquemas de extensão XMP do PDF/A-3 para Factur-X, que cobre o lado dos metadados quando o documento arquivado também carrega dados estruturados de fatura
O PDFlibPas é uma biblioteca PDF nativa em Pascal para Delphi, C++Builder e Lazarus, de modo que conversão, reparo e validação acontecem dentro do seu próprio processo sem nenhuma ferramenta externa na cadeia — veja a página do produto PDFlibPas para as partes e plataformas de PDF/A suportadas