PDFium Delphi Component Docs

Παραδείγματα προγραμματισμού PDFium VCL

Βασικές λειτουργίες εγγράφων

Φόρτωση και προβολή ενός εγγράφου PDF

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;

Δημιουργία νέου εγγράφου PDF

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;

Λειτουργίες κειμένου

Εξαγωγή κειμένου από PDF

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;

Τα έργα Demo\Delphi\FontProperties, Demo\CBuilder\FontProperties και Demo\Lazarus\FontProperties δείχνουν τα ίδια μεταδεδομένα τόσο μέσω του TPdf όσο και μέσω του TPdfView

Δημιουργία αναφοράς εξαγωγής περιεχομένου πολλών κατηγοριών

Τα έργα Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab και Demo\Lazarus\ContentExtractionLab μετατρέπουν την εξαγωγή περιεχομένου σε ενιαίο workflow. Ανοίγουν ή δημιουργούν ένα PDF, αφήνουν τους χρήστες να επιλέξουν μεταδεδομένα, κείμενο σελίδας, page objects, εικόνες, attachments, συνδέσμους, σχόλια, bookmarks και μετρικές γραμματοσειράς / χαρακτήρων, και έπειτα παράγουν σύνοψη μαζί με αναλυτική αναφορά TXT ή JSON. Το lab περιλαμβάνει επίσης επιλογή κατηγοριών όλων / καμία, αντιγραφή της αναφοράς στο πρόχειρο και ενέργειες αποθήκευσης του source PDF ώστε οι χρήστες να κρατούν το παραγόμενο δείγμα PDF δίπλα στην αναφορά εξαγωγής του. Τα παλαιότερα demos ExtractText, ExtractImages, Attachment και FontProperties παραμένουν εστιασμένα παραδείγματα · το ExtractText υποστηρίζει επιλογές page-range και page-separator για παραγωγή εξόδου κειμένου ανά σελίδα σε Delphi, C++Builder και Lazarus, ενώ το ContentExtractionLab είναι το διαθεματικό δείγμα απογραφής

Ανίχνευση και εξαγωγή πινάκων

Τα έργα Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab και Demo\Lazarus\TableExtractionLab μετατρέπουν την ανίχνευση πινάκων σε μία μόνο ροή εργασίας. Το εργαστήριο χτίζει ένα δείγμα εγγράφου που περιέχει πίνακα με γραμμές και συγχωνευμένα κελιά επικεφαλίδας, πίνακα στοιχισμένο με κενά χωρίς γραμμές και έναν μακρύ πίνακα που κόβεται στα όρια μιας σελίδας, και μετά εκτελεί ExtractTables για την τρέχουσα σελίδα ή ExtractDocumentTables για όλο το έγγραφο και αναφέρει γραμμές, στήλες, τιμές RowSpan και ColumnSpan, σημαίες επικεφαλίδας, λειτουργία ανίχνευσης, εμπιστοσύνη και ομάδες συνέχειας. Οι επιλογές DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings και MinConfidence είναι επεξεργάσιμες στο περιβάλλον εργασίας, και ο επιλεγμένος πίνακας εξάγεται μέσω TPdfTable.ToCsv και TPdfTable.ToJson. Το εργαστήριο επεξεργάζεται δέσμια και έναν ολόκληρο φάκελο: το Batch folder εκτελεί ExtractDocumentTables σε κάθε PDF, αναφέρει τον αριθμό πινάκων ανά έγγραφο, σηματοδοτεί σαρώσεις χωρίς στρώμα κειμένου και ξαναδοκιμάζει κενά έγγραφα με προεπιλογή συμπαγών στηλών· το Export all CSV γράφει κάθε ανιχνευμένο πίνακα δίπλα στα αρχεία προέλευσης. Κάθε έγγραφο ανοίγει στη δική του παρουσία TPdf, ώστε ένα μη αναγνώσιμο αρχείο να μην μπορεί να επηρεάσει την υπόλοιπη δέσμη

