În fluxurile de lucru pentru imprimare enterprise, arhivare și conformitate a documentelor, un fișier PDF nu poate fi pur și simplu „randat”. Acesta trebuie să fie auditat. Un PDF ar putea conține grupuri de transparență neaplatizate care blochează procesoarele de imagini raster (RIP) mai vechi, JavaScript încorporat care prezintă un risc de securitate sau imagini cu rezoluție redusă care vor arăta groaznic la imprimarea la 300 DPI.
Acest proces de inspectare a unui PDF înainte ca acesta să intre într-un flux de lucru de producție este cunoscut sub numele de Preflighting. În acest articol, vom explora cum să construim un instrument automatizat de preflight și de auditare a riscurilor în Delphi, valorificând capacitățile de parsare de nivel scăzut ale PDFium.
Verificări preflight cheie
Un audit standard al riscurilor verifică de obicei următoarele elemente dintr-un PDF:
- Elemente interactive: Acțiuni JavaScript, acțiuni Launch (executarea de programe externe) și AcroForms.
- Valori ale resurselor: Prezența imaginilor de rezoluție redusă sau a fonturilor încorporate lipsă.
- Stare de securitate: Criptarea documentului, cerințele pentru parole și permisiunile de acces (de exemplu, imprimarea dezactivată).
- Standarde ale documentului: Validarea markerilor de conformitate PDF/A sau PDF/X în metadatele documentului.
Extragerea metadatelor și a adnotărilor PDF cu PDFium
PDFium oferă un API C robust pe care Delphi îl poate consuma. Pentru a efectua un audit preflight, nu randăm pur și simplu pagina; parcurgem arborele de obiecte PDF. Să vedem cum să iterăm prin paginile documentului și să inspectăm adnotările pentru a găsi acțiuni JavaScript potențial riscante.
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;
Verificarea rezoluției imaginii
Un alt pas critic de preflight pentru fluxurile de lucru de imprimare este asigurarea faptului că nicio imagine nu scade sub un prag DPI specific. PDFium vă permite să extrageți obiecte imagine direct din fluxul paginii. Împărțind dimensiunile în pixeli ale imaginii extrase la dimensiunile fizice (în puncte) pe care le ocupă pe pagina PDF, puteți calcula DPI-ul efectiv.
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;
Integrarea cu PDFium Component
Construirea unui motor de preflight robust de la zero folosind API-ul C PDFium brut necesită un cod repetitiv semnificativ și o cunoaștere profundă a specificației PDF. Utilizarea unui wrapper simplifică enorm acest lucru. Cu un wrapper Delphi de nivel înalt, puteți transforma iterațiile complexe de pointeri C într-un cod curat orientat pe obiecte.
Automatizând faza de preflight, preveniți ca fișierele defecte să vă blocheze pipeline-ul de producție, economisind atât timp, cât și resurse de randare.
Notă: Capacitățile avansate de parsare și preflight PDF sunt pe deplin suportate de PDFium Component.