PDF/E-1 es el perfil de archivo para documentos de ingeniería, y PDFlibPas lo implementa como un modo author que se activa con SetPDFEMode más un preflight acotado que lee los content streams operador por operador. El perfil no es PDF/A con otra etiqueta: tiene su propio namespace de identificación, su propio requisito de metadata de lifecycle, y una regla que hace la validación de contenido más estricta que la de cualquier perfil de archivo que haya visto
Los entregables de ingeniería son la razón de ser del perfil. Un set 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 la plotter del otro edificio. Esos requisitos producen una especificación cuyas exigencias viven mayormente fuera del contenido de la página, en metadata y manejo de color, que es exactamente donde un escritor de PDF genérico se equivoca
Identificación propia, no una variación de PDF/A
Lo primero que hay que tener claro es que la identificación PDF/E-1 no se produce adaptando el patrón de PDF/A o PDF/X. Usa un namespace XMP propio, http://www.aim.org/pdfe/ns/id/, y el valor de versión tiene que aparecer en dos lugares: como entrada de información del documento y como propiedad XMP calificada por el namespace. Emitir solo la propiedad XMP, o solo la entrada de información, produce un archivo que carga 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 embebido con el identificador de subtipo ISO_PDFE1, y el perfil debe tener un conteo 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 en silencio, porque significa que el intent no se puede elegir por adelantado 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 que un escaneo a nivel de página nunca alcanza. PDF/E-1 trata DeviceRGB y DeviceCMYK como familias mutuamente excluyentes para un documento, así que validar el perfil implica conocer cada espacio de color de dispositivo que cualquier cosa en el archivo use. Un form XObject tiene sus propios recursos. Un pattern también, y una imagen igual. Un tiling pattern dentro de un form XObject dentro de una página está a tres niveles de profundidad, y un validador que solo revisa los recursos de página de primer nivel le va a dar un pase a un documento que usa ambas familias
Por eso el barrido registra los espacios de color mientras recorre páginas, forms, imágenes y patterns como un solo traversal, y solo entonces decide si el documento es coherente y si el output intent coincide. El mismo razonamiento mueve la arquitectura del preflight en general: un traversal parcial produce falsos pases, y un falso pase en una comprobación de conformidad es peor que ninguna comprobación, porque queda registrado 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 author mantiene la metadata de lifecycle al día en cada save.
// Pregunte antes de guardar si el documento pasaría su propia 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;
La metadata de lifecycle es una obligación de cada save
PDF/E-1 pide más que un identificador de documento. El set mínimo incluye el identificador de documento de media management, un identificador de versión, una clase de rendition, hora de creación, hora de modificación, hora de metadata y un título. Ese 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 sola vez
La consecuencia para una implementación es que estos campos no se pueden fijar al crear el documento. Si la hora de modificación se escribe cuando usted activa el modo y el documento se edita después, la instantánea XMP y el estado real del documento se separan, y un validador que las compara reporta una inconsistencia que nadie planeó. Por eso el modo author sincroniza los campos inmediatamente antes de cada save, de modo que la metadata describe los bytes a punto de escribirse y no los bytes que existían cuando se activó el modo
Este es un principio general para metadata de conformidad y vale la pena enunciarlo aparte de PDF/E: la metadata derivada pertenece 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 vuelve estricta la validación de contenido
PDF/E-1 no permite que los operadores de la sección de compatibilidad absorban contenido desconocido. En PDF ordinario, BX y EX delimitan una región en la que un consumidor debe ignorar los operadores que no reconoce, que es la válvula de escape que deja a un productor emitir construcciones más nuevas sin romper lectores viejos. Bajo PDF/E-1 ese escape está cerrado, así que cualquier operador que el preflight no reconozca se reporta incondicionalmente, esté o no dentro de una sección de compatibilidad
El efecto sobre un validador es considerable. No puede saltarse regiones que no entiende, lo que significa que el parser de operandos tiene que parsear de verdad cada operador de cada content stream. Ahí es donde entran los límites. El traversal 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 archivo hostil o simplemente corrupto 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 evita que una pasada de validación se vuelva un vector de denegación de servicio. La misma postura defensiva se describe en parseo seguro de PDFs no confiables
// Validación standalone de un archivo 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;
Lo que la compuerta de guardado repara y lo que rechaza
La compuerta divide su trabajo en dos etapas, y la división es de por sí una idea de diseño aprovechable. Primero normaliza lo que se puede reparar con seguridad: los flags de impresión de anotaciones, los flags de no-zoom y no-rotate 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 revisa 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 esas se rechaza, porque inventar un output intent o elegir una familia de color en nombre del autor produciría un archivo que pasa la validación y tergiversa el contenido
Leer los diagnósticos vía 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 blockers por archivo y mande las fallas a una cola que una persona revise. Eso rinde mucho más que un save que lanza una excepción, porque los blockers suelen agruparse: cuarenta documentos fallando por el mismo output intent faltante es un arreglo, no cuarenta
Elegir entre los perfiles de archivo
PDF/E-1 es el target correcto cuando el entregable es documentación de ingeniería con un ciclo de revisiones, y en particular cuando la coherencia de color de dispositivo importa porque la salida va a plotters e impresoras de gran formato. PDF/A es el target correcto cuando el objetivo es la legibilidad a largo plazo de documentos en general, y es el perfil con el soporte de validadores más amplio. Los dos no son intercambiables, y un documento puede cumplir uno y fallar el otro
Si está eligiendo, parta de quién valida el archivo en el otro extremo. Las herramientas de validación PDF/A están en todas partes, y el preflight correspondiente en PDFlibPas se describe en preflight PDF/A y PDF/UA. La validación PDF/E es más especializada y suele ser un requisito contractual en lugar de un valor predeterminado. Cuando un archivo existente tiene que subirse a un perfil para el que nunca se escribió, la ruta de reparación de metadata en conversión a PDF/A con reparación de metadata es el patrón a seguir, y aquí aplica la misma forma: identificar, reparar lo seguro, rechazar el resto con una lista
El modo author, el preflight de contenido acotado y la comprobación de conformidad standalone vienen todos con la PDFlibPas Delphi PDF library, así que un documento puede producirse bajo el perfil y verificarse después de forma independiente a través de una ruta de código separada, que es el único arreglo digno de confianza para una declaración de conformidad