PDFium Delphi Component Docs

PDFium-VCL-Programmierbeispiele

Eine lauffähige Demo auswählen

Die Demosammlung umfasst 32 Themen: 32 Delphi-, 31 C++Builder- und 32 Lazarus-Projekte, insgesamt 95 native Projekte; jede Plattform behält 22 vollständige Workflowdemos im Hauptverzeichnis; zehn fokussierte Themen unter Miscellaneous umfassen 29 native Projekte über die drei Plattformen; XfaLab ist für Delphi und Lazarus verfügbar

Öffnen Sie zuerst einen Workflow aus dem Hauptverzeichnis: PDFViewer für eine Feature-Tour, CreatePDF für Live-Autoring, ContentExtractionLab für ein sofortiges Inventar, FormFill für editierbare Formulare, StandardsLab für Validierung und Konvertierung oder IntakeWorkbenchCli für automatisiertes Intake. Diese sechs Einstiegspunkte liefern sofort brauchbare Ergebnisse; die fokussierten Samples weiter unten sind nützlich, wenn Sie eine einzelne API im Detail untersuchen wollen

Workflow-Demos im Hauptverzeichnis

DemoEinsatzzweckAbgrenzung zu verwandten Demos
PDFViewerAllgemeines Ansehen und FunktionsauswertungDer Haupt-Viewer kombiniert Navigation, Suche, Miniaturansichten, Anzeigemodi, Drucken und ein Showcase der Funktionen
MultiPageViewerFortlaufende Seiten, Spreads und Deckblatt-LayoutsEin fokussiertes Layout-Beispiel mit den integrierten Auswahl-APIs des Viewers; für das breitere Viewer-Erlebnis PDFViewer verwenden
SplitViewSeiten oder Dokumente in getrennten Panels vergleichenZeigt unabhängige Ansichtspositionen und das Weiterleiten von Befehlen an das aktive Panel statt eines Zwei-Seiten-Layouts in einer Ansicht
SearchAndSelectSeitenübergreifende Suchergebnisse und AuswahlEine Ergebnisliste und Suchoptionen legen den Such-Workflow direkter offen als eine Viewer-Symbolleiste
PrintPDFVorschau und normale DruckaufträgeSeitenbereiche, Skalierung, Fortschritt und Abbruch decken den zentralen Druck-Workflow ab
ContentExtractionLabMehrere Inhaltskategorien gemeinsam betrachtenTXT/JSON-Inventare beschreiben Objekte und zeigen Text als Vorschau; sie ersetzen weder den vollständigen Text-Export noch den Export von Bilddateien
ExtractImagesEingebettete Bildobjekte exportierenExtrahiert Bild-Bitmaps statt Screenshots ganzer Seiten; die eingebaute Testdatei enthält auf zwei Seiten jeweils zwei echte Bildobjekte
TableExtractionLabTabellen erkennen und als CSV/JSON exportierenLinien- und Whitespace-Tabellen, verbundene Zellen, Fortsetzungsgruppen und Konfidenz-Regelung sind unabhängig von der reinen Textextraktion
AttachmentEingebettete Anhänge lesen, hinzufügen und exportierenOperationen auf Anhang-Payloads gehen über das Auflisten von Namen und Größen in ContentExtractionLab hinaus
BatchExportSeitenbilder aus mehreren Dokumenten exportierenStreaming-Ausgabe, Status pro Datei und isolierte Fehler demonstrieren Batch-Verarbeitung statt einer einzelnen Konvertierung
CreatePDFSeiteninhalte mit Live-Vorschau erstellenAlle drei nativen Varianten erzeugen durchsuchbaren Text, Vektorformen, ein echtes Rasterbild, Tabellen und eine Review-Annotation; Optionen bauen die Vorschau neu auf, bevor explizit gespeichert wird
ImageToPDFSeiten aus Eingabebilddateien aufbauenBild-Layout, Einpassen, Reihenfolge und JPEG-Behandlung ergeben einen Dokumentkonvertierungs-Workflow
MergePDFSeiten aus mehreren PDFs zusammenfügenDemonstriert Dokument-Import und geordnetes Zusammenfügen; Splitten deckt den umgekehrten Workflow ab
SplitPDFAusgewählte Seitengruppen in separate PDFs schreibenAusgabenamen und Validierung der Seitengruppen unterscheiden sich von Merging und Seitenbild-Rendering
WatermarkStampWiederholte Overlays auf bestehenden Seiten anwendenPlatzierung und Seiten-Stempeln im Batch ergänzen die grundlegenden Autoring-APIs
FormFillInteraktive AcroForm-Eingabe und FlatteningFeldeingaben und gespeicherte Appearances unterscheiden sich von XFDF-Interchange und XFA-spezifischem Verhalten
AccessibilityReaderInteraktives Lesen und SprachausgabeDer GUI-Reader demonstriert Navigation und Hervorheben beim Lesen statt eines Compliance-Audits
AccessibilityWorkbenchCliBarrierefreiheit im Batch prüfen und Berichte erzeugenBefunde, Zusammenfassungen und Review-Gates dienen der Automatisierung; Befunde ersetzen keine manuelle Barrierefreiheits-Prüfung
StandardsLabStandard-spezifische Validierung und KonvertierungDas interaktive Lab legt Operationen und Optionen offen, statt nur einen Aggregatbericht zu erzeugen
PreflightReportInteraktive StandardberichteDie GUI unterstützt manuelle Inspektion und Bericht-Export
PreflightReportCliAutomatisierte StandardberichteBatch-Eingaben, Berichtsformate und Exitcode-Gates bilden das automatisierte Gegenstück zu PreflightReport
IntakeWorkbenchCliIntake, Sichtung und Routing im BatchAggregatberichte, Fehler-Gates und Routing-Entscheidungen machen daraus einen Verarbeitungs-Workflow über die SecurityAudit-GUI hinaus

