U poslovnim tijekovima rada za ispis, arhiviranje i usklađenost dokumenata, PDF datoteka ne može se jednostavno "prikazati" (renderirati). Ona mora biti revidirana. PDF može sadržavati neizravnate (unflattened) grupe transparentnosti koje uzrokuju pad naslijeđenih procesora rasterske slike (RIP-ova), ugrađeni JavaScript koji predstavlja sigurnosni rizik ili slike niske razlučivosti koje će izgledati užasno ispisane na 300 DPI.
Ovaj proces pregleda PDF-a prije nego što uđe u produkcijski tijek rada poznat je kao Preflighting. U ovom ćemo članku istražiti kako izgraditi automatizirani alat za preflight i reviziju rizika u Delphiju korištenjem mogućnosti parsiranja niske razine koje pruža PDFium.
Ključne preflight provjere
Standardna revizija rizika obično provjerava sljedeće elemente unutar PDF-a:
- Interaktivni elementi: JavaScript akcije, Launch akcije (pokretanje vanjskih programa) i AcroForms.
- Metrika resursa: Prisutnost slika niske razlučivosti ili nedostajući ugrađeni fontovi.
- Sigurnosni status: Enkripcija dokumenta, zahtjevi za lozinkom i dopuštenja pristupa (npr. ispis onemogućen).
- Standardi dokumenta: Validacija PDF/A ili PDF/X oznaka sukladnosti u metapodacima dokumenta.
Izdvajanje PDF metapodataka i zabilješki pomoću PDFiuma
PDFium pruža robusni C API koji Delphi može konzumirati. Da bismo izvršili preflight reviziju, ne samo da renderiramo stranicu; prolazimo kroz stablo PDF objekata. Pogledajmo kako iterirati kroz stranice dokumenta i pregledati zabilješke kako bismo pronašli potencijalno rizične JavaScript akcije.
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;
Provjera razlučivosti slike
Još jedan kritičan preflight korak za tijekove rada ispisa osigurava da nijedna slika ne padne ispod određenog DPI praga. PDFium vam omogućuje izdvajanje slikovnih objekata izravno iz toka stranice. Dijeljenjem dimenzija u pikselima izdvojene slike s fizičkim dimenzijama (u točkama) koje zauzima na PDF stranici, možete izračunati efektivni 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;
Integracija s PDFium Componentom
Izgradnja robusnog preflight motora od nule pomoću sirovog PDFium C API-ja zahtijeva značajnu količinu standardnog (boilerplate) koda i duboko poznavanje PDF specifikacije. Korištenje omotača (wrapper) to neizmjerno pojednostavljuje. Uz Delphi omotač visoke razine, složene iteracije C pokazivača možete pretvoriti u čist objektno orijentirani kod.
Automatizacijom faze preflighta sprječavate loše datoteke da začepe vaš proizvodni cjevovod, štedeći vrijeme i resurse za renderiranje.
Napomena: Napredno PDF parsiranje i mogućnosti preflighta u potpunosti su podržani u PDFium Component.