I arbejdsgange for virksomhedsudskrivning, arkivering og dokumentoverholdelse kan en PDF-fil ikke bare "gengives". Den skal revideres. En PDF kan indeholde ufladgjorte gennemsigtighedsgrupper, der får ældre raster-billedprocessorer (RIP'er) til at gå ned, indlejret JavaScript, der udgør en sikkerhedsrisiko, eller lavopløselige billeder, der vil se forfærdelige ud, når de udskrives i 300 DPI.
Denne proces med at inspicere en PDF, før den går ind i en produktionsarbejdsgang, er kendt som Preflighting. I denne artikel vil vi undersøge, hvordan man bygger et automatiseret værktøj til preflight og risikorevision i Delphi ved at udnytte PDFiums parsingfunktioner på lavt niveau.
Vigtige preflight-tjek
En standard risikorevision tjekker typisk for følgende elementer i en PDF:
- Interaktive elementer: JavaScript-handlinger, Launch-handlinger (udførelse af eksterne programmer) og AcroForms.
- Ressourcemetrikker: Tilstedeværelse af lavopløselige billeder eller manglende indlejrede skrifttyper.
- Sikkerhedsstatus: Dokumentkryptering, adgangskodekrav og adgangstilladelser (f.eks. udskrivning deaktiveret).
- Dokumentstandarder: Validering af PDF/A- eller PDF/X-overholdelsesmarkører i dokumentmetadataene.
Udtrækning af PDF-metadata og annotationer med PDFium
PDFium leverer en robust C-API, som Delphi kan forbruge. For at udføre en preflight-revision gengiver vi ikke bare siden; vi gennemgår PDF-objekttræet. Lad os se på, hvordan man itererer gennem dokumentsiderne og inspicerer annotationer for at finde potentielt risikable JavaScript-handlinger.
uses
System.SysUtils, pdfium_lib;
procedure AuditPdfSecurity(const FileName: string);
var
Doc: FPDF_DOCUMENT;
PageCount, i, j: Integer;
Page: FPDF_PAGE;
AnnotCount: Integer;
Annot: FPDF_ANNOTATION;
AnnotSubType: FPDF_ANNOTATION_SUBTYPE;
Action: FPDF_ACTION;
ActionType: ULONG;
begin
FPDF_InitLibrary();
try
// Load the document without a password
Doc := FPDF_LoadDocument(PAnsiChar(AnsiString(FileName)), nil);
if Doc = nil then
raise Exception.Create('Failed to load document or password required.');
try
PageCount := FPDF_GetPageCount(Doc);
Writeln(Format('Auditing %d pages...', [PageCount]));
for i := 0 to PageCount - 1 do
begin
Page := FPDF_LoadPage(Doc, i);
if Page <> nil then
begin
AnnotCount := FPDFPage_GetAnnotCount(Page);
for j := 0 to AnnotCount - 1 do
begin
Annot := FPDFPage_GetAnnot(Page, j);
if Annot <> nil then
begin
AnnotSubType := FPDFAnnot_GetSubtype(Annot);
// Check for Link Annotations that might have malicious actions
if AnnotSubType = FPDF_ANNOT_LINK then
begin
Action := FPDFAnnot_GetLinkAction(Annot);
if Action <> nil then
begin
ActionType := FPDFAction_GetType(Action);
// 2 represents PDFACTION_URI, 3 represents PDFACTION_SOUND, 4 represents PDFACTION_MOVIE
// We specifically look out for PDFACTION_LAUNCH or PDFACTION_JAVA_SCRIPT
if (ActionType = PDFACTION_JAVA_SCRIPT) or (ActionType = PDFACTION_LAUNCH) then
begin
Writeln(Format('WARNING: Malicious action detected on page %d', [i + 1]));
end;
end;
end;
FPDFPage_CloseAnnot(Annot);
end;
end;
FPDF_ClosePage(Page);
end;
end;
finally
FPDF_CloseDocument(Doc);
end;
finally
FPDF_DestroyLibrary();
end;
end;
Tjek af billedopløsning
Et andet kritisk preflight-trin for udskrivningsarbejdsgange er at sikre, at intet billede falder under en bestemt DPI-tærskel. PDFium giver dig mulighed for at udtrække billedobjekter direkte fra sidens stream. Ved at dividere pixeldimensionerne for det udtrukne billede med de fysiske dimensioner (i punkter), det optager på PDF-siden, kan du beregne den effektive DPI.
procedure AuditPageImages(Page: FPDF_PAGE);
var
ObjCount, i: Integer;
PageObj: FPDF_PAGEOBJECT;
ImgWidth, ImgHeight: Integer;
begin
ObjCount := FPDFPage_CountObjects(Page);
for i := 0 to ObjCount - 1 do
begin
PageObj := FPDFPage_GetObject(Page, i);
if FPDFPageObj_GetType(PageObj) = FPDF_PAGEOBJ_IMAGE then
begin
FPDFImageObj_GetBitmap(PageObj); // Returns an FPDF_BITMAP you can inspect
// Retrieve metadata using FPDFImageObj_GetImageMetadata
// Calculate effective DPI based on quad coordinates
end;
end;
end;
Integration med PDFium Component
At bygge en robust preflight-motor fra bunden ved hjælp af den rå PDFium C-API kræver betydelig mængde rutinekoder og dyb viden om PDF-specifikationen. Brug af en wrapper forenkler dette enormt. Med en højniveau Delphi-wrapper kan du omdanne komplekse C-pointeriterationer til ren objektorienteret kode.
Ved at automatisere preflight-fasen forhindrer du dårlige filer i at stoppe din produktionspipeline, hvilket sparer både tid og gengivelsesressourcer.
Bemærk: Avancerede PDF-parsing- og preflight-funktioner understøttes fuldt ud af PDFium Component.