Fokussierte Samples unter Miscellaneous

Öffnen Sie diese Projekte unter Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous oder Demo\Lazarus\Miscellaneous; sie enthalten nützliche API-Rezepte und schmale Exportaufgaben, während das Hauptverzeichnis vollständige Workflows zeigt; grundlegende Unicode-Prüfungen und der feste Annotationsschreib-/Auflistungsdurchlauf sind durch Erstellung, Extraktion, XFDF-Austausch und API-Tests abgedeckt und haben keine separaten Demoprojekte mehr

DemoEinsatzzweckAbgrenzung zu verwandten Demos
SecurityAuditDie Sicherheitslage interaktiv untersuchenDie GUI betont Berechtigungen, Skripte, Signaturen und Sicherheitsdetails statt Datei-Routing
XfdfLabXFDF-Daten importieren und exportierenInterchange und ein explizites Speichern des importierten PDFs demonstrieren Persistenz; der XFDF-Export allein speichert das veränderte PDF nicht
AccessibilityLabDie Reader-APIs in einer Konsole durchgehenEin kompakter ausführbarer Walkthrough legt Leseeinheiten, Wortboxen, Struktur und Sprach-Skript-Ausgabe offen
ExtractTextVollständigen Text ausgewählter Seiten exportierenTextlayer-Ausgabe, Seitentrennzeichen und Abbruch unterscheiden sich von Inventar-Vorschauen und Tabellenerkennung; OCR wird nicht durchgeführt
FontPropertiesSchrift- und Zeichenmetriken untersuchenStartet mit echten Schrift- und Zeichenmetriken für das erste Textobjekt; wählen Sie eine andere Zeile aus, um Schriften zu vergleichen, ohne Dokument-Payloads zu exportieren
NavigationLabLesezeichen, Ziele und NavigationsaktionenDer kompakte API-Walkthrough ergänzt die sichtbaren Navigationssteuerelemente in PDFViewer
PDFtoJpgEin Dokument in Seitenbilder rendernEin kompaktes Rendering-Beispiel für ein einzelnes Dokument; Delphi legt diskrete Seitenbereiche offen, während BatchExport auf mehrere Eingabedokumente zielt
PrintPreferencesN-up-Blätter und Druckvoreinstellungen des PDF-AutorsKopien, Gerade-/Ungerade-Filterung und vom Autor gesetzte Voreinstellungen stehen im Vordergrund; dies ist eine Ergänzung zu PrintPDF
ViewerInteractionLabDiagnose von Maus-, Tastatur- und Koordinaten-InteraktionenDas Interaktionslog und die Umrechnung zwischen Seiten- und Gerätekoordinaten machen es zu einem API-Diagnosewerkzeug
XfaLabStatische XFA-Pakete und Runtime-FähigkeitenÖffnet Template- und Datasets-Pakete mit der gewöhnlichen Runtime; interaktives XFA-Rendering braucht eine XFA-fähige Runtime, mit Delphi- und Lazarus-Varianten

Mit einer funktionierenden Feature-Tour starten

PDFViewer öffnet sein mitgeliefertes PDFiumDemoShowcase.pdf, ein sechsseitiges Dokument mit durchsuchbarem Text, Vektor-Diagrammen, zwei eingebetteten Bildern, einer Tabelle, vier AcroForm-Feldern, Kapitel-Lesezeichen, Links, einer Review-Notiz und zwei Dateianhängen. Die Experience-Leiste bietet Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF und Explore forms; jede Aktion wirkt auf das aktuell geöffnete Dokument

CreatePDF öffnet eine zweiseitige Live-Vorschau eines Berichts. Bearbeiten Sie Titel und Autor oder schalten Sie Formen, Tabelle und Wasserzeichen um, um echte Seiteninhalte neu aufzubauen; die Unicode-Option fügt eine dritte Seite hinzu. Vor dem Speichern wird nichts geschrieben, und das gespeicherte PDF bleibt durchsuchbar

MultiPageViewer, SearchAndSelect, ContentExtractionLab und FormFill öffnen dasselbe Dokument für ihre jeweiligen Workflows, mit Suchtreffern, einem Extraktions-Inventar und editierbaren Feldern, die sofort bereitstehen. Miscellaneous\NavigationLab verwendet seine eigene lokale Kopie für einen Lesezeichen- und Ziel-API-Walkthrough

Attachment startet mit zwei echten eingebetteten Dateien. PrintPreferences startet mit vier Seiten und Autoren-Vorgaben für zwei Kopien, gewählte Seitenbereiche, Skalierung und Duplex; der aktuelle Druck-Workflow setzt Kopien und Seitenbereiche um, während Skalierung und Duplex geprüft und berichtet werden. XfaLab startet mit echten Template- und Datasets-Paketen für die statische XFA-Inspektion; interaktives XFA-Rendering braucht eine passende Runtime und ist eine eigenständige Fähigkeit