Λειτουργίες φορμών

Εργασία με πεδία φόρμας

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;

Ενσωμάτωση συμπληρωμένων τιμών φόρμας στη σελίδα

// Without flattening, FormField[i] := value writes only the /V entry —
// the visible appearance comes from the /AP stream and may not refresh
// GenerateFormAppearances regenerates /AP for every widget, then
// FlattenAllPages bakes every page's annotations and widgets into
// permanent, non-editable content
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := 'john@example.com';
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);

Αποθήκευση και συμπίεση

Αποθήκευση με συμπίεση

// Create a compressed PDF document
Pdf1.CreateDocument;
Pdf1.Compressed := True; // ensure all streams are FlateDecode compressed (default)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // A4 size
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;

// Save with options
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // incremental save
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // remove security

// Save to a specific PDF version target. The PDF version validator rejects
// any feature introduced after the chosen target (JBIG2Decode, MarkInfo,
// AES encryption, Polygon / Caret / Watermark / Redact annotations, ...)
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
  ShowMessage('Save rejected: document contains features newer than PDF 1.5');

Δημιουργία αρχειακής εξόδου PDF/A-1b

// SaveAsPdfA post-processes the base save with an incremental update that
// injects an XMP metadata stream, an sRGB ICC OutputIntent, and an updated
// document catalog so the result is PDF/A-1b conformant. The bundled
// sRGB IEC61966-2.1 profile is used automatically when no custom profile
// is supplied
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 with a custom ICC profile (CMYK printing pipelines for example)
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 output
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

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

  // Cheap header-style probe — reads the conformance without iterating
  // the full validator. Result: pacNone, pac1a, pac1b, pac2b, pac3b, or
  // 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;

  // Full validator with per-issue diagnostics
  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;

Έλεγχος πολλών προτύπων PDF στο StandardsLab

Τα έργα Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab και Demo\Lazarus\StandardsLab φορτώνουν ή δημιουργούν ένα PDF, εκτελούν τα ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR και ValidatePdfVT και εμφανίζουν κάθε εντοπισμένο επίπεδο συμμόρφωσης και πλήθος προβλημάτων σε ένα πλέγμα. Τα κουμπιά αποθήκευσής τους καλούν τα SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR και SaveAsPdfVT, ώστε η ροή εργασίας έξοδου δεικτών να είναι ορατή χωρίς τη συγγραφή προσαρμοσμένου harness

Δημιουργία αναφορών preflight

Η μονάδα FPdfPreflightReport τυλίγει τα ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR και ValidatePdfVT σε ένα αντικείμενο αναφοράς με δυνατότητα ερωτημάτων, με σοβαρότητα Info / Warning / Error, συσσώρευση κατάστασης και προβλημάτων, αναζήτηση με κλειδί, αναζήτηση, φιλτράρισμα και στατικά αποτυπώματα SHA-256. Οι αναφορές μπορούν να εκπεμφθούν ως text, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON ή εγγενές XML. Τα Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport και Demo\CBuilder\PreflightReport προσφέρουν διαδραστικές ροές επιλογής και προεπισκόπησης, ενώ το Demo\Delphi\PreflightReportCli προσθέτει scriptable ορίσματα εισόδου / εξόδου, τυπικό φιλτράρισμα, προαιρετική ενσωμάτωση επισύναψης αναφοράς, gating με κωδικό εξόδου για CI, επεξεργασία batch list και καταλόγων, δρομολόγηση ασφαλές ως προς τις συγκρούσεις, συγκεντρωτικές συνοψίες και CSV manifests. Η παραγόμενη αναφορά δηλώνει ότι οι ενσωματωμένοι επικυρωτές καλύπτουν ελέγχους επιπέδου δεικτών και επιλεγμένους ελέγχους επιπέδου αρχείου, ώστε το πλήρες preflight επιπέδου περιεχομένου να μπορεί ακόμα να ανατεθεί σε ειδικευμένη μηχανή επικύρωσης

