El PDFium Component para Delphi valida documentos PDF/X listos para imprimir mediante TPdf.ValidatePdfX, que implementa la verificación de la norma ISO 15930 en dos capas: ocho comprobaciones de contenido a nivel de bytes (prohibición de compresión LZW, JavaScript, campos de formulario, referencias OPI, TrimBox ausente, clave Trapped no establecida, entre otras) más una pasada por el modelo de objetos de PDFium que utiliza FPDFFont_GetIsEmbedded para verificar la incrustación de fuentes en cada objeto de texto de cada página. El resultado es un registro TPdfXValidationResult que indica el nivel de conformidad detectado y detalla cada infracción como un enumerado con tipo, de modo que su aplicación Delphi pueda informar a un cliente exactamente por qué un archivo será rechazado en la imprenta antes de iniciar el proceso de producción
Si alguna vez ha enviado un trabajo a una imprenta comercial y lo ha recibido de vuelta con un rechazo de una sola línea ("sin TrimBox", "fuentes no incrustadas", "Trapped no establecido"), sabrá lo costoso que es enterarse tarde. PDF/X es el equivalente en preimpresión de PDF/A: mientras que PDF/A para archivado garantiza que un documento se renderice de manera idéntica dentro de décadas, PDF/X garantiza que un documento se separe, filme y recorte de forma idéntica en el procesador de imágenes de trama (RIP) de otra persona mañana por la mañana. Ambos estándares comparten mecanismos (identificación XMP, OutputIntents, perfiles ICC integrados) pero responder a preguntas diferentes, razón por la cual el componente incluye validadores independientes para cada uno; la parte de PDF/A se cubre en validación de verificación previa de PDF/A con el PDFium Component
¿Qué exige realmente la norma ISO 15930 de un PDF listo para imprimir?
La norma ISO 15930 existe para hacer posible el intercambio a ciegas: un diseñador entrega un archivo a una imprenta con la que nunca ha hablado, y esta puede generar el resultado correcto sin necesidad de llamadas telefónicas, correos sobre fuentes faltantes ni imágenes enlazadas que se hayan quedado en la computadora del diseñador. Cada regla de la norma sirve a ese propósito. Las fuentes deben estar incrustadas porque no se puede asumir que el RIP receptor las posea. Las referencias externas están prohibidas porque el archivo debe ser completo en sí mismo. Las funciones interactivas están prohibidas porque la tinta no tiene un controlador de clics
El PDFium Component reconoce tres familias de conformidad y las reporta a través del enumerado TPdfXConformance en el resultado de la validación: pxc1a para PDF/X-1a:2001 (ISO 15930-1, la base estricta de CMYK más color plano sobre PDF 1.3/1.4), pxc3 para PDF/X-3:2002 (ISO 15930-3, que admite color RGB, Lab y gestionado por ICC) y pxc4 para PDF/X-4:2010 (ISO 15930-7, que finalmente permite transparencia activa y capas sobre una base de PDF 1.6). Un archivo que no contenga ninguna identificación de PDF/X se reporta como pxcNone, lo cual es en sí mismo una respuesta útil: el documento nunca declaró estar listo para impresión, y todo lo demás que reporta el validador explica lo que se necesitaría para lograrlo
Las prohibiciones tienen sentido una vez que se piensa como un fabricante de RIP. /LZWDecode está prohibido en cada variante de PDF/X para que un consumidor conforme nunca dependa de un filtro con un historial de compatibilidad y licencias complejo; Flate realiza el mismo trabajo sin esos inconvenientes. JavaScript, los campos de AcroForm y los diccionarios de acciones adicionales /AA están prohibidos porque un archivo de impresión debe ser una descripción fija de marcas en el papel; cualquier cosa que pueda alterar la apariencia al abrir el archivo rompe la garantía de que lo que se aprobó es lo que se imprime. Los marcadores de posición OPI (Open Prepress Interface) están prohibidos porque son, por diseño, referencias a imágenes de alta resolución almacenadas en otro lugar, y "somewhere else" es exactamente lo que prohíbe el intercambio a ciegas
¿Por qué las imprentas rechazan los PDFs sin un TrimBox?
El TrimBox es la página terminada: el rectángulo que queda después de los cortes de la guillotina. El MediaBox, que tienen todas las páginas PDF, es simplemente la hoja: incluye sangrado (bleed), marcas de corte, marcas de registro y barras de color. El software de imposición posiciona las páginas en una hoja de imprenta mediante sus TrimBoxes; sin uno, el operador debe adivinar dónde termina realmente su tarjeta de presentación, y una estimación incorrecta recorta su sangrado o deja una franja blanca en un borde. Por eso la norma ISO 15930 exige un TrimBox (or an ArtBox) en cada página, y por lo que ValidatePdfX genera pvxiMissingTrimBox cuando no se encuentra la clave /TrimBox en ninguna página del documento
La clave /Trapped responde a una pregunta de producción diferente. El reventado (trapping) es la técnica de preimpresión que consiste en superponer ligeramente los colores adyacentes para que los pequeños desajustes de registro de la prensa no dejen espacios en blanco entre ellos. La imprenta necesita saber si ese trabajo ya se ha realizado: aplicar trapping a un archivo que ya lo tiene duplica las superposiciones, y omitirlo en un archivo sin trapping arriesga la aparición de espacios visibles. Por lo tanto, PDF/X exige que el diccionario Info declare explícitamente /Trapped /True o /Trapped /False; una clave faltante o /Unknown obliga a un operador humano a inspeccionar el archivo, que es precisamente la conversación que el intercambio a ciegas pretendía evitar. El componente marca esto como pvxiTrappedNotSet
Ejecutar la validación en dos capas con TPdf.ValidatePdfX
TPdf.ValidatePdfX no toma argumentos y devuelve un registro TPdfXValidationResult con tres miembros: Conformance (la variante de PDF/X detectada), Issues (un conjunto en Pascal de valores TPdfXValidationIssue) y un asistente IsCompliant. Internamente, serializa el documento cargado en un flujo de memoria, ejecuta el inspector a nivel de bytes sobre él y luego recorre el modelo de objetos de PDFium para la comprobación de incrustación por fuente. Un filtro de verificación previo mínimo se ve así:
uses PDFium, FPdfPdfx;
procedure CheckPrintReadiness(const FileName: string);
var
Pdf: TPdf;
Res: TPdfXValidationResult;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Active := True;
Res := Pdf.ValidatePdfX;
Writeln('Detected conformance: ',
Ord(Res.Conformance)); // pxc1a, pxc3, pxc4, pxcNone...
if Res.IsCompliant then
Writeln('PDF/X checks passed')
else
begin
if pvxiMissingTrimBox in Res.Issues then
Writeln('REJECT: no /TrimBox on the pages');
if pvxiTrappedNotSet in Res.Issues then
Writeln('REJECT: /Trapped missing or /Unknown');
if pvxiPdfiumFontNotEmbedded in Res.Issues then
Writeln('REJECT: a page uses a non-embedded font');
if pvxiLzwForbidden in Res.Issues then
Writeln('REJECT: LZWDecode filter present');
end;
finally
Pdf.Free;
end;
end;
Debido a que Issues es un conjunto estándar de Pascal, usted puede dividirlo según las necesidades de su flujo de trabajo: tratar los problemas estructurales como rechazos definitivos, tratar pvxiMissingTitle (una recomendación en el estándar, no una obligación) como una advertencia y registrar el resto. El mismo tipo de registro también alimenta al generador de reportes del componente, de modo que si prefiere emitir un documento legible por humanos en lugar de realizar bifurcaciones basadas en enumerados, el patrón de crear un CLI de reporte de verificación previa por lotes con el PDFium Component se aplica a PDF/X sin cambios
Lo que la capa a nivel de bytes detecta — y lo que pasa por alto
La capa a nivel de bytes es un escaneo de tokens sobre los bytes estructurales del documento con los cuerpos de flujo vacíos, por lo que un JPEG que contenga la secuencia de bytes /JavaScript no puede activar un falso positivo. Además de las comprobaciones de marcadores (XMP pdfxid:GTS_PDFXVersion, OutputIntent con un perfil ICC integrado, /ID final, la prohibición de cifrado), el análisis de contenido añade ocho comprobaciones, cada una con su propio valor de enumerado:
pvxiLzwForbidden— aparece un filtro/LZWDecodeen cualquier parte del archivo (prohibido en todas las variantes de PDF/X)pvxiJavaScriptForbidden— está presente una acción/JavaScripto un árbol de nombrespvxiFormFieldsForbidden— existe un diccionario/AcroFormo una entrada/XFApvxiAdditionalActions— está presente un diccionario de acciones adicionales/AApvxiEmbeddedFilesForbidden— está presente la clave/EmbeddedFileso una anotación/FileAttachmentpvxiOpiForbidden— una entrada/OPIo/Alternateshace referencia a contenido de imagen reemplazablepvxiMissingTrimBox— no se encontró/TrimBoxen ninguna páginapvxiTrappedNotSet—/Trappedestá ausente o establecido en/Unknown
El escaneo de bytes es rápido y no necesita un motor de renderizado, pero tiene un punto ciego inherente con las fuentes: a ese nivel, el inspector solo puede aplicar una heurística aproximada (marca un documento cuando no encuentra ningún programa de fuentes incrustado). Un archivo con nueve fuentes incrustadas y una fuente del sistema añadida parece correcto en un escaneo de bytes. Esa brecha específica es la razón por la que existe la segunda capa
Incrustación por fuente a través del modelo de objetos de PDFium
La capa de modelo de objetos de PDFium Component responde a la cuestión de las fuentes con precisión. Después de la pasada a nivel de bytes, TPdf.ValidatePdfX recorre cada página, solicita la lista de objetos a FPDFPage_CountObjects, y para cada objeto de texto resuelve el identificador de fuente mediante FPDFTextObj_GetFont y consulta FPDFFont_GetIsEmbedded. Una sola fuente no incrustada en cualquier parte del documento añade pvxiPdfiumFontNotEmbedded al conjunto de problemas. El recorrido se interrumpe en dos niveles (deja de escanear objetos en una página y deja de cargar más páginas) en el momento en que se confirma el problema, por lo que en un catálogo de 300 páginas con infracciones, el veredicto suele llegar tras la primera página
Hay dos detalles de límite que vale la pena conocer. Primero, esta capa requiere que la biblioteca PDFium esté cargada y necesita compilaciones que exporten FPDFFont_GetIsEmbedded; cuando la función de exportación está ausente, la comprobación se omite en lugar de fallar, por lo que una DLL más antigua nunca genera rechazos falsos. Segundo, la comprobación responde a "incrustada o no" y nada más (no distingue la incrustación completa del subconjunto de fuentes, ni inspecciona la cobertura de glifos). Cuando un archivo falla y necesita saber qué fuente en qué página lo causó, las técnicas de enumeración de analizar propiedades de fuentes PDF con PDFium en Delphi continúan exactamente donde se detiene el resultado booleano del validador
Validar flujos de datos sin cargar un documento — ni la DLL
El inspector a nivel de bytes también se expone como una función independiente, ValidatePdfXCompliance(Source: TStream) en la unidad FPdfPdfx, y es Object Pascal puro sin dependencia de la DLL de PDFium. Eso permite implementarlo en lugares donde un motor de renderizado no es deseable: un filtro de subida ligero en un servidor web, una tarea de CI que evalúe el diseño generado o un servicio de Lazarus en una plataforma donde prefiera no distribuir binarios nativos. Suminístrele cualquier flujo de datos con soporte de búsqueda (seekable):
uses Classes, FPdfPdfx;
function QuickPdfXGate(const FileName: string): Boolean;
var
Fs: TFileStream;
Res: TPdfXValidationResult;
begin
Fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Res := ValidatePdfXCompliance(Fs);
Result := Res.IsCompliant and (Res.Conformance <> pxcNone);
finally
Fs.Free;
end;
end;
La compensación es clara: la ruta independiente ejecuta las comprobaciones de marcadores y las ocho comprobaciones de contenido, pero no la capa de PDFium por fuente, por lo que su veredicto de fuentes recurre a la heurística aproximada. Una arquitectura sensata utiliza ValidatePdfXCompliance como una primera validación económica y reserva la llamada completa TPdf.ValidatePdfX para los archivos que la superen
Dónde termina este validador y comienza una verificación previa completa
La honestidad es importante en las herramientas de verificación previa, por lo que aquí definimos el límite. ValidatePdfX verifica marcadores de identificación, prohibiciones estructurales, claves de geometría de página, la declaración de Trapped e incrustación de fuentes hasta llegar a objetos de texto individuales. No mide la cobertura de tinta total, no valida que cada espacio de color sea permitido para la variante declarada (la regla de solo CMYK de X-1a, por ejemplo), no comprueba la resolución de la imagen frente a la lineatura de trama, ni evalúa el comportamiento de sobreimpresión y acoplado de transparencias; estas tareas requieren un motor de verificación previa con gestión de color, y la propia documentación de la unidad aconseja combinarlo con uno para la certificación final. Lo que la verificación en dos capas le proporciona es el 80% de los rechazos que son estructurales y detectables de forma temprana, capturados en milisegundos dentro de su propio código Delphi en lugar de en el correo electrónico de rechazo de la imprenta de mañana
Ambas capas de validación, las API de inyección de marcadores PDF/X para generar salidas conformes, y los validadores de PDF/A, PDF/UA, PDF/E y PDF/VT que comparten la misma arquitectura, se distribuyen en el PDFium Component para Delphi y C++Builder: un solo componente, desde el renderizado hasta el control de preimpresión