Jedes Ansichts-, Formular-, Extraktions- und Navigationsprojekt enthält sein eigenes PDFiumDemoShowcase.pdf. Kopieren Sie das Projektverzeichnis und lassen Sie diese mitgelieferte Eingabe neben der weitergegebenen ausführbaren Datei liegen; Lazarus-Builds legen sie automatisch daneben ab. Die Tour funktioniert offline, und allgemeine Viewer- und Extraktions-Samples stellen außerdem generierte Fallback-Inhalte bereit, wenn das lokale PDF nicht verfügbar ist

Die nativen Samples kopieren und pflegen

Jedes native Demo enthält seine eigene Sample-Implementierung. Die Delphi- und Lazarus-Einstiegspunkte für AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli und PreflightReportCli enthalten den vollständigen Workflow im Projektverzeichnis, einschließlich der compilerspezifischen Initialisierung und des JPEG-Writers. Die Beispiele für Anhänge, Druckvoreinstellungen und XFA erzeugen ihre funktionsbezogenen Eingaben ebenfalls lokal. Außerhalb des kopierten Projekts werden nur die Bibliothek, die passende native Runtime und die üblichen Compiler-Framework-Abhängigkeiten benötigt

Wählen Sie die Bildobjekt-Extraktion, wenn Sie eingebettete Bitmaps brauchen, das Seiten-Rendering, wenn Sie die sichtbare Seite brauchen, und die Textextraktion, wenn das PDF bereits eine Textebene hat. Ein Bericht, der diese Kategorien auflistet, exportiert nicht ihre vollständigen Payloads. Diese Grenzen halten fokussierte Beispiele nützlich, ohne jedes Demo zu einem weiteren Allzweck-Viewer oder einer weiteren Workbench aufzublähen

Grundlegende Dokumentoperationen

Laden und Anzeigen eines PDF-Dokuments

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;

Neues PDF-Dokument erstellen

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;

Textoperationen

Text aus PDF extrahieren

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;

Text suchen

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;

Text mit Formatierung hinzufügen

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;

Zeichen- und Schriftmetadaten untersuchen

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;

Die Projekte Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties und Demo\Lazarus\Miscellaneous\FontProperties zeigen dieselben Metadaten sowohl über TPdf als auch über TPdfView

Mehrkategorigen Inhalts-Extraktionsbericht erstellen

Die Projekte Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab und Demo\Lazarus\ContentExtractionLab machen aus der Inhaltsextraktion einen einzelnen Workflow. Sie öffnen oder erstellen ein PDF, lassen Benutzer Metadaten, Seitentext, Seitenobjekte, Bilder, Anhänge, Links, Annotationen, Lesezeichen sowie Schrift-/Zeichenmetriken auswählen und generieren dann eine Zusammenfassung sowie einen detaillierten TXT- oder JSON-Bericht. Das Lab enthält außerdem Alle-/Keine-Kategorieauswahl, Bericht-in-Zwischenablage-Kopieren und Aktionen zum Speichern der Quell-PDF, sodass Anwender das generierte Sample-PDF neben dem zugehörigen Extraktionsbericht aufbewahren können. ExtractImages und Attachment bieten Payload-Export-Workflows, während Miscellaneous\ExtractText und Miscellaneous\FontProperties fokussierte API-Beispiele bleiben; ExtractText unterstützt Seitenbereich- und Seitentrennzeichen-Optionen zur Erzeugung seitenweise getrennter Textausgabe in Delphi, C++Builder und Lazarus, während ContentExtractionLab das übergreifende Bestandsbeispiel ist

Tabellen erkennen und extrahieren

Die Projekte Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab und Demo\Lazarus\TableExtractionLab machen aus der Tabellenerkennung einen einzigen Workflow. Das Labor erstellt ein Beispieldokument mit einer Tabelle mit Linien und verbundenen Kopfzellen, einer Tabelle ohne Linien, die über Zwischenräume ausgerichtet ist, und einer langen Tabelle, die über eine Seitengrenze hinweg umbrochen wird, führt dann ExtractTables für die aktuelle Seite oder ExtractDocumentTables für das gesamte Dokument aus und berichtet Zeilen, Spalten, RowSpan- und ColumnSpan-Werte, Kopfzeilen-Flags, Erkennungsmodus, Konfidenz und Fortsetzungsgruppen. Die Optionen DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings und MinConfidence sind in der Benutzeroberfläche bearbeitbar, und die ausgewählte Tabelle wird über TPdfTable.ToCsv und TPdfTable.ToJson exportiert. Das Labor verarbeitet auch einen ganzen Ordner im Batch: Batch folder führt ExtractDocumentTables über jede PDF-Datei aus, berichtet Tabellenanzahlen pro Dokument, markiert Scans ohne Textebene und wiederholt leere Dokumente mit einer Voreinstellung für kompakte Spalten; Export all CSV schreibt jede erkannte Tabelle neben die Quelldateien. Jedes Dokument öffnet in seiner eigenen TPdf-Instanz, damit eine unlesbare Datei den Rest des Batches nicht beeinträchtigen kann

Formularoperationen

Mit Formularfeldern arbeiten

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;