Φόρτωση με ροή και μεγάλα έγγραφα

Φόρτωση PDF κατ' απαίτηση με LoadCustomDocument

// LoadCustomDocument lets PDFium pull blocks from any seekable TStream on
// demand. The stream is NOT copied into memory, so multi-GB PDFs, remote
// HTTP body streams, and database-backed sources are all viable without
// an up-front buffer
var
  FileStream: TFileStream;
begin
  // Read-from-file streaming (no in-memory copy)
  FileStream := TFileStream.Create('C:\Huge.pdf',
    fmOpenRead or fmShareDenyWrite);
  Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
  // ^^ ownership transferred — Pdf1 frees FileStream on UnloadDocument
  Pdf1.Active := True;
  ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;

// Externally-owned stream (caller frees it after 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;

Ασύγχρονη ακύρωση και προοδευτική απόδοση

Συνεργατικά tokens ακύρωσης

// FPdfAsync exposes IPdfCancellationToken /
// IPdfCancellationTokenSource for cancel-from-UI semantics that work
// across the long-running export and render paths
uses FPdfAsync;

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

  // user clicks Cancel
  CancelSource.Cancel;

  // The worker periodically checks CancelToken.IsCancelled, or the render
  // path polls it through PDFium's IFSDK_PAUSE callback
  if CancelToken.IsCancelled then
    Memo1.Lines.Add('Cancelled by user');
end;

Προοδευτική απόδοση σελίδας με δυνατότητα ακύρωσης

// RenderPageProgressive lets a long high-DPI render abort mid-page when
// the user clicks Cancel, instead of blocking the caller until done
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

// TPdfFuture<T> spins up a worker on a background thread and posts a
// TPdfFutureResult<T> envelope back to the main thread
//
// Important: TPdf serializes render calls per instance, but the worker still
// owns dispatch and document lifetime. Do not mutate a TPdf while a render is
// in flight; batch export usually keeps one TPdf per file
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;

Πίνακες μετασχηματισμού

Σύνθεση Translate / Scale / Rotate / Skew

// FPdfMatrix wraps PDFium's FS_MATRIX so callers can build a transform
// declaratively and hand it to FPDFPageObj_SetMatrix
uses FPdfMatrix, FPdfView;

var
  M: TPdfMatrix;
  RawMatrix: FS_MATRIX;
  PageObj: FPDF_PAGEOBJECT;
begin
  M := TPdfMatrix.Create;
  try
    M.Translate(72, 200);       // move 1in right, ~2.8in up
    M.Scale(0.5, 0.5);          // half-size stamp
    M.Rotate(15);               // 15-degree CCW rotation
    // M.HorizontalFlip;
    // M.VerticalFlip;
    // M.CentralFlip;
    // M.Skew(10, 5);
    // M.Multiply(Other);       // post-multiply with another matrix

    // Apply to any PDFium page object (text / path / image / form XObject)
    RawMatrix := M.Handle;
    FPDFPageObj_SetMatrix(PageObj, RawMatrix);
  finally
    M.Free;
  end;
end;

Σύνθεση σελίδων

Εισαγωγή υποσυνόλου σελίδων ανά δείκτη

// ImportPagesByIndex copies an explicit zero-based index array from a
// source PDF into this document. InsertAt = 0 inserts before page 1;
// PageCount appends
var
  Source: TPdf;
begin
  Source := TPdf.Create(nil);
  try
    Source.FileName := 'C:\Report.pdf';
    Source.Active   := True;

    // Import pages 0, 2, 4 (one-based: pages 1, 3, 5) from Source
    // and append them at the end of Pdf1
    Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);

    // Empty array imports every source page
    // Pdf1.ImportPagesByIndex(Source, [], 0);
  finally
    Source.Free;
  end;
end;

