Στις εταιρικές ροές εργασίας εκτύπωσης, αρχειοθέτησης και συμμόρφωσης εγγράφων, ένα αρχείο PDF δεν μπορεί απλώς να "αποδοθεί" (rendered). Πρέπει να ελεγχθεί. Ένα PDF ενδέχεται να περιέχει μη ισοπεδωμένες (unflattened) ομάδες διαφάνειας που καταρρέουν παλαιότερους επεξεργαστές εικόνας ράστερ (RIP), ενσωματωμένη JavaScript που εγκυμονεί κινδύνους ασφαλείας, ή εικόνες χαμηλής ανάλυσης που θα φαίνονται απαίσιες όταν εκτυπωθούν στα 300 DPI.
Αυτή η διαδικασία επιθεώρησης ενός PDF πριν εισέλθει σε μια ροή παραγωγής είναι γνωστή ως Preflighting. Σε αυτό το άρθρο, θα εξερευνήσουμε πώς να κατασκευάσουμε ένα αυτοματοποιημένο εργαλείο preflight και ελέγχου κινδύνων στο Delphi, αξιοποιώντας τις δυνατότητες ανάλυσης χαμηλού επιπέδου του PDFium.
Βασικοί Έλεγχοι Preflight
Ένας τυπικός έλεγχος κινδύνου ελέγχει συνήθως για τα ακόλουθα στοιχεία μέσα σε ένα PDF:
- Διαδραστικά Στοιχεία: Ενέργειες JavaScript, Ενέργειες εκκίνησης (Launch actions - εκτέλεση εξωτερικών προγραμμάτων) και AcroForms.
- Μετρήσεις Πόρων: Παρουσία εικόνων χαμηλής ανάλυσης ή απουσία ενσωματωμένων γραμματοσειρών.
- Κατάσταση Ασφαλείας: Κρυπτογράφηση εγγράφου, απαιτήσεις κωδικού πρόσβασης και δικαιώματα πρόσβασης (π.χ. απενεργοποιημένη εκτύπωση).
- Πρότυπα Εγγράφου: Επικύρωση δεικτών συμμόρφωσης PDF/A ή PDF/X στα μεταδεδομένα του εγγράφου.
Εξαγωγή Μεταδεδομένων και Σχολίων PDF με το PDFium
Το PDFium παρέχει ένα ισχυρό C API που μπορεί να καταναλώσει το Delphi. Για να εκτελέσουμε έναν έλεγχο preflight, δεν αποδίδουμε απλώς τη σελίδα· διασχίζουμε το δέντρο αντικειμένων του PDF. Ας δούμε πώς να επαναλάβουμε τις σελίδες του εγγράφου και να επιθεωρήσουμε σχόλια για να βρούμε δυνητικά επικίνδυνες ενέργειες JavaScript.
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;
Έλεγχος Ανάλυσης Εικόνας
Ένα άλλο κρίσιμο βήμα preflight για ροές εργασίας εκτύπωσης είναι η διασφάλιση ότι καμία εικόνα δεν πέφτει κάτω από ένα συγκεκριμένο όριο DPI. Το PDFium σας επιτρέπει να εξάγετε αντικείμενα εικόνας απευθείας από τη ροή της σελίδας. Διαιρώντας τις διαστάσεις σε pixel της εξαγόμενης εικόνας με τις φυσικές διαστάσεις (σε στιγμές/points) που καταλαμβάνει στη σελίδα PDF, μπορείτε να υπολογίσετε το πραγματικό 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;
Ενσωμάτωση με το PDFium Component
Η κατασκευή μιας ισχυρής μηχανής preflight από το μηδέν χρησιμοποιώντας το ακατέργαστο C API του PDFium απαιτεί σημαντικό κώδικα boilerplate και βαθιά γνώση της προδιαγραφής PDF. Η χρήση ενός περιτυλίγματος (wrapper) απλοποιεί εξαιρετικά αυτή τη διαδικασία. Με ένα υψηλού επιπέδου περιτύλιγμα Delphi, μπορείτε να μετατρέψετε πολύπλοκες επαναλήψεις δεικτών (pointers) C σε καθαρό αντικειμενοστραφή (object-oriented) κώδικα.
Αυτοματοποιώντας τη φάση του preflight, αποτρέπετε τα προβληματικά αρχεία από το να μπλοκάρουν τη γραμμή παραγωγής σας, εξοικονομώντας χρόνο και πόρους απόδοσης (rendering resources).
Σημείωση: Οι προηγμένες δυνατότητες ανάλυσης και preflight PDF υποστηρίζονται πλήρως από το PDFium Component.