Ausgefüllte Formularwerte in die Seite einbacken

// Ohne Flattening schreibt FormField[i] := value nur den /V-Eintrag —
// das sichtbare Erscheinungsbild stammt aus dem /AP-Stream und wird
// möglicherweise nicht aktualisiert. GenerateFormAppearances regeneriert
// /AP für jedes Widget; anschließend backt FlattenAllPages die Annotationen
// und Widgets jeder Seite dauerhaft als nicht editierbaren Inhalt ein.
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;

Bildoperationen

Bilder extrahieren

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;

Bilder hinzufügen

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;

Annotationsoperationen

Mit Annotationen arbeiten

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;

Zeichenoperationen

Formen zeichnen

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;

Navigation und Lesezeichen

Mit Lesezeichen arbeiten

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;

Mit benannten Zielorten arbeiten

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;

Anhangoperationen

Mit Anhängen arbeiten

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;

Seitenverwaltung

Seitenoperationen

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);

Speichern und Komprimierung

Mit Komprimierung speichern

// Komprimiertes PDF-Dokument erstellen
Pdf1.CreateDocument;
Pdf1.Compressed := True; // sicherstellen, dass alle Streams FlateDecode-komprimiert sind (Standard)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // A4-Größe
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;

// Mit Optionen speichern
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // inkrementelles Speichern
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // Sicherheit entfernen

// Auf eine bestimmte PDF-Zielversion speichern. Die PDF-Versionsprüfung lehnt
// jede Funktion ab, die nach dem gewählten Ziel eingeführt wurde (JBIG2Decode,
// MarkInfo, AES-Verschlüsselung, Polygon-/Caret-/Watermark-/Redact-Annotationen, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
  ShowMessage('Save rejected: document contains features newer than PDF 1.5');

PDF/A-1b-Archivausgabe erstellen

// SaveAsPdfA ergänzt den Basis-Speichervorgang durch ein inkrementelles Update,
// das einen XMP-Metadaten-Stream, ein sRGB-ICC-OutputIntent und einen
// aktualisierten Dokument-Catalog einfügt, sodass das Ergebnis PDF/A-1b-konform
// ist. Das mitgelieferte sRGB-IEC61966-2.1-Profil wird automatisch verwendet,
// wenn kein benutzerdefiniertes Profil bereitgestellt wird.
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 mit einem benutzerdefinierten ICC-Profil (z. B. CMYK-Druckpipelines)
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;

// In-Memory-PDF/A-Ausgabe
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;

PDF/A-Konformität validieren

var
  Validation: TPdfAValidationResult;
  Issue: TPdfAValidationIssue;
begin
  Pdf1.FileName := 'C:\Incoming\report.pdf';
  Pdf1.Active   := True;

  // Günstige Header-Stil-Prüfung — liest die Konformität, ohne den vollen
  // Validator zu durchlaufen. Ergebnis: pacNone, pac1a, pac1b, pac2b, pac3b
  // oder 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;

  // Vollständiger Validator mit detaillierten Befunden pro Issue
  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;

Mehrere PDF-Standards in StandardsLab untersuchen

Die Projekte Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab und Demo\Lazarus\StandardsLab laden oder erstellen ein PDF, führen ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR und ValidatePdfVT aus und zeigen dann jede erkannte Konformitätsstufe und die Issue-Anzahl in einer Tabelle an. Ihre Speichern-Schaltflächen rufen SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR und SaveAsPdfVT auf, sodass der Marker-Output-Workflow sichtbar wird, ohne ein eigenes Test-Harness schreiben zu müssen

Preflight-Berichte erzeugen

Die Unit FPdfPreflightReport fasst ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR und ValidatePdfVT zu einem einzigen abfragbaren Berichtsobjekt mit Info- / Warning- / Error-Schweregraden, Status- und Issue-Aggregation, Lookup, Suche, Filterung und stabilen SHA-256-Fingerprints zusammen. Berichte können als Text, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON oder natives XML ausgegeben werden. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport und Demo\CBuilder\PreflightReport bieten interaktive Auswahl- und Preview-Workflows, während Demo\Delphi\PreflightReportCli skriptfähige Input-/Output-Argumente, Standardfilterung, optionale Berichtsanhang-Einbettung, CI-Gating über Exitcodes, Batch-Listen- und Verzeichnisverarbeitung, kollisionssicheres Routing, Aggregat-Zusammenfassungen und CSV-Manifeste ergänzt. Der erzeugte Bericht weist darauf hin, dass die integrierten Validatoren Marker-Prüfungen und ausgewählte Prüfungen auf Dateiebene abdecken, sodass vollständige Preflight-Prüfungen auf Inhaltsebene weiterhin an eine dedizierte Validierungs-Engine delegiert werden können

Streaming-Laden und große Dokumente

Ein PDF bedarfsweise mit LoadCustomDocument laden

// LoadCustomDocument lässt PDFium Blöcke von einem beliebigen seekbaren
// TStream bedarfsweise abrufen. Der Stream wird NICHT in den Speicher
// kopiert, sodass mehrere Gigabyte große PDFs, Remote-HTTP-Body-Streams
// und datenbankgestützte Quellen alle ohne vorab erstellten Puffer
// nutzbar sind.
var
  FileStream: TFileStream;