Έξοδος σύνθεσης N-up

// ImportNPagesToOne returns a brand-new TPdf whose pages are NumX*NumY
// composites of THIS document. OutputWidth/Height are PDF user units
// (1 unit = 1/72 in)
var
  Composite: TPdf;
begin
  Pdf1.FileName := 'C:\Slides.pdf';
  Pdf1.Active   := True;
  // 4-up A4 landscape: 842 x 595 pt, 2 columns x 2 rows
  Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
  try
    if Composite <> nil then
      Composite.SaveAs('C:\Slides_4up.pdf');
  finally
    Composite.Free;
  end;
end;

Αναδιάταξη σελίδων επί τόπου

// MovePages takes the zero-based indices of the pages to move plus the
// destination index for the first moved page after the move completes
// Other pages shift around the moved block so the document length stays
// the same
//
// Example: in a 5-page document with pages numbered [0,1,2,3,4],
// MovePages([2, 3], 0) reorders to [2, 3, 0, 1, 4]
if not Pdf1.MovePages([2, 3], 0) then
  ShowMessage('Invalid indices passed to MovePages');

Υδατογράφημα μέσω επαναχρησιμοποίησης σελίδας Form XObject

// CreateXObjectFromPage manufactures a reusable Form XObject handle from
// any page of any other TPdf. Stamp that handle onto as many pages of
// THIS document as you want — each stamp is a single PDFium page object
// that can be positioned, scaled, and rotated through the 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;

    // Wrap page 0 of WatermarkSource as a reusable 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;

        // Centre the watermark on the page
        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; // closes the FPDF_XOBJECT handle
    end;

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

Τα έργα Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp και Demo\CBuilder\WatermarkStamp μετατρέπουν αυτό το μοτίβο σε εκτελέσιμη ροή εργασίας: δημιουργούν ένα PDF στόχο και ένα επαναχρησιμοποιήσιμο PDF σφραγίδας, τυλίγουν τη σελίδα της σφραγίδας με το CreateXObjectFromPage, εισάγουν το ίδιο Form XObject σε κάθε σελίδα στόχο, εφαρμόζουν μετασχηματισμούς TPdfMatrix για κεντραρισμένα υδατογραφήματα και σφραγίδες πάνω δεξιά και προσθέτουν προαιρετικές ετικέτες αριθμού σελίδας πριν την αποθήκευση του αποτελέσματος

Εισαγωγή εικόνων (άμεσες υπερφορτώσεις AddImage)

Προσθήκη καταχωρισμένου αρχείου εικόνας ή TBitmap

// AddImage(FileName) accepts any format registered with the VCL or LCL
// graphics units (BMP, PNG via PngImage, JPG, ...)
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);

// AddImage(TBitmap) skips the TPicture intermediary, ideal when the
// bitmap already comes from rendering or batch generation work
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;

Τα έργα Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF και Demo\Lazarus\ImageToPDF μετατρέπουν αυτό σε πλήρη ομαδική ροή εργασίας: επιλογή πολλών αρχείων εικόνων, προεπισκόπηση του επιλεγμένου στοιχείου, δημιουργία μιας σελίδας PDF ανά εικόνα, κλιμάκωση κάθε εικόνας σε κατακόρυφη ή οριζόντια σελίδα A4, αποθήκευση του αποτελέσματος και άνοιγμα του παραγόμενου PDF

Επισήμανση αναζήτησης στον viewer

Επισήμανση κάθε αντιστοιχίας στην τρέχουσα σελίδα

var
  MatchCount: Integer;
begin
  // Paint a clYellow mask over every match on the view's current page
  // Switching to a different page clears the highlight automatically
  PdfView1.HighlightColor := clYellow;
  MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
  Status.Caption := Format('%d match(es) on this page', [MatchCount]);

  // Programmatically remove the overlay before the page changes
  PdfView1.ClearHighlight;
end;

Διάταξη viewer και χρώμα σελίδας

