In Workflows für Unternehmensdruck, Archivierung und Dokumenten-Compliance kann eine PDF-Datei nicht einfach „gerendert“ werden. Sie muss geprüft werden. Ein PDF kann nicht reduzierte Transparenzgruppen enthalten, die ältere Raster Image Processors (RIPs) zum Absturz bringen, eingebettetes JavaScript, das ein Sicherheitsrisiko darstellt, oder niedrig auflösende Bilder, die bei einem Druck mit 300 DPI schrecklich aussehen.
Dieser Prozess der Inspektion eines PDFs, bevor es in einen Produktions-Workflow gelangt, wird als Preflighting bezeichnet. In diesem Artikel werden wir untersuchen, wie man ein automatisiertes Preflight- und Risiko-Auditing-Tool in Delphi entwickelt, indem man die Low-Level-Parsing-Funktionen von PDFium nutzt.
Wichtige Preflight-Prüfungen
Ein standardmäßiges Risiko-Audit prüft typischerweise auf die folgenden Elemente innerhalb eines PDFs:
- Interaktive Elemente: JavaScript-Aktionen, Launch-Aktionen (Ausführen externer Programme) und AcroForms.
- Ressourcenmetriken: Vorhandensein von niedrig auflösenden Bildern oder fehlenden eingebetteten Schriftarten.
- Sicherheitsstatus: Dokumentenverschlüsselung, Kennwortanforderungen und Zugriffsberechtigungen (z. B. Drucken deaktiviert).
- Dokumentenstandards: Validierung von PDF/A- oder PDF/X-Konformitätsmarkierungen in den Dokumentenmetadaten.
Extrahieren von PDF-Metadaten und Anmerkungen mit PDFium
PDFium bietet eine robuste C-API, die von Delphi konsumiert werden kann. Um ein Preflight-Audit durchzuführen, rendern wir nicht nur die Seite; wir durchlaufen den PDF-Objektbaum. Sehen wir uns an, wie man durch die Dokumentseiten iteriert und Anmerkungen überprüft, um potenziell riskante JavaScript-Aktionen zu finden.
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;
Überprüfen der Bildauflösung
Ein weiterer kritischer Preflight-Schritt für Druck-Workflows ist die Sicherstellung, dass kein Bild einen bestimmten DPI-Schwellenwert unterschreitet. PDFium ermöglicht es Ihnen, Bildobjekte direkt aus dem Seitenstrom zu extrahieren. Indem Sie die Pixelabmessungen des extrahierten Bildes durch die physischen Abmessungen (in Punkt) teilen, die es auf der PDF-Seite einnimmt, können Sie die effektive DPI berechnen.
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;
Integration mit PDFium Component
Der Aufbau einer robusten Preflight-Engine von Grund auf mit der rohen PDFium-C-API erfordert erheblichen Boilerplate-Code und tiefes Wissen über die PDF-Spezifikation. Die Verwendung eines Wrappers vereinfacht dies immens. Mit einem High-Level-Delphi-Wrapper können Sie komplexe C-Zeiger-Iterationen in sauberen objektorientierten Code umwandeln.
Durch die Automatisierung der Preflight-Phase verhindern Sie, dass fehlerhafte Dateien Ihre Produktionspipeline verstopfen, und sparen so sowohl Zeit als auch Rendering-Ressourcen.
Hinweis: Erweiterte PDF-Parsing- und Preflight-Funktionen werden von der PDFium Component VCL-Komponente vollständig unterstützt.