begin
  // Streaming aus Datei lesen (keine Speicherkopie)
  FileStream := TFileStream.Create('C:\Huge.pdf',
    fmOpenRead or fmShareDenyWrite);
  Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
  // ^^ Eigentum übertragen — Pdf1 gibt FileStream bei UnloadDocument frei.
  Pdf1.Active := True;
  ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;

// Extern besitzter Stream (Aufrufer gibt ihn nach UnloadDocument frei)
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;

Async-Abbruch und progressives Rendering

Kooperative Cancellation-Tokens

// FPdfAsync stellt IPdfCancellationToken /
// IPdfCancellationTokenSource für Cancel-from-UI-Semantik bereit, die
// über die langlaufenden Export- und Render-Pfade hinweg funktioniert.
uses FPdfAsync;

var
  CancelSource: IPdfCancellationTokenSource;
  CancelToken:  IPdfCancellationToken;
begin
  CancelSource := PdfCancellationTokenSource;
  CancelToken  := CancelSource.Token;

  // ... Benutzer klickt auf Abbrechen ...
  CancelSource.Cancel;

  // Der Worker prüft regelmäßig CancelToken.IsCancelled, oder der Render-
  // Pfad fragt es über PDFiums IFSDK_PAUSE-Callback ab.
  if CancelToken.IsCancelled then
    Memo1.Lines.Add('Cancelled by user');
end;

Abbrechbares progressives Seitenrendering

// RenderPageProgressive ermöglicht es einem langen High-DPI-Rendering,
// mitten in der Seite abzubrechen, wenn der Benutzer Abbrechen klickt,
// anstatt den Aufrufer bis zum Abschluss zu blockieren.
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;

Renderings mit TPdfFuture auf einem Hintergrund-Thread ausführen

// TPdfFuture<T> startet einen Worker auf einem Hintergrund-Thread und
// sendet einen TPdfFutureResult<T>-Envelope zurück an den Haupt-Thread.
//
// Wichtig: TPdf serialisiert Render-Aufrufe pro Instanz, doch der Worker
// besitzt weiterhin den Dispatch und die Dokumentlebensdauer. Mutieren Sie
// keinen TPdf während eines laufenden Renderings; Batch-Exporte halten
// üblicherweise eine TPdf pro Datei.
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;

Transformationsmatrizen

Komposition von Translate / Scale / Rotate / Skew

// FPdfMatrix umschließt PDFiums FS_MATRIX, sodass Aufrufer eine
// Transformation deklarativ aufbauen und an FPDFPageObj_SetMatrix
// übergeben können.
uses FPdfMatrix, FPdfView;

var
  M: TPdfMatrix;
  RawMatrix: FS_MATRIX;
  PageObj: FPDF_PAGEOBJECT;
begin
  M := TPdfMatrix.Create;
  try
    M.Translate(72, 200);       // 1 Zoll nach rechts, ~2,8 Zoll nach oben verschieben
    M.Scale(0.5, 0.5);          // halb großer Stempel
    M.Rotate(15);               // 15-Grad-Drehung gegen Uhrzeigersinn
    // M.HorizontalFlip;
    // M.VerticalFlip;
    // M.CentralFlip;
    // M.Skew(10, 5);
    // M.Multiply(Other);       // mit einer anderen Matrix post-multiplizieren

    // Auf ein beliebiges PDFium-Seitenobjekt anwenden (Text / Pfad / Bild / Form XObject)
    RawMatrix := M.Handle;
    FPDFPageObj_SetMatrix(PageObj, RawMatrix);
  finally
    M.Free;
  end;
end;

Seitenkomposition

Teilmenge von Seiten nach Index importieren

// ImportPagesByIndex kopiert ein explizites null-basiertes Index-Array
// aus einem Quell-PDF in dieses Dokument. InsertAt = 0 fügt vor Seite 1
// ein; PageCount hängt an.
var
  Source: TPdf;
begin
  Source := TPdf.Create(nil);
  try
    Source.FileName := 'C:\Report.pdf';
    Source.Active   := True;

    // Seiten 0, 2, 4 (eins-basiert: Seiten 1, 3, 5) aus Source importieren
    // und am Ende von Pdf1 anhängen.
    Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);

    // Leeres Array importiert jede Quellseite
    // Pdf1.ImportPagesByIndex(Source, [], 0);
  finally
    Source.Free;
  end;
end;

N-up-Kompositionsausgabe

// ImportNPagesToOne liefert ein brandneues TPdf, dessen Seiten NumX*NumY-
// Kompositionen DIESES Dokuments sind. OutputWidth/Height sind PDF-
// Benutzereinheiten (1 Einheit = 1/72 Zoll).
var
  Composite: TPdf;
begin
  Pdf1.FileName := 'C:\Slides.pdf';
  Pdf1.Active   := True;
  // 4-up A4 Querformat: 842 x 595 pt, 2 Spalten x 2 Zeilen
  Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
  try
    if Composite <> nil then
      Composite.SaveAs('C:\Slides_4up.pdf');
  finally
    Composite.Free;
  end;
end;

Seiten an Ort und Stelle umsortieren