Fit Mode και φόντο σελίδας

// FitMode keeps long documents framed during Resize or page changes
// Setting Zoom directly cancels FitMode (it reverts to pfmNone)
PdfView1.FitMode := pfmFitPage;       // whole page in viewport
// PdfView1.FitMode := pfmFitWidth;   // page width matches viewport width
// PdfView1.FitMode := pfmActualSize; // 100%

// PageColor decouples the rendered PDF page from the host control's Color
// — typical dark-mode viewer setup keeps the scroll area dark while the
// PDF page stays paper-white
PdfView1.Color     := clBlack;        // scroll area
PdfView1.PageColor := clWhite;        // PDF page background

// Optional drop shadow and page border to lift the page off a dark bg
PdfView1.PageShadowSize  := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;

Εξερεύνηση αλληλεπίδρασης viewer στο ViewerInteractionLab

Τα έργα Demo\Delphi\ViewerInteractionLab, Demo\CBuilder\ViewerInteractionLab και Demo\Lazarus\ViewerInteractionLab κρατούν τη σύγχρονη επιφάνεια αλληλεπίδρασης του TPdfView σε μία συμπαγή φόρμα: άνοιγμα ή δημιουργία δείγματος PDF, εναλλαγή DisplayMode, εφαρμογή FitMode, αλλαγή PageColor, περιστροφή σελίδων, επισήμανση θεμάτων αναζήτησης της τρέχουσας σελίδας με HighlightSearchText, ενεργοποίηση ή απενεργοποίηση επιλογής κειμένου του χρήστη, εξέταση του SelectedText, κλήση SelectAll, CopySelectionToClipboard και ClearSelection, και παρακολούθηση της ενημέρωσης συντεταγμένων DeviceToPage στη γραμμή κατάστασης όσο το ποντίκι κινείται πάνω από τη σελίδα

Αναζήτηση και επιλογή κειμένου στο SearchAndSelect

Τα έργα Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect και Demo\Lazarus\SearchAndSelect μετατρέπουν τη ροή αναζήτησης και επιλογής του viewer σε αυτόνομα δείγματα. Ανοίγουν ή δημιουργούν ένα PDF, απαριθμούν αποτελέσματα αναζήτησης όλων των σελίδων με αριθμό σελίδας, δείκτη χαρακτήρα και κείμενο προεπισκόπησης, υποστηρίζουν πλοήγηση Previous / Next και άλμα στο αποτέλεσμα με διπλό κλικ, επισημαίνουν τις αντιστοιχίες της τρέχουσας σελίδας με HighlightSearchText, εκθέτουν επιλογές match-case και whole-word, εναλλάσσουν το AllowUserTextSelection, προεπισκοπούν το SelectedText, οδηγούν τα SelectAll, CopySelectionToClipboard και ClearSelection από κουμπιά και αφήνουν τους χρήστες να εναλλάσσουν λειτουργίες εμφάνισης single και spread

Ανάγνωση προτιμήσεων εκτύπωσης PDF στο PrintPreferences

Τα έργα Demo\Delphi\PrintPreferences, Demo\CBuilder\PrintPreferences και Demo\Lazarus\PrintPreferences διαβάζουν τις προτιμήσεις εκτύπωσης του συντάκτη πριν την εκτύπωση. Εμφανίζουν τα PrintCopies, PrintPageRanges, PrintScaling και PrintPaperHandling, μπορούν να αντιγράψουν τα αντίτυπα και τα εύρη που όρισε ο συντάκτης στις εισόδους εκτύπωσης και δείχνουν πώς το SetPdfPrintPaperHandlingDevMode αντιστοιχίζει την πρόθεση duplex του PDF σε ένα Windows DEVMODE

Τυπική εκτύπωση PDF στο PrintPDF

