De democollectie beslaat 33 onderwerpen: 33 Delphi-projecten, 32 C++Builder-projecten en 33 Lazarus-projecten, in totaal 98 native projecten. In de hoofdmap van elk platform staan 24 complete workflowdemo's. Negen gerichte onderwerpen staan onder Miscellaneous, samen 26 native projecten over de drie platforms; XfaLab is beschikbaar voor Delphi en Lazarus
Open eerst een workflow uit de hoofdmap: PDFViewer voor een featuretour, CreatePDF voor live documentcreatie, ContentExtractionLab voor een directe inventaris, FormFill voor bewerkbare formulieren, StandardsLab voor validatie en conversie, of IntakeWorkbenchCli voor geautomatiseerde intake. Deze zes instappunten leveren direct werkende resultaten op; de gerichte voorbeelden hieronder zijn handig wanneer u één API in detail wilt inspecteren
| Demo | Gebruik het voor | Waarin het verschilt van verwante demo's |
|---|---|---|
PDFViewer | Algemene weergave en feature-evaluatie | De hoofdviewer combineert navigatie, zoeken, miniaturen, weergavemodi, afdrukken en een feature-overzicht |
MultiPageViewer | Doorlopende pagina's, spreads en omslagpagina-indelingen | Een gericht layoutvoorbeeld met de ingebouwde selectie-API's van de viewer; gebruik PDFViewer voor de bredere viewer-ervaring |
SplitView | Pagina's of documenten vergelijken in aparte deelvensters | Demonstreert onafhankelijke weergaveposities en het sturen van commando's naar het actieve deelvenster, in plaats van een tweepagina-indeling in één weergave |
SearchAndSelect | Zoekresultaten en selectie over pagina's heen | Een resultatenlijst en zoekopties leggen de zoekworkflow directer bloot dan een werkbalk in de viewer |
PrintPDF | Voorvertoning en gewone afdruktaken | Paginabereiken, schaling, voortgang en annuleren vormen de kern van de afdrukworkflow |
ContentExtractionLab | Meerdere contentcategorieën samen inspecteren | TXT/JSON-inventarissen beschrijven objecten en tonen voorvertoningstekst; ze vervangen geen volledige export van tekst of afbeeldingsbestanden |
ExtractImages | Ingebedde afbeeldingsobjecten exporteren | Haalt afbeeldingsbitmaps op in plaats van screenshots van hele pagina's; de ingebouwde fixture bevat op elk van twee pagina's twee echte afbeeldingsobjecten |
TableExtractionLab | Tabellen detecteren en als CSV/JSON exporteren | Tabellen met en zonder rasterlijnen, samengevoegde cellen, vervolggroepen en confidence-instellingen staan los van platte-tekstextractie |
Attachment | Ingebedde bijlagen lezen, toevoegen en exporteren | Bewerkingen op de payload van bijlagen gaan verder dan het tonen van namen en groottes in ContentExtractionLab |
BatchExport | Paginabeelden exporteren uit meerdere documenten | Gestreamde uitvoer, status per bestand en geïsoleerde fouten laten batchverwerking zien in plaats van één enkele conversie |
CreatePDF | Pagina-inhoud aanmaken met een live voorvertoning | Alle drie de native varianten maken doorzoekbare tekst, vectorvormen, een echte rasterafbeelding, tabellen en een review-annotatie aan; opties bouwen de voorvertoning opnieuw op vóór een expliciete opslag |
ImageToPDF | Pagina's opbouwen uit invoerafbeeldingsbestanden | Afbeeldingslayout, passend schalen, volgorde en JPEG-afhandeling vormen een workflow voor documentconversie |
MergePDF | Pagina's uit meerdere PDF's samenstellen | Demonstreert documentimport en geordende samenstelling; splitsen behandelt de omgekeerde workflow |
SplitPDF | Geselecteerde paginagroepen naar aparte PDF's schrijven | Uitvoerbenaming en validatie van paginagroepen verschillen van samenvoegen of paginabeeld-rendering |
WatermarkStamp | Herhaalde overlays aanbrengen op bestaande pagina's | Plaatsing en batchgewijs stempelen van pagina's vullen de basis-API's voor documentcreatie aan |
FormFill | Interactieve AcroForm-invoer en flattening | Veldinvoer en opgeslagen appearances verschillen van XFDF-uitwisseling en XFA-specifiek gedrag |
AccessibilityReader | Interactief lezen en spraak | De GUI-lezer demonstreert leesnavigatie en markering in plaats van een compliance-audit |
AccessibilityWorkbenchCli | Batchgewijze accessibility-review en rapportgeneratie | Bevindingen, samenvattingen en review-gates dienen automatisering; bevindingen zijn geen vervanging voor handmatige accessibility-review |
StandardsLab | Validatie en conversie voor specifieke standaarden | De interactieve lab ontsluit bewerkingen en opties in plaats van alleen een totaalrapport te genereren |
PreflightReport | Interactieve standaardrapporten | De GUI ondersteunt handmatige inspectie en rapportexport |
PreflightReportCli | Geautomatiseerde standaardrapporten | Batch-invoer, rapportformaten en exit-code-gates leveren de automatiseringsvariant van PreflightReport |
IntakeWorkbenchCli | Batch-intake, triage en routering | Geaggregeerde rapporten, drempels voor mislukte runs en routeringsbeslissingen maken dit een verwerkingsworkflow die verder gaat dan de SecurityAudit-GUI |
Open deze projecten vanuit Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous of Demo\Lazarus\Miscellaneous. Ze bewaren nuttige API-recepten en gerichte exporttaken, terwijl de hoofdmap zich op complete ervaringen richt. Eenvoudige controles waarbij Unicode-tekst wordt weggeschreven en opnieuw geladen, vallen onder de workflows voor documentcreatie en extractie; aparte demoprojecten zijn er niet meer
| Demo | Gebruik het voor | Waarin het verschilt van verwante demo's |
|---|---|---|
SecurityAudit | De security posture interactief inspecteren | De GUI benadrukt rechten, scripts, handtekeningen en beveiligingsdetails in plaats van bestandsroutering |
XfdfLab | XFDF-gegevens importeren en exporteren | Uitwisseling plus een expliciete opslag van de geïmporteerde PDF tonen persistentie; alleen XFDF exporteren slaat de gewijzigde PDF niet op |
AccessibilityLab | De reader-API's doorlopen in een console | Een compacte, uitvoerbare rondleiding toont leeseenheden, woordkaders, structuur en speech-script-uitvoer |
ExtractText | Volledige tekst exporteren van geselecteerde pagina's | Tekstlaag-uitvoer, paginascheidingstekens en annuleren onderscheiden zich van inventarisvoorvertoningen en tabeldetectie; er wordt geen OCR uitgevoerd |
FontProperties | Font- en karaktermetrics inspecteren | Opent met echte font- en karaktermetrics voor het eerste tekstobject; selecteer een andere regel om fonts te vergelijken zonder documentpayloads te exporteren |
NavigationLab | Bladwijzers, bestemmingen en navigatieacties | De compacte API-rondleiding vult de zichtbare navigatiebediening van PDFViewer aan |
PDFtoJpg | Één document renderen naar paginabeelden | Een compact rendervoorbeeld voor één document; Delphi ontsluit discrete paginabereiken, terwijl BatchExport zich richt op meerdere invoerdocumenten |
PrintPreferences | N-up-vellen en auteur-printvoorkeuren | Kopieën, filters op oneven/even en door de auteur opgegeven voorkeuren staan centraal; dit is een aanvulling op PrintPDF |
ViewerInteractionLab | Muis-, toetsenbord- en coördinaatinteracties diagnosticeren | Het interactielog en de omzetting tussen pagina- en apparaatcoördinaten maken het een diagnostiektool voor de API |
XfaLab | Statische XFA-packets en runtime-mogelijkheden | Opent template- en datasets-packets met de gewone runtime; interactieve XFA-weergave vereist een runtime met XFA-ondersteuning, met varianten voor Delphi en Lazarus |
PDFViewer opent zijn meegeleverde PDFiumDemoShowcase.pdf, een document van zes pagina's met doorzoekbare tekst, vectorgrafieken, twee ingebedde afbeeldingen, een tabel, vier AcroForm-velden, hoofdstukbladwijzers, links, een review-notitie en twee bestandsbijlagen. De experience-bar biedt Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF en Explore forms; elke actie werkt op het huidige document
CreatePDF opent een live rapportvoorvertoning van twee pagina's. Bewerk de titel en auteur of wissel vormen, de tabel en het watermerk om echte pagina-inhoud opnieuw op te bouwen; de Unicode-optie voegt een derde pagina toe. Er wordt niets weggeschreven tot u opslaat, en de opgeslagen PDF blijft doorzoekbaar
MultiPageViewer, SearchAndSelect, ContentExtractionLab en FormFill openen hetzelfde document voor hun eigen workflows, met zoekresultaten, een extractie-inventaris en bewerkbare velden direct gereed. Miscellaneous\NavigationLab gebruikt zijn eigen lokale kopie voor een rondleiding langs de bladwijzer- en bestemmings-API's
Attachment start met twee echte ingebedde bestanden. PrintPreferences start met vier pagina's en auteursvoorkeuren voor twee kopieën, geselecteerde paginabereiken, schaling en duplex; de huidige printworkflow past kopieën en paginabereiken toe, terwijl schaling en duplex worden geïnspecteerd en gerapporteerd. XfaLab start met echte template- en datasets-packets voor statische XFA-inspectie; interactieve XFA-weergave vereist een geschikte runtime en is een aparte mogelijkheid
Elk weergave-, formulier-, extractie- en navigatieproject bevat zijn eigen PDFiumDemoShowcase.pdf. Kopieer de projectmap en houd deze meegeleverde invoer naast de gedistribueerde executable; Lazarus-builds zetten hem automatisch klaar. De tour werkt offline, en algemene viewers en extractievoorbeelden bieden ook gegenereerde fallback-content wanneer de lokale PDF niet beschikbaar is
Elke native demo bevat zijn eigen voorbeeldimplementatie. De Delphi- en Lazarus-instappunten voor AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli en PreflightReportCli bevatten de volledige workflow in de projectmap, inclusief compilerspecifieke initialisatie en het schrijven van JPEG's. De voorbeelden voor bijlagen, printvoorkeuren en XFA bouwen hun eigen featurespecifieke invoer ook lokaal op. Buiten het gekopieerde project zijn alleen de library, de bijpassende native runtime en de normale afhankelijkheden van het compilerframework nodig
Kies extractie van afbeeldingsobjecten wanneer ingebedde bitmaps nodig zijn, paginarendering wanneer de zichtbare pagina nodig is, en tekstextractie wanneer de PDF al een tekstlaag heeft. Een rapport dat deze categorieën opsomt, exporteert niet hun volledige payloads. Deze grenzen houden de gerichte voorbeelden nuttig zonder dat elke demo uitgroeit tot weer een andere algemene viewer of workbench
Pdf1.FileName := 'C:\MyDocument.pdf';
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
ShowMessage('Title: ' + Pdf1.Title);
ShowMessage('Author: ' + Pdf1.Author);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile('C:\MyDocument.pdf');
Pdf1.LoadDocument(Stream, True);
Pdf1.Active := True;
ShowMessage('PDF loaded from stream');
finally
Stream.Free;
end;
end;
Pdf1.CreateDocument;
Pdf1.Active := True;
Pdf1.AddPage(0, 612, 792);
Pdf1.PageNumber := 1;
Pdf1.AddText('Hello World!', 'Arial', 12, 100, 700, clBlack, $FF, 0.0);
Pdf1.UpdatePage;
Pdf1.SaveAs('C:\NewDocument.pdf');
Pdf1.Active := False;
var
PageText: WString;
RectText: WString;
begin
Pdf1.PageNumber := 1;
PageText := Pdf1.Text;
Memo1.Text := PageText;
RectText := Pdf1.TextInRectangle(100, 100, 500, 200);
ShowMessage('Text in rectangle: ' + RectText);
end;
var
Position: Integer;
begin
Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
while Position >= 0 do
begin
ShowMessage('Found at character: ' + IntToStr(Position));
Position := Pdf1.FindNext;
end;
end;
Pdf1.PageNumber := 1;
Pdf1.AddText('Document Title', 'Times New Roman', 16, 100, 750, clBlue);
Pdf1.AddText('This is the document content.', 'Arial', 12, 100, 700, clBlack);
Pdf1.UpdatePage;
var
I: Integer;
MetricSize: Single;
FontBytes: TBytes;
begin
Pdf1.PageNumber := 1;
for I := 0 to Pdf1.ObjectCount - 1 do
if Pdf1.ObjectType[I] = otText then
begin
MetricSize := 12.0;
FontBytes := Pdf1.FontData[I];
Memo1.Lines.Add('Object ' + IntToStr(I));
Memo1.Lines.Add('Base name: ' + Pdf1.FontBaseName[I]);
Memo1.Lines.Add('Family: ' + Pdf1.FontFamilyName[I]);
Memo1.Lines.Add('Embedded: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
Memo1.Lines.Add('Weight: ' + IntToStr(Pdf1.FontWeight[I]));
Memo1.Lines.Add('Italic angle: ' + IntToStr(Pdf1.FontItalicAngle[I]));
Memo1.Lines.Add('Ascent: ' + FloatToStr(Pdf1.FontAscent[I, MetricSize]));
Memo1.Lines.Add('Descent: ' + FloatToStr(Pdf1.FontDescent[I, MetricSize]));
Memo1.Lines.Add('Font data bytes: ' + IntToStr(Length(FontBytes)));
end;
if Pdf1.CharacterCount > 0 then
begin
Memo1.Lines.Add('First character size: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
Memo1.Lines.Add('First character weight: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
Memo1.Lines.Add('First character angle: ' + FloatToStr(Pdf1.CharacterAngle[0]));
end;
end;
De projecten Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties en Demo\Lazarus\Miscellaneous\FontProperties tonen dezelfde metadata via zowel TPdf als TPdfView
De projecten Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab en Demo\Lazarus\ContentExtractionLab maken van inhoudsextractie één workflow. Ze openen of maken een PDF, laten gebruikers metadata, paginatekst, pagina-objecten, afbeeldingen, bijlagen, links, annotaties, bladwijzers en font-/karaktermetrics kiezen, en genereren vervolgens een samenvatting plus een gedetailleerd TXT- of JSON-rapport. De lab bevat ook alle / geen categorie-selectie, rapport-kopiëren-naar-klembord en bron-PDF-opslag-acties, zodat gebruikers de gegenereerde voorbeeld-PDF naast zijn extractierapport kunnen bewaren. ExtractImages en Attachment verzorgen workflows voor payload-export, terwijl Miscellaneous\ExtractText en Miscellaneous\FontProperties gerichte API-voorbeelden blijven; ExtractText ondersteunt opties voor paginabereik en paginascheidingstekens om tekstuitvoer per pagina te produceren in Delphi, C++Builder en Lazarus, terwijl ContentExtractionLab het overkoepelende inventarisvoorbeeld is
De projecten Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab en Demo\Lazarus\TableExtractionLab maken van tabeldetectie één werkstroom. De lab bouwt een voorbeelddocument met een tabel met rasterlijnen en samengevoegde kopcellen, een tabel die zonder lijnen op witruimte is uitgelijnd en een lange tabel die over een paginagrens heen afbreekt, draait vervolgens ExtractTables voor de huidige pagina of ExtractDocumentTables voor het hele document en rapporteert rijen, kolommen, RowSpan- en ColumnSpan-waarden, kopvlaggen, detectiemodus, confidence en vervolggroepen. De opties DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings en MinConfidence zijn in de gebruikersinterface te bewerken, en de geselecteerde tabel wordt geëxporteerd via TPdfTable.ToCsv en TPdfTable.ToJson. De lab batcht ook een hele map: Batch folder draait ExtractDocumentTables over elke PDF, rapporteert tabellaantallen per document, vlagt scans zonder tekstlaag en probeert lege documenten opnieuw met een voorinstelling voor compacte kolommen; Export all CSV schrijft elke gedetecteerde tabel naast de bronbestanden. Elk document opent in zijn eigen TPdf-instantie, zodat één onleesbaar bestand de rest van de batch niet kan beïnvloeden
var
I: Integer;
FieldInfo: TPdfFormFieldInfo;
begin
Pdf1.FormField[0] := 'John';
for I := 0 to Pdf1.FormFieldCount - 1 do
begin
FieldInfo := Pdf1.FormFieldInfo[I];
ShowMessage(FieldInfo.Name + ': ' + Pdf1.FormField[I]);
end;
end;
// Zonder afvlakken schrijft FormField[i] := value alleen de /V-entry —
// de zichtbare appearance komt uit de /AP-stream en kan mogelijk niet
// vernieuwen. GenerateFormAppearances regenereert /AP voor elk widget,
// daarna bakt FlattenAllPages alle annotaties en widgets van elke pagina
// in als permanente, niet-bewerkbare inhoud.
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := '[email protected]';
Pdf1.GenerateFormAppearances;
if Pdf1.FlattenAllPages then
Pdf1.SaveAs('C:\Application.flat.pdf');
Pdf1.Active := False;
var
I: Integer;
Bitmap: TBitmap;
begin
for I := 0 to Pdf1.BitmapCount - 1 do
begin
Bitmap := Pdf1.Bitmap[I];
try
Bitmap.SaveToFile('C:\ExtractedImage' + IntToStr(I) + '.bmp');
finally
Bitmap.Free;
end;
end;
end;
var
JpegStream: TFileStream;
begin
JpegStream := TFileStream.Create('C:\MyImage.jpg', fmOpenRead or fmShareDenyWrite);
try
Pdf1.AddJpegImage(JpegStream, 100, 500, 200, 150);
finally
JpegStream.Free;
end;
Pdf1.AddPicture(Image1.Picture, 100, 300, 150, 100);
Pdf1.UpdatePage;
end;
var
I: Integer;
Annotation: TPdfAnnotation;
begin
for I := 0 to Pdf1.AnnotationCount - 1 do
begin
Annotation := Pdf1.Annotation[I];
ShowMessage('Annotation ' + IntToStr(I) + ': ' + Annotation.ContentsText);
end;
end;
Pdf1.CreatePath(100, 100, 200, 150, fmAlternate, clYellow, $FF, True, clBlack, $FF, 2.0);
Pdf1.AddPath;
Pdf1.CreatePath(100, 100, fmNone, clBlack, $FF, True, clRed, $FF, 3.0);
Pdf1.LineTo(200, 100);
Pdf1.LineTo(150, 200);
Pdf1.ClosePath;
Pdf1.AddPath;
Pdf1.UpdatePage;
var
I: Integer;
Bookmarks: TBookmarks;
begin
Bookmarks := Pdf1.Bookmarks;
for I := 0 to Length(Bookmarks) - 1 do
ShowMessage(Bookmarks[I].Title + ' -> Page ' + IntToStr(Bookmarks[I].PageNumber));
end;
var
I: Integer;
Destination: TDestination;
begin
for I := 0 to Pdf1.DestinationCount - 1 do
begin
Destination := Pdf1.Destination[I];
if Destination.Name = 'Chapter1' then
begin
Pdf1.PageNumber := Destination.PageNumber;
Break;
end;
end;
end;
var
I: Integer;
AttachmentData: TBytes;
AttachmentName: WString;
FileStream: TFileStream;
begin
for I := 0 to Pdf1.AttachmentCount - 1 do
begin
AttachmentName := Pdf1.AttachmentName[I];
AttachmentData := Pdf1.Attachment[I];
FileStream := TFileStream.Create('C:\Extracted_' + string(AttachmentName), fmCreate);
try
if Length(AttachmentData) > 0 then
FileStream.WriteBuffer(AttachmentData[0], Length(AttachmentData));
finally
FileStream.Free;
end;
end;
if Pdf1.CreateAttachment('MyFile.txt') then
Pdf1.Attachment[Pdf1.AttachmentCount - 1] := TFile.ReadAllBytes('C:\MyFile.txt');
end;
Pdf1.AddPage(Pdf1.PageCount + 1, 612, 792);
Pdf1.AddPage(Pdf1.PageCount + 1, 595, 842);
Pdf1.AddPage(Pdf1.PageCount + 1, 400, 600);
var
SourcePdf: TPdf;
begin
SourcePdf := TPdf.Create(nil);
try
SourcePdf.FileName := 'C:\SourceDocument.pdf';
SourcePdf.Active := True;
Pdf1.ImportPages(SourcePdf, '1', Pdf1.PageCount + 1);
finally
SourcePdf.Free;
end;
end;
if Pdf1.PageCount > 1 then
Pdf1.DeletePage(Pdf1.PageCount);
// Maak een gecomprimeerd PDF-document
Pdf1.CreateDocument;
Pdf1.Compressed := True; // zorg dat alle streams FlateDecode-gecomprimeerd zijn (standaard)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // A4-formaat
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Opslaan met opties
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // incrementeel opslaan
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // beveiliging verwijderen
// Opslaan met specifieke PDF-versie als doel. De PDF-versie-validator
// weigert elke functie die na de gekozen doelversie is geïntroduceerd
// (JBIG2Decode, MarkInfo, AES-versleuteling, Polygon / Caret / Watermark /
// Redact-annotaties, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Save rejected: document contains features newer than PDF 1.5');
// SaveAsPdfA nabewerkt de basisopslag met een incrementele update die een
// XMP-metadatastream, een sRGB ICC OutputIntent en een bijgewerkte
// documentcatalogus injecteert zodat het resultaat PDF/A-1b-conform is.
// Het meegeleverde sRGB IEC61966-2.1-profiel wordt automatisch gebruikt
// wanneer geen aangepast profiel wordt geleverd.
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('Saved PDF/A-1b archive');
// PDF/A met een aangepast ICC-profiel (bijvoorbeeld voor CMYK-print-pijplijnen)
var
Opts: TPdfASaveOptions;
begin
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
Opts.IccProfileData := TFile.ReadAllBytes('C:\Profiles\Coated_GRACoL_2006.icc');
Pdf1.SaveAsPdfA('C:\Report.cmyk.pdfa.pdf', Opts);
end;
// PDF/A-uitvoer in het geheugen
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
if Pdf1.SaveAsPdfAToStream(Stream, Opts) then
UploadToArchive(Stream);
finally
Stream.Free;
end;
end;
var
Validation: TPdfAValidationResult;
Issue: TPdfAValidationIssue;
begin
Pdf1.FileName := 'C:\Incoming\report.pdf';
Pdf1.Active := True;
// Goedkope header-stijl probe — leest de conformiteit zonder de
// volledige validator te itereren. Resultaat: pacNone, pac1a, pac1b,
// pac2b, pac3b of pacUnknown.
case Pdf1.PdfAConformance of
pac1b: Status.Caption := 'PDF/A-1b';
pac2b: Status.Caption := 'PDF/A-2b';
pacNone: Status.Caption := 'Not PDF/A';
else
Status.Caption := 'Unknown conformance';
end;
// Volledige validator met diagnostiek per probleem
Validation := Pdf1.ValidatePdfA;
Memo1.Lines.Add('Conformance: ' + GetEnumName(TypeInfo(TPdfAConformance),
Ord(Validation.Conformance)));
for Issue in Validation.Issues do
Memo1.Lines.Add('- ' + Issue.Description);
end;
De projecten Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab en Demo\Lazarus\StandardsLab laden of maken een PDF, voeren ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR en ValidatePdfVT uit en tonen vervolgens elk gedetecteerd conformiteitsniveau en aantal problemen in één raster. Hun save-knoppen roepen SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR en SaveAsPdfVT aan, zodat de marker-output-workflow zichtbaar is zonder een aangepast harnas te schrijven
De unit FPdfPreflightReport wikkelt ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR en ValidatePdfVT in één doorzoekbaar rapportobject met ernst Info / Warning / Error, aggregatie van status en problemen, opzoeken, zoeken, filtering en stabiele SHA-256-vingerafdrukken. Rapporten kunnen worden uitgevoerd als tekst, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON of native XML. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport en Demo\CBuilder\PreflightReport bieden interactieve selectie- en voorvertoningsworkflows, terwijl Demo\Delphi\PreflightReportCli scriptbare invoer-/uitvoerargumenten, filtering op standaard, optionele inbedding van rapportbijlagen, CI-exitcode-gating, batchverwerking via lijsten en mappen, collision-veilige routering, samenvattende totalen en CSV-manifesten toevoegt. Het gegenereerde rapport vermeldt dat de ingebouwde validators marker-level- en geselecteerde file-level-checks dekken, zodat volledige content-level preflight nog steeds kan worden gedelegeerd aan een gespecialiseerde validatie-engine
// LoadCustomDocument laat PDFium blokken ophalen uit elke seekable TStream
// op aanvraag. De stream wordt NIET naar het geheugen gekopieerd, zodat
// PDF's van meerdere GB, remote HTTP body streams en databasegebaseerde
// bronnen allemaal haalbaar zijn zonder een vooraf gemaakte buffer.
var
FileStream: TFileStream;
begin
// Streamen vanuit bestand (geen kopie in geheugen)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ eigendom overgedragen — Pdf1 vrijgeeft FileStream bij UnloadDocument.
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Stream in extern beheer (aanroeper geeft hem vrij na UnloadDocument)
var
Stream: TFileStream;
begin
Stream := TFileStream.Create('C:\Live.pdf',
fmOpenRead or fmShareDenyNone);
try
Pdf1.LoadCustomDocument(Stream, False);
Pdf1.Active := True;
DoWork;
Pdf1.Active := False;
finally
Stream.Free;
end;
end;
// FPdfAsync biedt IPdfCancellationToken / IPdfCancellationTokenSource voor
// cancel-from-UI-semantiek die werkt over de langlopende export- en
// renderpaden.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... gebruiker klikt op Annuleren ...
CancelSource.Cancel;
// De worker controleert periodiek CancelToken.IsCancelled, of het
// renderpad peilt het via PDFium's IFSDK_PAUSE-callback.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive laat een lange high-DPI-render halverwege de
// pagina afbreken wanneer de gebruiker op Annuleren klikt, in plaats van
// de aanroeper te blokkeren tot het klaar is.
var
Status: TPdfProgressiveStatus;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Status := Pdf1.RenderPageProgressive(Bitmap, 0, 0, Bitmap.Width,
Bitmap.Height, CancelToken, ro0, [reAnnotations], clWhite);
case Status of
prsDone: SaveBitmap(Bitmap);
prsCancelled: Memo1.Lines.Add('Render cancelled — partial result available');
prsFailed: Memo1.Lines.Add('PDFium reported FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> start een worker op een achtergrondthread en stuurt een
// TPdfFutureResult<T>-envelop terug naar de hoofdthread.
//
// Belangrijk: TPdf serialiseert render-aanroepen per instance, maar de
// worker beheert nog steeds dispatch en levensduur van het document. Muteer
// geen TPdf terwijl een render onderweg is; batch-export houdt meestal één
// TPdf per bestand aan.
type
TRenderResult = record
Bitmap : TBitmap;
PageNo : Integer;
end;
var
Future: TPdfFuture<TRenderResult>;
begin
Future := TPdfFuture<TRenderResult>.Create(
function (const ACancelToken: IPdfCancellationToken): TRenderResult
var
LocalPdf: TPdf;
begin
LocalPdf := TPdf.Create(nil);
try
LocalPdf.FileName := 'C:\Huge.pdf';
LocalPdf.Active := True;
LocalPdf.PageNumber := 1;
Result.Bitmap := LocalPdf.RenderPage(0, 0, 2480, 3508);
Result.PageNo := 1;
finally
LocalPdf.Free;
end;
end,
procedure (const AResult: TPdfFutureResult<TRenderResult>)
begin
case AResult.State of
pfsSuccess: PaintBitmapToView(AResult.Value.Bitmap);
pfsCancelled: Log.Add('Cancelled');
pfsFailed: Log.Add('Worker failed: ' + AResult.ErrorMessage);
end;
end);
end;
// FPdfMatrix wikkelt PDFium's FS_MATRIX zodat aanroepers een transform
// declaratief kunnen bouwen en aan FPDFPageObj_SetMatrix kunnen overdragen.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // verplaats 1in naar rechts, ~2.8in omhoog
M.Scale(0.5, 0.5); // half-formaat stempel
M.Rotate(15); // 15 graden CCW-rotatie
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // post-multipliceer met een andere matrix
// Toepassen op elk PDFium-pagina-object (text / path / image / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex kopieert een expliciete zero-based index-array van
// een bron-PDF naar dit document. InsertAt = 0 voegt in vóór pagina 1;
// PageCount voegt toe aan het einde.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Importeer pagina's 0, 2, 4 (one-based: pagina's 1, 3, 5) uit Source
// en voeg ze toe aan het einde van Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Een lege array importeert elke bronpagina
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne retourneert een gloednieuwe TPdf waarvan de pagina's
// NumX*NumY composieten zijn van DIT document. OutputWidth/Height zijn
// PDF-user-units (1 unit = 1/72 in).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 landschap: 842 x 595 pt, 2 kolommen x 2 rijen
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages neemt de zero-based indices van de te verplaatsen pagina's
// plus de doelindex voor de eerste verplaatste pagina nadat de verplaatsing
// is voltooid. Andere pagina's schuiven rond het verplaatste blok zodat de
// documentlengte hetzelfde blijft.
//
// Voorbeeld: in een document van 5 pagina's met pagina's [0,1,2,3,4],
// herordent MovePages([2, 3], 0) naar [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage maakt een herbruikbare Form XObject-handle van
// elke pagina van elke andere TPdf. Stempel die handle op zoveel pagina's
// van DIT document als u wilt — elke stempel is één PDFium-pagina-object
// dat kan worden gepositioneerd, geschaald en geroteerd via de matrix-API.
uses FPdfMatrix, FPdfView;
var
WatermarkSource: TPdf;
XObj: TPdfXObject;
PageObj: FPDF_PAGEOBJECT;
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
I: Integer;
begin
WatermarkSource := TPdf.Create(nil);
try
WatermarkSource.FileName := 'C:\Watermarks\Confidential.pdf';
WatermarkSource.Active := True;
// Wikkel pagina 0 van WatermarkSource in als herbruikbaar XObject
XObj := Pdf1.CreateXObjectFromPage(WatermarkSource, 0);
try
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageObj := Pdf1.InsertFormObjectFromXObject(XObj);
if PageObj = nil then Continue;
// Centreer het watermerk op de pagina
M := TPdfMatrix.Create;
try
M.Scale(0.5, 0.5);
M.Translate(0.25 * Pdf1.PageWidth, 0.5 * Pdf1.PageHeight);
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
Pdf1.UpdatePage;
end;
finally
XObj.Free; // sluit de FPDF_XOBJECT-handle
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
De projecten Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp en Demo\CBuilder\WatermarkStamp maken van dit patroon een uitvoerbare workflow: ze maken een doel-PDF en een herbruikbare stempel-PDF, wikkelen de stempelpagina in met CreateXObjectFromPage, voegen hetzelfde Form XObject in op elke doelpagina, passen TPdfMatrix-transformaties toe voor gecentreerde watermerken en stempels rechtsboven en voegen optionele paginanummerlabels toe vóór het opslaan van het resultaat
// AddImage(FileName) accepteert elk formaat dat is geregistreerd bij de
// grafische units van VCL of LCL (BMP, PNG via PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) slaat de tussenstap via TPicture over, ideaal wanneer
// de bitmap al uit rendering- of batch-generatiewerk komt.
var
Bitmap: TBitmap;
begin
Bitmap := Pdf1.RenderPage(0, 0, 595, 842);
try
Pdf1.PageNumber := 2;
Pdf1.AddImage(Bitmap, 50, 50, 250, 350);
Pdf1.UpdatePage;
finally
Bitmap.Free;
end;
end;
De projecten Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF en Demo\Lazarus\ImageToPDF maken hiervan een volledige batchworkflow: selecteer meerdere afbeeldingsbestanden, bekijk het geselecteerde item, maak één PDF-pagina per afbeelding, schaal elke afbeelding in een A4-staand- of liggende pagina, sla het resultaat op en open de gegenereerde PDF
var
MatchCount: Integer;
begin
// Schilder een clYellow-masker over elke match op de huidige pagina van
// de viewer. Wisselen naar een andere pagina wist de markering automatisch.
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d match(es) on this page', [MatchCount]);
// Verwijder de overlay programmatisch voordat de pagina wisselt
PdfView1.ClearHighlight;
end;
// FitMode houdt lange documenten ingekaderd tijdens Resize of paginawisselingen.
// Het rechtstreeks instellen van Zoom annuleert FitMode (wordt teruggezet naar pfmNone).
PdfView1.FitMode := pfmFitPage; // hele pagina in viewport
// PdfView1.FitMode := pfmFitWidth; // paginabreedte komt overeen met viewport-breedte
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor ontkoppelt de gerenderde PDF-pagina van de Color van de host-control
// — een typische donker-thema viewer-opzet houdt het scrollgebied donker terwijl
// de PDF-pagina papierwit blijft.
PdfView1.Color := clBlack; // scrollgebied
PdfView1.PageColor := clWhite; // PDF-pagina-achtergrond
// Optionele slagschaduw en paginarand om de pagina van een donkere achtergrond te tillen
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
De projecten Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab en Demo\Lazarus\Miscellaneous\ViewerInteractionLab houden de moderne TPdfView-interactie-oppervlakte in één compact formulier: open of maak een voorbeeld-PDF, wissel DisplayMode, pas FitMode toe, wijzig PageColor, roteer pagina's, markeer huidige-pagina-zoekresultaten met HighlightSearchText, schakel gebruikerstekstselectie in of uit, inspecteer SelectedText, roep SelectAll, CopySelectionToClipboard en ClearSelection aan, en bekijk hoe DeviceToPage-coördinaten in de statusbalk bijwerken terwijl de muis over de pagina beweegt
De projecten Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect en Demo\Lazarus\SearchAndSelect maken van de viewer-workflow voor zoeken en selecteren standalone voorbeelden. Ze openen of maken een PDF, vermelden zoekresultaten over alle pagina's met paginanummer, karakterindex en voorvertoningstekst, ondersteunen Vorige/Volgende-navigatie en dubbelklik-resultaat-springen, markeren huidige-pagina-matches met HighlightSearchText, stellen hoofdletter-/heel-woord-opties beschikbaar, schakelen AllowUserTextSelection aan/uit, bekijken SelectedText, sturen vanuit knoppen SelectAll, CopySelectionToClipboard en ClearSelection aan, en laten gebruikers wisselen tussen enkele en spread-weergavemodi
De projecten Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences en Demo\Lazarus\Miscellaneous\PrintPreferences lezen auteur-printvoorkeuren vóór het afdrukken. Ze tonen PrintCopies, PrintPageRanges, PrintScaling en PrintPaperHandling, kunnen door de auteur opgegeven kopieën en bereiken kopiëren naar de print-invoeren, en laten zien hoe SetPdfPrintPaperHandlingDevMode de PDF-duplex-intentie vertaalt naar een Windows-DEVMODE
De projecten Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF en Demo\Lazarus\PrintPDF tonen de standaard print-workflow: open een PDF, bekijk pagina's vooraf, kies paginabereiken en kopieën in het platform-printdialoog, respecteer collate-modus, render elke pagina via TPdf.RenderPage en stel printvoortgang beschikbaar met annulering. Het Delphi-voorbeeld accepteert ook gesleepte PDF-bestanden voor snel laden
De projecten Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer en Demo\Lazarus\MultiPageViewer oefenen continue, spread- en omslag-bewuste weergave met reguliere pagina-navigatie- en zoom-workflows. Ze zijn ook nuttig voor het testen van open-to-first-page-snelheid en render-responsiviteit op zeer grote PDF's: in tests met grote bestanden kunnen documenten van 2,x GB die Acrobat of Foxit 20-30 seconden kunnen kosten vóór de eerste weergave, bijna onmiddellijk bruikbaar worden via het viewer-pad van PDFium Delphi Component
De projecten Demo\Delphi\SplitView, Demo\CBuilder\SplitView en Demo\Lazarus\SplitView tonen PDF-beoordeling naast elkaar. De C++Builder- en Lazarus-voorbeelden richten zich op vergelijking in twee of drie panelen, selectie van actieve weergave, optionele gesynchroniseerde navigatie-commando's, gedeelde zoom-presets en rotatie voor de geselecteerde weergave of alle geladen weergaven. Gebruik deze voorbeelden om grote documenten te vergelijken terwijl de eerste bruikbare weergave en daaropvolgende pagina-rendering responsief blijven; dezelfde 2,x GB PDF-bestanden die Acrobat of Foxit 20-30 seconden nodig hebben om te openen, kunnen bijna onmiddellijk bruikbaar worden in het viewer-pad van PDFium Delphi Component
De projecten Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit en Demo\Lazarus\SecurityAudit openen een PDF alleen-lezen en vermelden de status van rechten, ingebedde bijlagen, document-JavaScript-acties, URI- en Launch-linkannotaties, weblinks, samenvattingen van handtekeningen, XFA-status, beschikbaarheid van V8-helpers en niet-ondersteunde-functie-callbacks. Dezelfde samenvattings- en bevindingsrijen kunnen worden opgeslagen of gekopieerd als TXT-auditrapport of als gestructureerd JSON-rapport worden opgeslagen. Ze zijn bedoeld als risico-panelen voor de host-toepassing, niet als malware-detectie
// LinkOptions bestuurt de automatische afhandeling van de vier PDF-link-
// actietypen. Standaardwaarden schakelen alleen goto en URI in; launch
// (een programma uitvoeren) en embedded GotoR (naar een ander bestand
// springen) blijven UIT, zodat een per ongeluk klik geen willekeurige code
// kan uitvoeren.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // veilige standaardwaarden
// OnAnnotationLinkClick vuurt voor bestemmingen binnen het document
// (paginasprongen, benoemde bestemmingen, actie-ketens). Markeer Handled = True
// om te voorkomen dat de viewer de link automatisch volgt.
procedure TForm1.PdfView1AnnotationLinkClick(Sender: TObject;
LinkIndex: Integer; const Action: TPdfAction;
var Handled: Boolean);
begin
if Action.Kind = paUri then
begin
if MessageDlg('Open ' + Action.Uri + '?', mtConfirmation, [mbYes, mbNo], 0)
<> mrYes then
Handled := True; // onderdruk automatische afhandeling
end;
end;
// OnWebLinkClick vuurt voor URI-strings ontdekt door PDFium's weblink-
// scanner (automatisch gedetecteerde URL's in de tekststream, zelfs zonder
// /A <</S/URI...>>-annotatie).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('Web link clicked: ' + string(Url));
end;
// Op het gefocuste AcroForm-widget sturen zes nieuwe methoden de
// formulier-edit-geschiedenis van PDFium aan. Alle zes vallen veilig
// terug wanneer geen widget gefocust is of het document geen AcroForm
// bevat.
procedure TForm1.btnSelectAllClick(Sender: TObject);
begin
PdfView1.SelectAllFormText;
EditMenuCopy.Caption := 'Copy: ' + string(PdfView1.GetSelectedFormText);
end;
procedure TForm1.btnUndoClick(Sender: TObject);
begin
btnUndo.Enabled := PdfView1.FormCanUndo;
btnRedo.Enabled := PdfView1.FormCanRedo;
if PdfView1.FormCanUndo then
PdfView1.FormUndo;
end;
procedure TForm1.btnRedoClick(Sender: TObject);
begin
if PdfView1.FormCanRedo then
PdfView1.FormRedo;
end;
// Alle drie staan standaard op True, zodat bestaande apps zonder
// gedragswijziging upgraden. Zet ze op False voor kiosken, preview-panes
// of alleen-lezen embeds zonder TPdfView te subclassen.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // wiel-omhoog/omlaag-sprongen
PdfView1.AllowUserTextSelection := False; // muis-/toetsenbord-tekstselectie
// Ctrl+wheel is gereserveerd voor zoom en wordt overgeslagen door de
// navigatie-handler ongeacht ChangePageOnMouseScrolling.
// TPdfThumbnailView (unit FPdfThumbnail) rendert één paginaminiatuur per
// rij in een scrollbaar zijpaneel.
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // warme accentkleur
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex is zero-based
end;
procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Patroon gebruikt door Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// en Demo\Lazarus\BatchExport. Één TPdf per bestand, IPdfCancellationToken
// voor cancel-from-UI, TPdfStreamAdapter voor gebufferde file load.
uses FPdfAsync;
procedure ExportBatch(const Files: TArray<string>;
const OutDir: string; DPI: Integer; Quality: Integer;
const ACancelToken: IPdfCancellationToken);
var
I, J: Integer;
Job: TPdf;
Bmp: TBitmap;
Jpeg: TJPEGImage;
begin
for I := 0 to High(Files) do
begin
if ACancelToken.IsCancelled then Break;
OverallProgress.Position := I;
Job := TPdf.Create(nil);
try
Job.FileName := Files[I];
Job.Active := True;
PageProgress.Max := Job.PageCount;
for J := 1 to Job.PageCount do
begin
if ACancelToken.IsCancelled then Break;
PageProgress.Position := J;
Job.PageNumber := J;
Bmp := Job.RenderPage(
0, 0,
Round(Job.PageWidth * DPI / 72),
Round(Job.PageHeight * DPI / 72));
try
Jpeg := TJPEGImage.Create;
try
Jpeg.CompressionQuality := Quality;
Jpeg.Assign(Bmp);
Jpeg.SaveToFile(Format('%s\%s.p%.3d.jpg',
[OutDir, ExtractFileName(Files[I]), J]));
finally
Jpeg.Free;
end;
finally
Bmp.Free;
end;
end;
finally
Job.Free;
end;
end;
end;
procedure FitCurrentPage;
begin
PdfView1.Zoom := PdfView1.PageZoom[PdfView1.PageNumber];
end;
procedure InspectViewerPoint(X, Y: Integer);
var
PageNo: Integer;
PageX, PageY: Double;
CharIndex: Integer;
Ch: WString;
begin
PageNo := PdfView1.PageNumber;
if not PdfView1.DeviceToPage(X, Y, PageNo, PageX, PageY) then
Exit;
CharIndex := PdfView1.CharacterIndexAtPos(X, Y, 8, 8);
if CharIndex >= 0 then
begin
Ch := PdfView1.Text(CharIndex, 1);
ShowMessage(Format('Page %d, X %.2f, Y %.2f, character %s',
[PageNo, PageX, PageY, string(Ch)]));
end;
end;
function LoadPdfSafely(const FileName: string): Boolean;
begin
Result := False;
if not FileExists(FileName) then
Exit;
try
Pdf1.FileName := FileName;
Pdf1.Active := True;
Result := Pdf1.Active;
except
Result := False;
end;
end;
function ExtractTextSafely(PageNo: Integer): WString;
begin
Result := '';
if not Pdf1.Active then
Exit;
if (PageNo < 1) or (PageNo > Pdf1.PageCount) then
Exit;
Pdf1.PageNumber := PageNo;
Result := Pdf1.Text;
end;
// IsTagged is een goedkope catalog-probe — True wanneer /StructTreeRoot
// bestaat. StructureElements materialiseert de boom in een flat array van
// TPdfStructureElement-records met type, title, alternate text, actual
// text, expansion text, language, level, parent index en child / marked
// content / attribute counts.
var
Elements: TPdfStructureElements;
I: Integer;
begin
if not Pdf1.IsTagged then
begin
Log.Add('Document is NOT tagged — accessibility tools may struggle.');
Exit;
end;
if Pdf1.Language = '' then
Log.Add('Tagged PDF without /Lang — fails PDF/UA.');
Elements := Pdf1.StructureElements;
for I := 0 to High(Elements) do
Log.Add(StringOfChar(' ', Elements[I].Level * 2)
+ Elements[I].StructType + ' "' + Elements[I].Title + '"');
end;
// SetPdfPrintMode is een globale functie die overeenkomt met PDFium's
// FPDF_SetPrintMode. Gebruik de bijpassende TPdfPrintMode-waarde voor het
// gebruikte printer-stuurprogramma.
SetPdfPrintMode(pmEmf); // GDI EMF (standaard)
// SetPdfPrintMode(pmTextOnly); // alleen-tekst-rendering
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + image masks
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + Type 42-fonts
// PrintCopies, PrintPageRanges, PrintScaling en PrintPaperHandling zijn
// de viewer-preference-dictionary-entries — ze coderen wat de
// documentauteur wilde dat PDF-readers standaard zouden gebruiken.
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // one-based bereiken
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// JavaScript op documentniveau wordt opgeslagen in de /Names /JavaScript
// name-tree. JavaScriptAction[i] retourneert één entry; JavaScriptActions
// retourneert de volledige array.
var
I: Integer;
Action: TPdfJavaScriptAction;
begin
for I := 0 to Pdf1.JavaScriptActionCount - 1 do
begin
Action := Pdf1.JavaScriptAction[I];
Memo1.Lines.Add('Name: ' + string(Action.Name));
Memo1.Lines.Add('Script: ' + string(Action.Script));
Memo1.Lines.Add('---');
end;
end;
procedure ProcessMultiplePages;
var
I: Integer;
PageText: WString;
begin
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageText := Pdf1.Text;
ProcessPageText(PageText);
end;
end;
procedure SetOptimalRenderOptions;
begin
PdfView1.Options := [reAnnotations, reLcd];
end;
// Zero-copy renderpad (standaard sinds v1.21.0): RenderPage schrijft
// rechtstreeks in de DIB-buffer van de bestemmings-TBitmap wanneer
// aanroepers een vooraf gealloceerde bitmap doorgeven, waarmee één kopie
// van width * height * 4 bytes wordt vermeden.
procedure RenderIntoCallerBitmap(Bitmap: TBitmap);
begin
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Pdf1.RenderPage(Bitmap, 0, 0, Bitmap.Width, Bitmap.Height);
end;