// MovePages nimmt die null-basierten Indizes der zu verschiebenden Seiten
// sowie den Zielindex für die erste verschobene Seite nach Abschluss der
// Verschiebung entgegen. Andere Seiten verschieben sich um den
// verschobenen Block herum, sodass die Dokumentlänge gleich bleibt.
//
// Beispiel: In einem 5-Seiten-Dokument mit Seiten [0,1,2,3,4]
// ordnet MovePages([2, 3], 0) zu [2, 3, 0, 1, 4] um.
if not Pdf1.MovePages([2, 3], 0) then
  ShowMessage('Invalid indices passed to MovePages');

Wasserzeichen über Wiederverwendung als Form XObject

// CreateXObjectFromPage erzeugt ein wiederverwendbares Form-XObject-Handle
// aus einer beliebigen Seite eines beliebigen anderen TPdf. Stempeln Sie
// dieses Handle auf so viele Seiten DIESES Dokuments wie Sie möchten —
// jeder Stempel ist ein einzelnes PDFium-Seitenobjekt, das über die
// Matrix-API positioniert, skaliert und gedreht werden kann.
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;

    // Seite 0 von WatermarkSource als wiederverwendbares XObject einhüllen
    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;

        // Wasserzeichen auf der Seite zentrieren
        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; // schließt das FPDF_XOBJECT-Handle
    end;

    Pdf1.SaveAs('C:\Watermarked.pdf');
  finally
    WatermarkSource.Free;
  end;
end;

Die Projekte Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp und Demo\CBuilder\WatermarkStamp verwandeln dieses Muster in einen lauffähigen Workflow: Sie erstellen ein Ziel-PDF und ein wiederverwendbares Stempel-PDF, hüllen die Stempel-Seite mit CreateXObjectFromPage ein, fügen dasselbe Form XObject auf jeder Zielseite ein, wenden TPdfMatrix-Transformationen für zentrierte Wasserzeichen und Stempel oben rechts an und fügen vor dem Speichern des Ergebnisses optionale Seitenzahl-Beschriftungen hinzu

Bildeinfügung (Direkte AddImage-Overloads)

Eine registrierte Bilddatei oder ein TBitmap hinzufügen

// AddImage(FileName) akzeptiert jedes Format, das mit den VCL- oder LCL-
// Grafikunits registriert ist (BMP, PNG über PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);

// AddImage(TBitmap) überspringt den TPicture-Zwischenschritt, ideal wenn
// das Bitmap bereits aus Rendering- oder Batch-Generierungsarbeiten stammt.
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;

Die Projekte Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF und Demo\Lazarus\ImageToPDF machen daraus einen vollständigen Batch-Workflow: mehrere Bilddateien auswählen, das ausgewählte Element vorschauen, eine PDF-Seite pro Bild erstellen, jedes Bild in eine A4-Seite im Hoch- oder Querformat skalieren, das Ergebnis speichern und das erzeugte PDF öffnen

Viewer-Such-Hervorhebung

Jeden Treffer auf der aktuellen Seite hervorheben

var
  MatchCount: Integer;
begin
  // Eine clYellow-Maske über jeden Treffer auf der aktuellen Ansichtsseite zeichnen.
  // Beim Wechsel zu einer anderen Seite wird die Hervorhebung automatisch gelöscht.
  PdfView1.HighlightColor := clYellow;
  MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
  Status.Caption := Format('%d match(es) on this page', [MatchCount]);

  // Das Overlay programmgesteuert vor einem Seitenwechsel entfernen
  PdfView1.ClearHighlight;
end;

Viewer-Layout und Seitenfarbe

Fit-Mode und Seitenhintergrund

// FitMode hält lange Dokumente bei Resize oder Seitenwechseln gerahmt.
// Das direkte Setzen von Zoom hebt FitMode auf (er wechselt zurück zu pfmNone).
PdfView1.FitMode := pfmFitPage;       // gesamte Seite im Ansichtsbereich
// PdfView1.FitMode := pfmFitWidth;   // Seitenbreite entspricht Ansichtsbereichsbreite
// PdfView1.FitMode := pfmActualSize; // 100 %

// PageColor trennt die gerenderte PDF-Seite von der Color des Host-Steuerelements
// — typische Dark-Mode-Viewer-Einrichtung hält den Bildlaufbereich dunkel,
// während die PDF-Seite papierweiß bleibt.
PdfView1.Color     := clBlack;        // Bildlaufbereich
PdfView1.PageColor := clWhite;        // PDF-Seitenhintergrund

// Optionaler Schlagschatten und Seitenrahmen, um die Seite von einem dunklen
// Hintergrund abzuheben
PdfView1.PageShadowSize  := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;

Viewer-Interaktion in ViewerInteractionLab erkunden

Die Projekte Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab und Demo\Lazarus\Miscellaneous\ViewerInteractionLab halten die moderne Interaktionsoberfläche von TPdfView in einem kompakten Formular zusammen: ein Sample-PDF öffnen oder erstellen, DisplayMode umschalten, FitMode anwenden, PageColor ändern, Seiten drehen, Suchtreffer der aktuellen Seite mit HighlightSearchText hervorheben, Benutzer-Textauswahl aktivieren oder deaktivieren, SelectedText untersuchen, SelectAll, CopySelectionToClipboard und ClearSelection aufrufen und beobachten, wie sich die DeviceToPage-Koordinaten in der Statusleiste aktualisieren, während sich die Maus über die Seite bewegt

Text in SearchAndSelect suchen und auswählen