Τα έργα Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF και Demo\Lazarus\PrintPDF δείχνουν την τυπική ροή εκτύπωσης: άνοιγμα PDF, προεπισκόπηση σελίδων, επιλογή εύρων σελίδων και αντιτύπων στο διάλογο εκτύπωσης της πλατφόρμας, τήρηση του collate mode, απόδοση κάθε σελίδας μέσω του TPdf.RenderPage και εμφάνιση προόδου εκτύπωσης με ακύρωση. Το δείγμα Delphi δέχεται επίσης αρχεία PDF με drag & drop για γρήγορη φόρτωση

Γρήγορη προβολή πολλών σελίδων στο MultiPageViewer

Τα έργα Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer και Demo\Lazarus\MultiPageViewer ασκούν συνεχή, spread και cover-aware προβολή με συνηθισμένες ροές πλοήγησης σελίδων και zoom. Είναι επίσης χρήσιμα για έλεγχο της ταχύτητας ανοίγματος έως την πρώτη σελίδα και της απόκρισης απόδοσης σε πολύ μεγάλα PDF: σε δοκιμές μεγάλων αρχείων, έγγραφα 2.x GB που μπορούν να κάνουν το Acrobat ή το Foxit να χρειαστούν 20-30 δευτερόλεπτα πριν την πρώτη προβολή γίνονται χρησιμοποιήσιμα σχεδόν αμέσως μέσω της διαδρομής viewer του PDFium Delphi Component

Παράπλευρη ανασκόπηση στο SplitView

Τα έργα Demo\Delphi\SplitView, Demo\CBuilder\SplitView και Demo\Lazarus\SplitView δείχνουν παράπλευρη ανασκόπηση PDF. Τα δείγματα C++Builder και Lazarus εστιάζουν σε σύγκριση δύο ή τριών πλαισίων, επιλογή ενεργής προβολής, προαιρετικές συγχρονισμένες εντολές πλοήγησης, κοινές προεπιλογές zoom και περιστροφή για την επιλεγμένη προβολή ή για όλες τις φορτωμένες προβολές. Χρησιμοποιήστε αυτά τα δείγματα για να συγκρίνετε μεγάλα έγγραφα κρατώντας παράλληλα την πρώτη χρησιμοποιήσιμη προβολή και την επόμενη απόδοση σελίδων γρήγορη · τα ίδια αρχεία PDF 2.x GB που μπορεί να κάνουν το Acrobat ή το Foxit να χρειαστούν 20-30 δευτερόλεπτα για να ανοίξουν γίνονται χρησιμοποιήσιμα σχεδόν αμέσως στη διαδρομή viewer του PDFium Delphi Component

Έλεγχος επιφάνειας κινδύνου PDF στο SecurityAudit

Τα έργα Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit και Demo\Lazarus\SecurityAudit ανοίγουν ένα PDF μόνο για ανάγνωση και απαριθμούν την κατάσταση δικαιωμάτων, τα ενσωματωμένα attachments, τις document JavaScript actions, τα σχόλια συνδέσμων URI και Launch, τους web links, τις συνόψεις υπογραφών, την κατάσταση XFA, τη διαθεσιμότητα των V8 helpers και τα callbacks μη υποστηριζόμενων χαρακτηριστικών. Οι ίδιες γραμμές σύνοψης και ευρημάτων μπορούν να αποθηκευτούν ή να αντιγραφούν ως αναφορά ελέγχου TXT ή να αποθηκευτούν ως δομημένο JSON. Προορίζονται ως panels κινδύνου για host εφαρμογές, όχι ως ανίχνευση κακόβουλου λογισμικού

Χειρισμός συνδέσμων viewer

Ασφαλές κλικ-για-μετάβαση με λίστες επιτρεπόμενων ανά ενέργεια

// LinkOptions controls automatic handling of the four PDF link action
// types. Defaults enable goto and URI only; launch (run a program) and
// embedded GotoR (jump to another file) stay OFF so a stray click cannot
// run arbitrary code
PdfView1.LinkOptions :=
  [loAutoGoto, loAutoOpenURI];  // safe defaults

