В работните процеси за корпоративен печат, архивиране и съответствие на документи (compliance), PDF файлът не може просто да бъде "изобразен". Той трябва да бъде одитиран. Даден PDF файл може да съдържа неоптимизирани групи за прозрачност, които сриват стари процесори за растерни изображения (RIP), вграден JavaScript, който представлява риск за сигурността, или изображения с ниска резолюция, които ще изглеждат ужасно при печат на 300 DPI.
Този процес на проверка на PDF файл преди влизането му в производствен работен процес е известен като Предварителна проверка (Preflighting). В тази статия ще разгледаме как да изградим автоматизиран инструмент за предварителна проверка и одит на риска в Delphi, възползвайки се от възможностите за синтактичен анализ на ниско ниво на PDFium.
Ключови предварителни проверки
Стандартният одит на риска обикновено проверява за следните елементи в рамките на PDF:
- Интерактивни елементи: Действия с JavaScript, действия за стартиране (Launch actions - изпълнение на външни програми) и AcroForms.
- Метрики на ресурсите: Наличие на изображения с ниска разделителна способност или липсващи вградени шрифтове.
- Състояние на сигурността: Криптиране на документа, изисквания за парола и разрешения за достъп (например забранен печат).
- Стандарти за документи: Валидиране на маркерите за съответствие с PDF/A или PDF/X в метаданните на документа.
Извличане на метаданни и анотации от PDF с PDFium
PDFium предоставя стабилен C API, който Delphi може да използва. За да извършим одит преди проверка, ние не просто изобразяваме страницата; ние обхождаме дървото на 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;
Проверка на резолюцията на изображенията
Друга критична стъпка при предварителната проверка за печатни работни процеси е да се гарантира, че никое изображение не пада под специфичен праг на 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
Изграждането на стабилна машина за предварителна проверка от нулата, използвайки суровия C API на PDFium, изисква значителен шаблонно генериран код и задълбочени познания за спецификацията на PDF. Използването на обвивка (wrapper) улеснява това неимоверно. С обвивка на високо ниво в Delphi можете да превърнете сложните итерации на указатели на C в чист обектно-ориентиран код.
Чрез автоматизиране на фазата на предварителна проверка, вие предотвратявате лоши файлове да задръстят вашия производствен конвейер, спестявайки както време, така и ресурси за изобразяване.
Забележка: Разширените възможности за анализ и предварителна проверка на PDF са напълно поддържани от PDFium Component.