Die Projekte Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect und Demo\Lazarus\SearchAndSelect machen aus dem Such- und Auswahl-Viewer-Workflow eigenständige Beispiele. Sie öffnen oder erstellen ein PDF, listen seitenübergreifende Suchergebnisse mit Seitennummer, Zeichenindex und Vorschautext auf, unterstützen Vorheriger-/Nächster-Navigation und Doppelklick-Sprung zum Treffer, heben Treffer der aktuellen Seite mit HighlightSearchText hervor, stellen Match-Case- und Whole-Word-Optionen bereit, schalten AllowUserTextSelection um, zeigen eine Vorschau von SelectedText, steuern SelectAll, CopySelectionToClipboard und ClearSelection über Schaltflächen und ermöglichen Benutzern den Wechsel zwischen Einzel- und Spread-Anzeigemodi

PDF-Druckvoreinstellungen in PrintPreferences lesen

Die Projekte Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences und Demo\Lazarus\Miscellaneous\PrintPreferences lesen die Druckvoreinstellungen des Autors vor dem Drucken. Sie zeigen PrintCopies, PrintPageRanges, PrintScaling und PrintPaperHandling an, können die vom Autor bereitgestellten Kopien und Bereiche in die Druckeingaben übernehmen und veranschaulichen, wie SetPdfPrintPaperHandlingDevMode die PDF-Duplex-Intent auf ein Windows-DEVMODE abbildet

Standard-PDF-Druck in PrintPDF

Die Projekte Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF und Demo\Lazarus\PrintPDF zeigen den Standard-Druck-Workflow: ein PDF öffnen, Seiten vorschauen, Seitenbereiche und Kopien im plattform-eigenen Druckdialog wählen, Collate-Modus respektieren, jede Seite über TPdf.RenderPage rendern und Druckfortschritt mit Abbruch bereitstellen. Das Delphi-Beispiel akzeptiert außerdem per Drag-and-Drop fallengelassene PDF-Dateien zum schnellen Laden

Schnelles mehrseitiges Anzeigen in MultiPageViewer

Die Projekte Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer und Demo\Lazarus\MultiPageViewer üben fortlaufendes, Spread- und deckblattbewusstes Betrachten mit regulären Seitennavigations- und Zoom-Workflows. Sie eignen sich auch zum Testen der Open-to-First-Page-Geschwindigkeit und der Rendering-Reaktionsfähigkeit bei sehr großen PDFs: In Tests mit großen Dateien können 2.x GB große Dokumente, bei denen Acrobat oder Foxit 20-30 Sekunden bis zur ersten Ansicht brauchen, über den PDFium Delphi Component-Viewer-Pfad nahezu sofort nutzbar werden

Nebeneinander-Prüfung in SplitView

Die Projekte Demo\Delphi\SplitView, Demo\CBuilder\SplitView und Demo\Lazarus\SplitView zeigen Nebeneinander-PDF-Prüfung. Die C++Builder- und Lazarus-Beispiele konzentrieren sich auf Zwei- oder Drei-Panel-Vergleich, Auswahl der aktiven Ansicht, optionale synchronisierte Navigationsbefehle, gemeinsame Zoom-Voreinstellungen und Drehung für die ausgewählte Ansicht oder alle geladenen Ansichten. Verwenden Sie diese Beispiele, um große Dokumente zu vergleichen und dabei die erste nutzbare Ansicht sowie das nachfolgende Seitenrendering reaktionsfähig zu halten; dieselben 2.x GB großen PDF-Dateien, für die Acrobat oder Foxit 20-30 Sekunden zum Öffnen brauchen, können im PDFium Delphi Component-Viewer-Pfad nahezu sofort nutzbar werden

PDF-Risikofläche in SecurityAudit prüfen

Die Projekte Demo\Delphi\Miscellaneous\SecurityAudit, Demo\CBuilder\Miscellaneous\SecurityAudit und Demo\Lazarus\Miscellaneous\SecurityAudit öffnen PDF schreibgeschützt und listen Berechtigungen, eingebettete Anhänge, Dokument-JavaScript, URI-/Launch-Linkannotationen, Weblinks, Signaturübersichten, XFA-Status, V8-Helperverfügbarkeit und Unsupported-Feature-Callbacks; dieselben Übersichts-/Fundzeilen lassen sich als TXT-Bericht speichern oder kopieren oder als strukturiertes JSON speichern; dies sind Risikopanels für Hostanwendungen, keine Malwareerkennung

Viewer-Link-Behandlung

Sicheres Click-to-Follow mit aktionsspezifischen Erlaubnislisten

// LinkOptions steuert die automatische Behandlung der vier PDF-Link-Aktionstypen.
// Standardmäßig sind nur goto und URI aktiviert; launch (ein Programm starten) und
// embedded GotoR (zu einer anderen Datei springen) bleiben AUS, sodass ein
// versehentlicher Klick keinen beliebigen Code ausführen kann.
PdfView1.LinkOptions :=
  [loAutoGoto, loAutoOpenURI];  // sichere Standardwerte

// OnAnnotationLinkClick wird für In-Dokument-Ziele ausgelöst (Seitensprünge,
// benannte Zielorte, Aktionsketten). Setzen Sie Handled = True, um zu verhindern,
// dass die Ansicht den Link automatisch verfolgt.
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;  // automatische Behandlung unterdrücken
  end;