// OnAnnotationLinkClick fires for in-document destinations (page jumps,
// named destinations, action chains). Mark Handled = True to prevent the
// view from auto-following the link
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;  // suppress auto-handling
  end;
end;

// OnWebLinkClick fires for URI strings discovered by PDFium's web-link
// scanner (auto-detected URLs in the text stream, even without an
// /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;

Επεξεργασία form widgets του viewer

Επιλογή και Undo / Redo

// On the focused AcroForm widget, six new methods drive PDFium's form
// edit history. All six short-circuit safely if no widget is focused or
// the document carries no AcroForm
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;

Κλείδωμα του viewer για kiosks

Απενεργοποίηση χειρονομιών πλοήγησης σελίδας

// All three default to True so existing apps upgrade with no behaviour
// change. Flip them False for kiosks, preview panes, or read-only
// embeddings without subclassing TPdfView
PdfView1.AllowUserPageChange       := False;  // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // wheel up/down jumps
PdfView1.AllowUserTextSelection    := False;  // mouse/keyboard text selection

// Ctrl+wheel is reserved for zoom and is skipped by the navigation
// handler regardless of ChangePageOnMouseScrolling.

Πλευρικό πάνελ μικρογραφιών

Σύνδεση TPdfThumbnailView με TPdfView

// TPdfThumbnailView (unit FPdfThumbnail) renders one page thumbnail per
// row in a scrollable side panel
uses FPdfThumbnail;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ThumbView.Pdf              := Pdf1;
  ThumbView.ThumbnailWidth   := 120;
  ThumbView.ThumbnailHeight  := 160;
  ThumbView.SelectionColor   := $00CFA85F;  // warm highlight
  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;

Μαζική εξαγωγή με συνεργατική ακύρωση

PDF σε JPG πολλών αρχείων με πρόοδο ανά αρχείο και ανά σελίδα

// Pattern used by Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport,
// and Demo\Lazarus\BatchExport. One TPdf per file, IPdfCancellationToken
// for cancel-from-UI, TPdfStreamAdapter for buffered 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;

Συντεταγμένες viewer και hit testing

Προσαρμογή της τρέχουσας σελίδας και εξέταση κειμένου κάτω από το ποντίκι

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;

Χειρισμός σφαλμάτων

Ανθεκτικές λειτουργίες PDF

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 και προσβασιμότητα

Ανίχνευση Tagged PDF και διάσχιση του δέντρου δομής

// IsTagged is a cheap catalog probe — True when /StructTreeRoot exists
// StructureElements materialises the tree into a flat array of
// TPdfStructureElement records with type, title, alternate text, actual
// text, expansion text, language, level, parent index, and 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;

Επιλογή λειτουργίας εκτύπωσης

Ορισμός λειτουργίας εκτύπωσης EMF / PostScript / Image-Mask

// SetPdfPrintMode is a global function that maps to PDFium's
// FPDF_SetPrintMode. Use the matching TPdfPrintMode value for the
// printer driver in use
SetPdfPrintMode(pmEmf);                   // GDI EMF (default)
// SetPdfPrintMode(pmTextOnly);           // text-only 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, and PrintPaperHandling are
// the viewer-preference dictionary entries — they encode what the
// document author wanted PDF readers to default to
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 ranges
  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 εγγράφου

Απαρίθμηση JavaScript του δέντρου ονομάτων

// Document-level JavaScript is stored in the /Names /JavaScript name
// tree. JavaScriptAction[i] returns one entry; JavaScriptActions returns
// the full 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;

Συμβουλές απόδοσης

Βελτιστοποίηση λειτουργιών PDF

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 path (default since v1.21.0): RenderPage writes
// directly into the destination TBitmap's DIB buffer when callers pass a
// pre-allocated bitmap, avoiding one width * height * 4 bytes copy
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;