PDF/E-1 es el perfil de archivo para documentos de ingeniería, y PDFlibPas lo implementa como un modo de autor que activa con SetPDFEMode más un preflight acotado que lee los streams de contenido operador a operador. El perfil no es un PDF/A con otra etiqueta: tiene su propio namespace de identificación, su propio requisito de metadatos de ciclo de vida, y una regla que hace la validación de contenido más estricta que la de cualquier perfil de archivo que se haya encontrado
Los entregables de ingeniería son la razón de ser del perfil. Un juego de planos que tiene que ser legible y demostrablemente inalterado dentro de veinte años, con un historial de revisiones que sobreviva, y con color que signifique lo mismo en el plotter del edificio de al lado. Esos requisitos producen una especificación cuyas exigencias están mayormente fuera del contenido de página, en los metadatos y la gestión del color, que es justo donde un generador de PDF genérico se equivoca
Identificación propia, no una variación del PDF/A
Lo primero que hay que acertar es que la identificación PDF/E-1 no se puede producir adaptando el patrón de PDF/A o PDF/X. Usa un namespace XMP distinto, http://www.aim.org/pdfe/ns/id/, y el valor de versión tiene que aparecer en dos sitios: como entrada de información del documento y como propiedad XMP cualificada por namespace. Emitir solo la propiedad XMP, o solo la entrada de información, produce un fichero que lleva la intención y falla la validación
El output intent tiene una forma igual de específica. PDF/E-1 exige un perfil ICC incrustado con el identificador de subtipo ISO_PDFE1, y el perfil debe tener un recuento de componentes que coincida con la familia de color de dispositivo que el documento realmente usa. Esa última cláusula es donde las implementaciones fallan silenciosamente, porque significa que el intent no se puede elegir de antemano y luego ignorar
¿Por qué el color de dispositivo necesita un barrido de todo el documento?
Porque los espacios de color se esconden en diccionarios de recursos a los que un escaneo a nivel de página nunca llega. PDF/E-1 trata DeviceRGB y DeviceCMYK como familias mutuamente excluyentes para un documento, así que validar el perfil significa conocer cada espacio de color de dispositivo que cualquier cosa del archivo use. Un form XObject tiene sus propios recursos. Un pattern también, y una imagen también. Un tiling pattern dentro de un form XObject dentro de una página está tres niveles hacia abajo, y un validador que solo comprueba los recursos de página de nivel superior aprobará un documento que usa ambas familias
El barrido registra por tanto los espacios de color mientras recorre páginas, forms, imágenes y patterns como un único recorrido, y solo entonces decide si el documento es coherente y si el output intent coincide. El mismo razonamiento gobierna en general la arquitectura del preflight: un recorrido parcial produce aprobaciones falsas, y una aprobación falsa en una comprobación de conformidad es peor que ninguna comprobación, porque queda registrada como evidencia
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');
// El modo de autor mantiene los metadatos de ciclo de vida sincronizados
// en cada guardado; pregunte antes si el documento pasaría su compuerta
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;
Los metadatos de ciclo de vida son una obligación en cada guardado
PDF/E-1 pide más que un identificador de documento. El conjunto mínimo incluye el identificador de documento de gestión de medios, un identificador de versión, una clase de rendition, hora de creación, hora de modificación, hora de metadatos y un título. Es un vocabulario de seguimiento de revisiones, y existe porque se espera que un entregable de ingeniería se reemita en lugar de escribirse una vez
La consecuencia para una implementación es que estos campos no se pueden fijar en la creación del documento. Si la hora de modificación se escribe al activar el modo y el documento se edita después, la instantánea XMP y el estado real del documento se han separado, y un validador que los compara informa de una inconsistencia que nadie pretendió. El modo de autor sincroniza por tanto los campos inmediatamente antes de cada guardado, de modo que los metadatos describen los bytes a punto de escribirse y no los que existían cuando se activó el modo
Es un principio general para los metadatos de conformidad y merece enunciarse por separado del PDF/E: los metadatos derivados pertenecen a la ruta de guardado, no a la ruta de edición. Cualquier campo calculado a partir del estado del documento tiene que recalcularse en el momento en que el estado se congela, o es una caché sin invalidación
La regla que hace estricta la validación de contenido
PDF/E-1 no permite que los operadores de sección de compatibilidad absorban contenido desconocido. En PDF ordinario, BX y EX acotan una región en la que un consumidor debe ignorar los operadores que no reconoce, que es la escotilla de escape que permite a un productor emitir construcciones más nuevas sin romper lectores antiguos. Bajo PDF/E-1 esa escotilla está cerrada, así que cualquier operador que el preflight no reconozca se informa incondicionalmente, esté o no dentro de una sección de compatibilidad
El efecto sobre un validador es significativo. No puede saltarse las regiones que no entiende, lo que significa que el parser de operandos tiene que analizar de verdad cada operador de cada stream de contenido. Ahí es donde entran los límites. El recorrido se acota a 128 niveles de anidamiento, un millón de objetos y 64 MiB de contenido, y esos límites no son ajuste de rendimiento. Un fichero hostil o simplemente roto puede presentar un grafo de objetos con ciclos o una profundidad de anidamiento que convierta un validador recursivo en un stack overflow, y los límites son lo que impide que una pasada de validación se convierta en un vector de denegación de servicio. La misma postura defensiva se describe en el análisis seguro de PDFs no confiables
// Validación independiente de un fichero que usted no produjo, sin
// cargarlo en una instancia 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;
Qué repara la compuerta de guardado y qué rechaza
La compuerta divide su trabajo en dos etapas, y esa división es por sí misma una idea de diseño aprovechable. Primero normaliza lo que es reparable con seguridad: los flags de impresión de anotaciones, los flags de no zoom y no rotación de las anotaciones de texto, y el flag de generación de apariencia del diccionario del formulario. Son ajustes con un único valor correcto bajo el perfil y sin contenido informativo, así que arreglarlos en silencio es lo correcto y rechazar por ellos sería pedantería
Luego comprueba las restricciones que no se pueden reparar sin cambiar lo que el documento significa: versión, identificación, cifrado, output intent, coherencia de color de dispositivo y presencia de contenido de formulario dinámico. Un documento que falle cualquiera de ellas se rechaza, porque inventar un output intent o elegir una familia de color en nombre del autor produciría un fichero que pasa la validación y tergiversa el contenido
Leer los diagnósticos mediante GetPDFEDiagnostics antes de guardar convierte ese rechazo en una lista accionable en lugar de una operación fallida. En un pipeline por lotes, llámelo en cada documento, registre los bloqueos por fichero y envíe los fallos a una cola que un humano revisa. Es mucho más útil que un guardado que lanza una excepción, porque los bloqueos suelen agruparse: cuarenta documentos fallando por el mismo output intent ausente son un arreglo, no cuarenta
Elegir entre los perfiles de archivo
PDF/E-1 es el objetivo correcto cuando el entregable es documentación de ingeniería con un ciclo de vida de revisiones, y en concreto cuando la coherencia de color de dispositivo importa porque la salida va a plotters e impresoras de gran formato. PDF/A es el objetivo correcto cuando la meta es la legibilidad a largo plazo de documentos en general, y es el perfil con el soporte de validadores más amplio. Ambos no son intercambiables, y un documento puede cumplir uno y fallar el otro
Si está eligiendo, parta de quién valida el fichero en el otro extremo. Las herramientas de validación PDF/A están por todas partes, y el preflight correspondiente en PDFlibPas se describe en el preflight PDF/A y PDF/UA. La validación PDF/E es más especializada y suele ser un requisito contractual más que un valor por defecto. Cuando un archivo existente tiene que subirse a un perfil para el que nunca se escribió, la ruta de reparación de metadatos de la conversión a PDF/A con reparación de metadatos es el patrón a seguir, y la misma forma aplica aquí: identificar, reparar lo seguro, rechazar el resto con una lista
El modo de autor, el preflight de contenido acotado y la comprobación de conformidad independiente se envían todos con la biblioteca PDF Delphi PDFlibPas, de modo que un documento puede producirse bajo el perfil y verificarse después de forma independiente mediante una ruta de código separada, que es la única disposición digna de confianza para una declaración de conformidad