Esta versão localizada trata de Build a PDF Intake Review Workbench in Delphi with PDFium Component usando o artigo em inglês atualizado como referência técnica para equipes Delphi, PDF e software documental
A página transforma a base atualizada em pontos de controle práticos para projeto, implementação e validação
Conteúdo sincronizado a partir da base em inglês
O artigo base foi ampliado com contexto prático, decisões técnicas e exemplos concretos, então esta página deve ser lida como guia de trabalho, não como resumo curto
Pontos importantes da versão atualizada:
- Use primeiro arquivos de entrada pequenos e reproduzíveis
- Mantenha intactos nomes de produto, API, arquivos e valores literais
- Salve a saída do validador e as versões junto com o arquivo de teste gerado
Decisões práticas de implementação
Comece pelo tipo de arquivo, pelo resultado esperado e pelo estado de erro que o usuário precisa ver. Depois conecte cada chamada API a um resultado verificável para que validação, logs e suporte possam reproduzir o caso do cliente
- Use primeiro arquivos de entrada pequenos e reproduzíveis
- Mantenha intactos nomes de produto, API, arquivos e valores literais
- Salve a saída do validador e as versões junto com o arquivo de teste gerado
Código e pontos API
Os exemplos de código são preservados sem alteração para comparação direta com projetos Delphi, C++Builder e 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;Verificação antes da publicação
Revise o arquivo de saída com as mesmas ferramentas que o cliente ou o arquivo documental usará. Registre versão do componente, dados de teste, versão do validador e resultado observado