O PDF/E-1 é o perfil de arquivo para documentos de engenharia, e o PDFlibPas implementa-o como um modo de autoria que ativa com SetPDFEMode mais um preflight limitado que lê os content streams operador a operador. O perfil não é um PDF/A com outro rótulo: tem o seu próprio namespace de identificação, o seu próprio requisito de metadados de ciclo de vida, e uma regra que torna a validação de conteúdo mais estrita do que qualquer perfil de arquivo que já encontrou
Os entregáveis de engenharia são a razão de ser do perfil. Um conjunto de desenhos que tem de continuar legível e comprovadamente inalterado daqui a vinte anos, com um histórico de revisões que sobrevive, e com cor que significa o mesmo no plotter do outro edifício. Esses requisitos produzem uma especificação cujas exigências estão maioritariamente fora do conteúdo da página, nos metadados e na gestão de cor, que é precisamente onde um escritor de PDF genérico as erra
Identificação própria, não uma variação do PDF/A
A primeira coisa a acertar é que a identificação PDF/E-1 não pode ser produzida adaptando o padrão do PDF/A ou do PDF/X. Usa um namespace XMP distinto, http://www.aim.org/pdfe/ns/id/, e o valor da versão tem de aparecer em dois sítios: como entrada de informação do documento e como propriedade XMP qualificada pelo namespace. Emitir só a propriedade XMP, ou só a entrada de informação, produz um ficheiro que carrega a intenção e falha a validação
O output intent tem uma forma igualmente específica. O PDF/E-1 exige um perfil ICC incorporado com o identificador de subtipo ISO_PDFE1, e o perfil tem de ter uma contagem de componentes que case com a família de cor de dispositivo que o documento realmente usa. Essa última cláusula é onde as implementações falham discretamente, porque significa que o intent não pode ser escolhido à partida e depois ignorado
Porque é que a cor de dispositivo precisa de uma varredura do documento inteiro?
Porque os espaços de cor escondem-se em dicionários de recursos que uma varredura ao nível da página nunca alcança. O PDF/E-1 trata DeviceRGB e DeviceCMYK como famílias mutuamente exclusivas num documento, por isso validar o perfil significa conhecer todos os espaços de cor de dispositivo que qualquer coisa no ficheiro usa. Um form XObject tem os seus próprios recursos. Um padrão também, e uma imagem também. Um tiling pattern dentro de um form XObject dentro de uma página está três níveis abaixo, e um validador que só verifica os recursos da página de topo passa um documento que usa as duas famílias
A varredura por isso regista os espaços de cor enquanto percorre páginas, forms, imagens e padrões como uma única travessia, e só então decide se o documento é coerente e se o output intent casa. O mesmo raciocínio orienta a arquitetura do preflight em geral: travessias parciais produzem falsas aprovações, e uma falsa aprovação numa verificação de conformidade é pior do que nenhuma verificação, porque fica registada como evidência
var
Lib: TPDFlib;
Diag: WideString;
begin
Lib := TPDFlib.Create(nil);
try
Lib.LoadFromFile('assembly-drawings.pdf');
if Lib.SetPDFEMode(1) = 0 then
raise Exception.Create('PDF/E author mode was refused');
// O modo de autoria mantém os metadados de ciclo de vida em passo a cada gravação.
// Pergunte antes de gravar se o documento passaria no seu próprio portão
if not Lib.PDFEReadyForSave then
begin
Diag := Lib.GetPDFEDiagnostics;
Writeln('PDF/E blockers: ', Diag);
Exit;
end;
Lib.SaveToFile('assembly-drawings-pdfe.pdf');
finally
Lib.Free;
end;
end;
Os metadados de ciclo de vida são uma obrigação a cada gravação
O PDF/E-1 pede mais do que um identificador de documento. O conjunto mínimo inclui o identificador de documento de gestão de media, um identificador de versão, uma classe de rendição, hora de criação, hora de modificação, hora dos metadados e um título. É um vocabulário de rastreio de revisões, e existe porque se espera que um entregável de engenharia seja reemitido e não escrito uma única vez
A consequência para uma implementação é que estes campos não podem ser definidos na criação do documento. Se a hora de modificação é escrita quando ativa o modo e o documento é editado depois, o snapshot XMP e o estado real do documento divergem, e um validador que os compara reporta uma inconsistência que ninguém pretendia. O modo de autoria por isso sincroniza os campos imediatamente antes de cada gravação, para os metadados descreverem os bytes prestes a ser escritos e não os bytes que existiam quando o modo foi ativado
Este é um princípio geral para metadados de conformidade e vale a pena enunciá-lo separadamente do PDF/E: metadados derivados pertencem ao caminho de gravação, não ao caminho de edição. Qualquer campo calculado a partir do estado do documento tem de ser recalculado no momento em que o estado é congelado, ou é uma cache sem invalidação
A regra que torna a validação de conteúdo estrita
O PDF/E-1 não permite que os operadores da secção de compatibilidade absorvam conteúdo desconhecido. Num PDF ordinário, BX e EX delimitam uma região em que um consumidor deve ignorar operadores que não reconhece, que é a válvula de escape que permite a um produtor emitir construções mais recentes sem partir leitores antigos. Sob o PDF/E-1 essa válvula está fechada, por isso qualquer operador que o preflight não reconheça é reportado incondicionalmente, esteja ou não dentro de uma secção de compatibilidade
O efeito num validador é significativo. Não pode saltar regiões que não compreende, o que significa que o parser de operandos tem de analisar realmente todos os operadores em todos os content streams. É aqui que entram os limites. A travessia é limitada a 128 níveis de aninhamento, um milhão de objetos e 64 MiB de conteúdo, e esses limites não são afinação de desempenho. Um ficheiro hostil ou simplesmente avariado pode apresentar um grafo de objetos com ciclos ou uma profundidade de aninhamento que transforma um validador recursivo num stack overflow, e os limites são o que impede uma passagem de validação de se tornar um vetor de denial-of-service. A mesma postura defensiva está descrita em analisar PDFs não fidedignos com segurança
// Validação autónoma de um ficheiro que não produziu, sem o carregar
// numa instância de documento
var
Issues: TStringList;
Stream: TFileStream;
I: Integer;
begin
Issues := TStringList.Create;
Stream := TFileStream.Create('incoming.pdf', fmOpenRead or fmShareDenyWrite);
try
if CheckCompliancePDFE(Stream, '', 0, Issues) = 0 then
for I := 0 to Issues.Count - 1 do
Writeln('PDF/E: ', Issues[I]);
finally
Stream.Free;
Issues.Free;
end;
end;
O que o portão de gravação repara e o que recusa
O portão divide o seu trabalho em duas fases, e a divisão é por si só uma ideia de design aproveitável. Primeiro normaliza o que é seguramente reparável: as flags de impressão das anotações, as flags no-zoom e no-rotate das anotações de texto, e a flag de geração de aparência no dicionário do formulário. São definições com um único valor correto sob o perfil e sem conteúdo informativo, por isso corrigi-las silenciosamente está certo e recusar por causa delas seria pedantismo
Depois verifica as restrições que não podem ser reparadas sem alterar o que o documento significa: versão, identificação, encriptação, output intent, coerência de cor de dispositivo e a presença de conteúdo de formulário dinâmico. Um documento que falhe qualquer uma dessas é recusado, porque inventar um output intent ou escolher uma família de cores em nome do autor produziria um ficheiro que passa a validação e deturpa o conteúdo
Ler os diagnósticos através de GetPDFEDiagnostics antes de gravar transforma essa recusa numa lista acionável em vez de uma operação falhada. Num pipeline de lote, chame-o em todos os documentos, registe os bloqueadores por ficheiro, e encaminhe as falhas para uma fila que um humano olha. Isso é muito mais útil do que uma gravação que levanta exceção, porque os bloqueadores costumam agrupar-se: quarenta documentos a falhar pelo mesmo output intent em falta são uma correção, não quarenta
Escolher entre os perfis de arquivo
O PDF/E-1 é o alvo certo quando o entregável é documentação de engenharia com um ciclo de vida de revisões, e especificamente quando a coerência de cor de dispositivo importa porque o output vai para plotters e impressoras de grande formato. O PDF/A é o alvo certo quando o objetivo é a legibilidade a longo prazo de documentos em geral, e é o perfil com o apoio de validadores mais alargado. Os dois não são intercambiáveis, e um documento pode satisfazer um e falhar o outro
Se está a escolher, comece por quem valida o ficheiro no destino final. As ferramentas de validação PDF/A estão por todo o lado, e o preflight correspondente no PDFlibPas está descrito em preflight PDF/A e PDF/UA. A validação PDF/E é mais especializada e costuma ser um requisito contratual e não uma predefinição. Quando um arquivo existente tem de ser elevado a um perfil para o qual nunca foi escrito, o caminho de reparação de metadados em converter para PDF/A com reparação de metadados é o padrão a seguir, e a mesma forma aplica-se aqui: identificar, reparar o que é seguro, recusar o resto com uma lista
O modo de autoria, o preflight de conteúdo limitado e a verificação de conformidade autónoma são todos distribuídos com a biblioteca PDF Delphi PDFlibPas, por isso um documento pode ser produzido sob o perfil e verificado de forma independente depois através de um caminho de código separado, que é o único arranjo em que vale a pena confiar para uma declaração de conformidade