Een PDF-intake-reviewwerkbank is een klein programmaatje met één taak: naar elk bestand kijken voordat iets downstream het mag aanraken. Om die taak te doen moet het een handvol mogelijkheden in één pass samenbrengen. Het opent het bestand (zonder het te vertrouwen), leest wat het bestand over zichzelf beweert, zoekt naar inhoud die een naïeve extractor zal misleiden of een aanval draagt, beslist of er überhaupt extraheerbare tekst is, en routeert het document dan naar een queue op basis van wat het vond. Sla de inspectie over en de falen zijn stille: een met eigenaarswachtwoord versleutelde PDF die een XFA-formulier omhult vaart door een tekstextractor als lege strings, wordt geïndexeerd als een blanco document, en niemand merkt het tot iemand downstream op zoek gaat naar inhoud die nooit gelezen is. PDFium Component is een source-code VCL/LCL-viewer en inspectiebibliotheek voor Delphi, C++Builder en Lazarus, en stelt de introspectie-aanroepen bloot die deze werkbank nodig heeft. De secties hieronder lopen door welke aanroep welke vraag beantwoordt, en de twee plaatsen waar de voor de hand liggende aanroep u een zelfverzekerd fout antwoord geeft
Vijf vragen om te beantwoorden voordat een bestand gerouteerd wordt
Stript u het raster en de thumbnail-strip af, dan reduceert intaketriage zich tot vijf vragen:
- Kan het bestand überhaupt geopend worden, en onder welk wachtwoord?
- Wat beweert het te zijn: titel, auteur, aanmaakdatum?
- Draagt het actieve of riskante inhoud zoals JavaScript, een XFA-formulier of ingebedde bestanden?
- Is er extraheerbare tekst, of is het een scan op weg naar OCR?
- Gegeven al dat, naar welke queue gaat het: directe verwerking, handmatige review of quarantaine?
Elke vraag beeldt zich op één of twee PDFium Component-aanroepen. Twee van die afbeeldingen hebben scherpe hoeken die verantwoordelijk zijn voor de meeste verkeerd gerouteerde bestanden die ik in productie heb moeten debuggen. Document-metadata leeft op twee verschillende plaatsen die het oneens kunnen zijn, en encryptie hoeft een document niet tegen te houden bij het openen
Goedkoop openen: form-fill uit, nul pagina's gerenderd
Triage hoort de goedkoopst mogelijke open te zijn. FormFill := False zetten vóór Active := True vertelt de component de form-fill-omgeving geheel over te slaan. Dat verkort de laadtijd, en (net zo belangrijk voor bestanden van onbekende herkomst) het voorkomt dat documentniveau-JavaScript initialiseert. Geen van de inspectie-eigenschappen die hieronder gebruikt worden vereist het renderen van een pagina, dus een triage-pass hoeft nooit één bitmap te produceren
procedure InspectIncoming(const IncomingPath: string; var Rec: TIntakeRecord);
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := IncomingPath;
Pdf.FormFill := False; // geen form-fill-omgeving, geen JavaScript-initialisatie
Pdf.Active := True; // mislukking is stil: Active blijft simpelweg False
if not Pdf.Active then
begin
Rec.OpenFailed := True; // beschadigd bestand of vergrendeling met gebruikerswachtwoord
Exit; // het finally-blok draait nog steeds
end;
Rec.PageCount := Pdf.PageCount;
CollectIdentity(Pdf, IncomingPath, Rec);
CollectRiskSignals(Pdf, Rec);
finally
Pdf.Active := False;
Pdf.Free; // lek de instantie nooit bij een misvormd bestand
end;
end;
De check na de toewijzing is niet optioneel, en het is een check in plaats van een exception-handler om een reden. Wanneer de engine het bestand niet kan laden, slikt de component de interne EPdfError weg en laat Active op False staan in plaats van die te propageren. Code die op een exception wacht leest vrolijk PageCount uit een document dat nooit opende. Als de afwijzingsworkflow de werkelijke fouttekst van de engine nodig heeft, lees het bestand in een byte-array en roep de LoadDocument-overload die TBytes neemt; dat pad raiset wél EPdfError met de melding, inclusief het wachtwoordgeval. Het try..finally verdient nog steeds zijn plaats. Intakeservices draaien wekenlang onbeheerd, en geen latere exception mag de TPdf-instantie lekken of een lock vasthouden waar de retry-pass over struikelt
Doorput wordt zelden de flessenhals. Met form-fill uit en geen rendering wordt een triage-open gedomineerd door I/O, en één worker inspecteert comfortabel enkele bestanden per seconde vanaf lokale schijf. Als intakevolume ooit één worker ontgroeit, partitioneer het werk op bestand in plaats van op check. De vijf vragen delen één open, en ze over processen verspreiden vermenigvuldigt de duurste stap in plaats van die af te schrijven
Metadata leeft op twee plaatsen, en ze zijn het oneens
ISO 32000-1 definieert twee thuishavens voor document-metadata: de document information dictionary (clausule 14.3.3) en een XMP-pakket dat aan de catalogus hangt (clausule 14.3.2). De eigenschappen Title, Author, Subject en CreationDate lezen de Info-dictionary, met MetaText[] voor elke andere key en DecodeDate om de D:YYYYMMDD...-datumstring te parsen. De adder is dat moderne producers steeds vaker alleen XMP schrijven, een richting die ISO 32000-2 officieel maakt door de meeste Info-dictionary-keys in PDF 2.0 te deprecaten. Het symptoom in een intakereeds is concreet. Uw werkbank toont een lege titel terwijl Adobe Acrobat er een toont, omdat Acrobat terugviel op dc:title binnen het XMP-pakket, wat de Info-dictionary-eigenschappen nooit aanraken
procedure CollectIdentity(Pdf: TPdf; const FilePath: string;
var Rec: TIntakeRecord);
begin
Rec.Title := Pdf.Title; // waarde uit de Info-dictionary
Rec.Author := Pdf.Author;
Rec.CreatedAt := Pdf.CreationDate; // ruwe PDF-datumstring ("D:2026...")
// Een lege Info-titel betekent niet dat het document geen titel heeft. Het
// component stelt het XMP-pakket niet bloot, dus doorzoek de ruwe bestands-
// bytes op het dc:title-element voordat u de lege waarde vertrouwt.
if (Rec.Title = '') and FileContainsText(FilePath, 'dc:title') then
Include(Rec.Flags, ifTitleInXmpOnly);
end;
Zelfs de ruwe substring-probe hierboven verdient zijn plaats: "metadata aanwezig, maar niet waar legacy-tools kijken" is een routeringsrelevant feit voor elke archiefpijplijn die op titel of auteur indexeert. Als uw downstream-index alleen de Info-dictionary leest, worden bestanden die zo gemarkeerd zijn stil onvindbaar
Versleutelde bestanden die toch openen
Een versleuteld document faalt niet noodzakelijk bij het openen. De standaard security handler (ISO 32000-1 clausule 7.6.3) onderscheidt een gebruikerswachtwoord, vereist om het document te openen, van een eigenaarswachtwoord die slechts permissies gate zoals afdrukken en kopiëren. Een groot aandeel "beschermde" zakelijke documenten is versleuteld met een eigenaarswachtwoord en een leeg gebruikerswachtwoord. Ze openen zonder prompt, ontcijferen volledig, en leunen op viewers die vrijwillig de permissieflags eren. Dat is beleid, geen bescherming, en uw intake-statussen moeten het verschil weerspiegelen
Encryptie detecteren na een geslaagde open vergt één engine-aanroep plus een fallback. FPDF_GetSecurityHandlerRevision(Pdf.Document) retourneert -1 voor onbeschermden en anders de handler-revisie, en Pdf.Permissions dat iets anders dan het alles-bit-gezette $FFFFFFFF-masker retourneert is het bevestigende signaal. Voor echt met gebruikerswachtwoord vergrendelde bestanden, wijs Password toe vóór Active := True; als het openen alsnog faalt, routeer het bestand naar een geblokkeerde status die credentials bij de afzender opvraagt via een beveiligd kanaal in plaats van blind te retrien. En weersta de verleiding om "versleuteld" als automatische quarantaine te behandelen. In de meeste documentintensieve bedrijfstakken zijn versleuteld-maar-openbare bestanden het normale geval, niet het verdachte
Actieve inhoud: JavaScript, XFA en ingebedde bestanden
Drie bevindingen moeten altijd de routeringsbeslissing bereiken. Ten eerste, JavaScript: het event OnUnsupportedFeature rapporteert structurele features zoals XFA of 3D-content wanneer de engine ze tegenkomt, maar detecteert geen JavaScript. Controleer in plaats daarvan JavaScriptActionCount en behandel een resultaat ongelijk nul als actieve inhoud. Ten tweede, XFA: wanneer FormType ftXfaFull retourneert, zijn de zichtbare pagina's vaak weinig meer dan een rendering van het XFA-template, en conventionele tekstextractie ziet boilerplate in plaats van de ingevulde waarden. Ten derde, bijlagen: een PDF is een containerformaat, en AttachmentCount vertelt u of deze passagiers meedraagt
procedure CollectRiskSignals(Pdf: TPdf; var Rec: TIntakeRecord);
var
i, PageNo: Integer;
Ext: string;
begin
Rec.IsEncrypted := Assigned(FPDF_GetSecurityHandlerRevision) and
(FPDF_GetSecurityHandlerRevision(Pdf.Document) <> -1);
Rec.HasForms := Pdf.FormType <> ftNone;
Rec.IsXfa := Pdf.FormType = ftXfaFull;
Rec.HasJavaScript := Pdf.JavaScriptActionCount > 0;
// AnnotationCount is een per-pagina-eigenschap; loop door de pagina's om het totaal
// te bepalen. Het laden van een paginaobject rendert niets, dus dit blijft goedkoop.
Rec.Annotations := 0;
for PageNo := 1 to Pdf.PageCount do
begin
Pdf.PageNumber := PageNo;
Inc(Rec.Annotations, Pdf.AnnotationCount);
end;
Rec.Attachments := Pdf.AttachmentCount;
for i := 0 to Rec.Attachments - 1 do
begin
Ext := LowerCase(ExtractFileExt(string(Pdf.AttachmentName[i])));
if (Ext = '.exe') or (Ext = '.js') or (Ext = '.vbs') or (Ext = '.dll') then
Include(Rec.Flags, ifDangerousAttachment);
end;
end;
Twee details in die lus verdienen aandacht. De bijlagen-naam komt van binnen het document, dus hergebruik die nooit als uitvoerpad zonder eerst te saneren; een ingebedde naam als ..\..\start.exe is een path-traversal die wacht op een onachtzame save-aanroep. En een extensie-blocklist is een draad, geen garantie. Zijn taak is een menselijke beslissing afdwingen, niet het bestand schoon certificeren
Van signalen naar routeringsstatussen
Een werkbaar statusmodel heeft minder statussen nodig dan de meeste teams verwachten: klaar (geen blokkades, tekst aanwezig), review (openen geslaagd maar iets vraagt ogen, zoals een XFA-formulier, JavaScript, een lege tekstlaag of een titel alleen in XMP), geblokkeerd (gebruikerswachtwoord vereist), en beschadigd (openen gefaald). Leg het bewijs vast naast de status. De bestandshash, paginatelling, de exacte flags, en de engine-foutmelding voor beschadigde bestanden doen er allemaal toe, want de persoon die een routeringsbeslissing in twijfel trekt doet dat weken later, tegen een bestand dat inmiddels vervangen of gewijzigd kan zijn
Wanneer een operator inderdaad naar een bestand in quarantaine moet kijken, lever het dan niet uit aan de standaard shell-viewer. Render het binnen een verhard paneel met scripting en koppelingsafhandeling uit, de aanpak beschreven in een veilig PDF-voorbeeldoppervlak bouwen in Delphi. En als uw intake een archief voedt met conformiteitseisen, dan is de triage-pass de natuurlijke plek om een diepere check in te plannen; batch preflight-validatie tegen PDF/A- en PDF/UA-profielen pakt precies op waar deze inspectie stopt
De productpagina van de component behandelt licentiëring, de volledige inspectie-API en de meegeleverde demo's, waaronder een intake-stijl documentinspecteur: PDFium Component