Esta versión localizada revisa Build a PDF Intake Review Workbench in Delphi with PDFium Component tomando como referencia el artículo base en inglés ya actualizado para equipos que trabajan con Delphi, PDF y software documental
La página convierte la versión base actualizada en puntos de control prácticos para diseño, implementación y validación
Contenido sincronizado desde la versión base
El artículo base se amplió con contexto práctico, decisiones técnicas y ejemplos concretos, por lo que esta página debe leerse como una guía de trabajo y no como un resumen breve
Puntos importantes de la versión actualizada:
- Trabaje primero con archivos de entrada pequeños y reproducibles
- Mantenga intactos nombres de producto, API, archivos y valores literales
- Guarde la salida del validador y las versiones junto con el archivo de prueba generado
Decisiones prácticas de implementación
Empiece por el tipo de archivo, el resultado esperado y el error que debe ver el usuario. Después vincule cada llamada API con un resultado verificable para que validación, registros y soporte puedan reproducir el caso del cliente
- Trabaje primero con archivos de entrada pequeños y reproducibles
- Mantenga intactos nombres de producto, API, archivos y valores literales
- Guarde la salida del validador y las versiones junto con el archivo de prueba generado
Código y puntos API
Los ejemplos de código se conservan sin cambios para poder compararlos directamente con proyectos Delphi, C++Builder y Lazarus/FPC
procedure InspectIncoming(const IncomingPath: string; var Rec: TIntakeRecord);
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := IncomingPath;
Pdf.FormFill := False; // no form environment, no JavaScript init
Pdf.Active := True; // failure is silent: Active simply stays False
if not Pdf.Active then
begin
Rec.OpenFailed := True; // damaged file or user-password lock
Exit; // the finally block still runs
end;
Rec.PageCount := Pdf.PageCount;
CollectIdentity(Pdf, IncomingPath, Rec);
CollectRiskSignals(Pdf, Rec);
finally
Pdf.Active := False;
Pdf.Free; // never leak the instance on a malformed file
end;
end;procedure CollectIdentity(Pdf: TPdf; const FilePath: string;
var Rec: TIntakeRecord);
begin
Rec.Title := Pdf.Title; // Info dictionary value
Rec.Author := Pdf.Author;
Rec.CreatedAt := Pdf.CreationDate; // raw PDF date string ("D:2026...")
// An empty Info title does not mean the document is untitled. The
// component does not expose the XMP packet, so probe the raw file
// bytes for the dc:title element before trusting the blank.
if (Rec.Title = '') and FileContainsText(FilePath, 'dc:title') then
Include(Rec.Flags, ifTitleInXmpOnly);
end;procedure CollectRiskSignals(Pdf: TPdf; var Rec: TIntakeRecord);
var
i, PageNo: Integer;
Ext: string;
begin
Rec.IsEncrypted := Assigned(FPDF_GetSecurityHandlerRevision) and
(FPDF_GetSecurityHandlerRevision(Pdf.Document) <> -1);
Rec.HasForms := Pdf.FormType <> ftNone;
Rec.IsXfa := Pdf.FormType = ftXfaFull;
Rec.HasJavaScript := Pdf.JavaScriptActionCount > 0;
// AnnotationCount is a per-page property; walk the pages to total
// it. Loading a page object renders nothing, so this stays cheap.
Rec.Annotations := 0;
for PageNo := 1 to Pdf.PageCount do
begin
Pdf.PageNumber := PageNo;
Inc(Rec.Annotations, Pdf.AnnotationCount);
end;
Rec.Attachments := Pdf.AttachmentCount;
for i := 0 to Rec.Attachments - 1 do
begin
Ext := LowerCase(ExtractFileExt(string(Pdf.AttachmentName[i])));
if (Ext = '.exe') or (Ext = '.js') or (Ext = '.vbs') or (Ext = '.dll') then
Include(Rec.Flags, ifDangerousAttachment);
end;
end;Comprobación antes de publicar
Revise el archivo de salida con las mismas herramientas que usará el cliente o el archivo documental. Registre versión del componente, datos de prueba, versión del validador y resultado observado