end;

// OnWebLinkClick wird für URI-Strings ausgelöst, die vom Web-Link-Scanner von
// PDFium entdeckt wurden (automatisch erkannte URLs im Textstream, auch ohne
// /A <</S/URI...>>-Annotation).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
  WebLinkIndex: Integer; const Url: WString;
  var Handled: Boolean);
begin
  Log.Add('Web link clicked: ' + string(Url));
end;

Viewer-Formular-Widget-Bearbeitung

Auswahl und Undo / Redo

// Auf dem fokussierten AcroForm-Widget steuern sechs neue Methoden die
// Formular-Bearbeitungshistorie von PDFium. Alle sechs verhalten sich sicher
// als No-op, wenn kein Widget fokussiert ist oder das Dokument kein AcroForm
// enthält.
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;

Den Viewer für Kioske sperren

Seitennavigationsgesten deaktivieren

// Alle drei stehen standardmäßig auf True, sodass bestehende Apps ohne
// Verhaltensänderung aktualisieren. Setzen Sie sie auf False für Kioske,
// Vorschaupanels oder schreibgeschützte Einbettungen ohne Subclassing von
// TPdfView.
PdfView1.AllowUserPageChange       := False;  // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // Mausrad hoch/runter springt Seiten
PdfView1.AllowUserTextSelection    := False;  // Maus/Tastatur-Textauswahl

// Ctrl+Mausrad ist für Zoom reserviert und wird vom Navigations-Handler
// unabhängig von ChangePageOnMouseScrolling übersprungen.

Miniaturansicht-Seitenpanel

Eine TPdfThumbnailView mit einer TPdfView verknüpfen

// TPdfThumbnailView (Unit FPdfThumbnail) rendert eine Seiten-Miniaturansicht
// pro Zeile in einem scrollbaren Seitenpanel.
uses FPdfThumbnail;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ThumbView.Pdf              := Pdf1;
  ThumbView.ThumbnailWidth   := 120;
  ThumbView.ThumbnailHeight  := 160;
  ThumbView.SelectionColor   := $00CFA85F;  // warme Hervorhebung
  ThumbView.OnPageClick      := ThumbViewPageClick;
end;

procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
  PdfView1.PageNumber := PageIndex + 1; // PageIndex ist null-basiert
end;

procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
  ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;

Kooperativ abbrechbarer Batch-Export

Mehrdatei-PDF-zu-JPG mit Fortschritt pro Datei und pro Seite

// Muster, verwendet von Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// und Demo\Lazarus\BatchExport. Eine TPdf pro Datei, IPdfCancellationToken
// für Cancel-from-UI, TPdfStreamAdapter für gepuffertes Dateiladen.
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;

Viewer-Koordinaten und Hit-Testing

Die aktuelle Seite anpassen und Text unter der Maus untersuchen

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;

Fehlerbehandlung

Robuste PDF-Operationen

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;

Tagged PDF und Barrierefreiheit

Tagged PDF erkennen und den Strukturbaum durchlaufen

// IsTagged ist eine günstige Catalog-Prüfung — True, wenn /StructTreeRoot
// existiert. StructureElements materialisiert den Baum in ein flaches Array
// von TPdfStructureElement-Records mit Typ, Titel, Alternativtext, Actual
// Text, Expansionstext, Sprache, Ebene, Eltern-Index und Zählungen für
// Children / Marked Content / Attribute.
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;

Druckmodus-Auswahl

EMF / PostScript / Image-Mask-Druckmodus festlegen

// SetPdfPrintMode ist eine globale Funktion, die auf PDFiums
// FPDF_SetPrintMode abbildet. Verwenden Sie den passenden TPdfPrintMode-Wert
// für den eingesetzten Druckertreiber.
SetPdfPrintMode(pmEmf);                   // GDI EMF (Standard)
// SetPdfPrintMode(pmTextOnly);           // nur-Text-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-Schriftarten

Vom Autor beabsichtigte Druckeinstellungen lesen

// PrintCopies, PrintPageRanges, PrintScaling und PrintPaperHandling sind
// die Einträge des Viewer-Preference-Dictionary — sie kodieren, was der
// Dokumentautor als Standard für PDF-Reader gewünscht hat.
var
  Ranges: TPrintPageRanges;
  Range: TPrintPageRange;
begin
  ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
  ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
    Ord(Pdf1.PrintScaling)));

  Ranges := Pdf1.PrintPageRanges; // eins-basierte Bereiche
  for Range in Ranges do
    Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));

  if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
    ApplyPrinterDevMode(PrinterDevMode);
end;

Dokument-JavaScript-Aktionen

JavaScript der Namensbaumstruktur auflisten

// JavaScript auf Dokumentebene wird im /Names /JavaScript-Namensbaum
// gespeichert. JavaScriptAction[i] liefert einen Eintrag;
// JavaScriptActions liefert das vollständige 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;

Leistungstipps

PDF-Operationen optimieren

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-Render-Pfad (Standard seit v1.21.0): RenderPage schreibt direkt
// in den DIB-Puffer des Ziel-TBitmap, wenn Aufrufer ein vorab allokiertes
// Bitmap übergeben, und vermeidet so eine Kopie von Breite * Höhe * 4 Bytes.
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;