בתהליכי עבודה ארגוניים של הדפסה, ארכיבאות ותאימות מסמכים, קובץ PDF אינו יכול פשוט להיות "מעובד לתצוגה" (rendered). חובה לבצע לו ביקורת. קובץ PDF עשוי להכיל קבוצות שקיפות שאינן משוטחות (unflattened transparency groups) שגורמות לקריסת מעבדי תמונה (RIPs) ישנים, קוד JavaScript מוטמע שמהווה סיכון אבטחה, או תמונות ברזולוציה נמוכה שייראו נורא בהדפסה ב-300 DPI.
תהליך זה של בדיקת קובץ PDF לפני כניסתו לתהליך עבודה בסביבת ייצור ידוע בשם Preflighting (קדם-טיסה). במאמר זה, נחקור כיצד לבנות כלי אוטומטי לבדיקות preflight וביקורת סיכונים ב-Delphi על ידי ניצול יכולות הניתוח ברמה הנמוכה (low-level parsing) של PDFium.
בדיקות Preflight מרכזיות
ביקורת סיכונים סטנדרטית בודקת בדרך כלל את האלמנטים הבאים בתוך ה-PDF:
- אלמנטים אינטראקטיביים: פעולות JavaScript, פעולות Launch (הפעלת תוכנות חיצוניות), ו-AcroForms.
- מדדי משאבים: נוכחות של תמונות ברזולוציה נמוכה או חוסר בגופנים מוטמעים.
- סטטוס אבטחה: הצפנת מסמך, דרישות סיסמה, והרשאות גישה (למשל, הדפסה מושבתת).
- תקני מסמכים: אימות סמני תאימות של PDF/A או PDF/X במטא-נתונים של המסמך.
חילוץ מטא-נתונים והערות של PDF עם PDFium
PDFium מספק ממשק C API רובסטי ש-Delphi יכולה לצרוך. כדי לבצע ביקורת preflight, אנחנו לא רק מעבדים את הדף לתצוגה; אנו עוברים על עץ האובייקטים של ה-PDF. בואו נראה כיצד לעבור בלולאה על דפי המסמך ולבדוק הערות (annotations) כדי למצוא פעולות 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 מאפשר לכם לחלץ אובייקטי תמונה ישירות מזרם הדף. על ידי חלוקת מימדי הפיקסלים של התמונה שחולצה במימדים הפיזיים (בנקודות) שהיא תופסת בדף ה-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 ברמה גבוהה (high-level), תוכלו להפוך איטרציות מורכבות של מצביעי C לקוד מונחה עצמים נקי.
על ידי אוטומציה של שלב ה-preflight, תמנעו מקבצים פגומים לתקוע את צינור הייצור (production pipeline) שלכם, ותחסכו זמן ומשאבי עיבוד.
הערה: יכולות מתקדמות של ניתוח PDF ובדיקות preflight נתמכות באופן מלא על ידי PDFium Component.