PDFium Component Docs

Šis puslapis lokalizuotas lietuvių kalbai ir nekeičia API, failų pavadinimų bei literalinių reikšmių

PDFium VCL programavimo pavyzdžiai

Pagrindinės dokumentų operacijos

PDF dokumento įkėlimas ir rodymas

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 įkeltas iš srauto');
  finally
    Stream.Free;
  end;
end;

Naujo PDF dokumento kūrimas

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;

Teksto operacijos

Teksto išskyrimas iš PDF

var
  PageText: WString;
  RectText: WString;
begin
  Pdf1.PageNumber := 1;
  PageText := Pdf1.Text;
  Memo1.Text := PageText;
  RectText := Pdf1.TextInRectangle(100, 100, 500, 200);
  ShowMessage('Tekstas stačiakampyje: ' + RectText);
end;

Teksto paieška

var
  Position: Integer;
begin
  Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
  while Position >= 0 do
  begin
    ShowMessage('Rasta ties simboliu: ' + IntToStr(Position));
    Position := Pdf1.FindNext;
  end;
end;

Teksto pridėjimas su formatavimu

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;

Simbolių ir šriftų metaduomenų tikrinimas

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('Objektas ' + IntToStr(I));
      Memo1.Lines.Add('Pagrindinis vardas: ' + Pdf1.FontBaseName[I]);
      Memo1.Lines.Add('Šeima: ' + Pdf1.FontFamilyName[I]);
      Memo1.Lines.Add('Įdėtas: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
      Memo1.Lines.Add('Svoris: ' + IntToStr(Pdf1.FontWeight[I]));
      Memo1.Lines.Add('Kursyvo kampas: ' + IntToStr(Pdf1.FontItalicAngle[I]));
      Memo1.Lines.Add('Pakilimas: ' + FloatToStr(Pdf1.FontAscent[I, MetricSize]));
      Memo1.Lines.Add('Nusileidimas: ' + FloatToStr(Pdf1.FontDescent[I, MetricSize]));
      Memo1.Lines.Add('Šrifto duomenų baitai: ' + IntToStr(Length(FontBytes)));
    end;

  if Pdf1.CharacterCount > 0 then
  begin
    Memo1.Lines.Add('Pirmo simbolio dydis: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
    Memo1.Lines.Add('Pirmo simbolio svoris: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
    Memo1.Lines.Add('Pirmo simbolio kampas: ' + FloatToStr(Pdf1.CharacterAngle[0]));
  end;
end;

Demo\Delphi\FontProperties, Demo\CBuilder\FontProperties ir Demo\Lazarus\FontProperties projektai rodo tuos pačius metaduomenis per TPdf ir TPdfView

Daugiakategorės turinio išskyrimo ataskaitos kūrimas

Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab ir Demo\Lazarus\ContentExtractionLab projektai sujungia turinio išskyrimą į vieną darbo srautą. Jie atidaro arba sukuria PDF, leidžia naudotojams pasirinkti metaduomenis, puslapio tekstą, puslapio objektus, vaizdus, priedus, nuorodas, anotacijas, žymeles ir šrifto bei simbolių metrikas, tada sugeneruoja santrauką ir išsamią TXT arba JSON ataskaitą. Laboratorijoje taip pat yra visų arba jokių kategorijų parinkimas, ataskaitos kopijavimas į iškarpinę ir šaltinio PDF išsaugojimo veiksmai, kad naudotojai galėtų laikyti sugeneruotą pavyzdinį PDF greta jo išskyrimo ataskaitos. Senesni ExtractText, ExtractImages, Attachment ir FontProperties demonstraciniai projektai išlieka kryptingi pavyzdžiai; ExtractText palaiko puslapių diapazono ir puslapių skyriklio parinktis, kad sugeneruotų atskirtą pagal puslapius teksto išvestį Delphi, C++Builder ir Lazarus aplinkose, o ContentExtractionLab yra skersinis inventoriaus pavyzdys

Formų operacijos

Darbas su formų laukais

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;

Užpildytų formos reikšmių suplokštinimas į puslapį

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

Vaizdų operacijos

Vaizdų išskyrimas

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;

Vaizdų pridėjimas

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;

Anotacijų operacijos

Darbas su anotacijomis

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;

Braižymo operacijos

Figūrų braižymas

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;

Naršymas ir žymelės

Darbas su žymelėmis

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;

Darbas su vardinėmis paskirtimis

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;

Priedų operacijos

Darbas su priedais

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;

Puslapių tvarkymas

Puslapių operacijos

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

Įrašymas ir glaudinimas

Įrašymas su glaudinimu

// 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 archyvinės išvesties kūrimas

// 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 atitikties tikrinimas

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;

StandardsLab kelių PDF standartų tikrinimas

Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab ir Demo\Lazarus\StandardsLab projektai įkelia arba sukuria PDF, paleidžia ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR ir ValidatePdfVT, tada vienoje lentelėje parodo kiekvieną aptiktą atitikties lygį ir problemų skaičių. Jų įrašymo mygtukai kviečia SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR ir SaveAsPdfVT, kad žymeklio išvesties eiga būtų matoma be papildomo pritaikyto karkaso

Preflight ataskaitų generavimas

FPdfPreflightReport vienetas sujungia ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR ir ValidatePdfVT į vieną ataskaitos objektą. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport ir Demo\CBuilder\PreflightReport leidžia naudotojams pasirinkti standartus, sugeneruoti santrauką, peržiūrėti būseną, prioritetą, problemų kategorijas, kategorijų skaičius, kitus veiksmus, klaidų kodus ir rekomenduojamus veiksmus, perjungti peržiūrą tarp teksto, Markdown, JSON ir CSV bei eksportuoti TXT, HTML, Markdown, JSON arba CSV ataskaitas. Delphi GUI pavyzdys taip pat prideda Action Plan peržiūrą, kuri nesėkmingus standartus, prioritetus, klaidų kodus ir rekomendacijas sutraukia į taisymo kontrolinį sąrašą. Demo\Delphi\PreflightReportCli pateikia tą patį ataskaitos kelią kaip konsolinį darbo srautą su įvesties / išvesties argumentais, pasirenkamu slaptažodžiu, išvesties formato parinkimu, įskaitant plan / actionplan, standartų filtravimu, pasirenkamu vieno failo attach=output.pdf ataskaitos įterpimu, failon= CI kontrolės grįžimo kodais, batch=list.txt apdorojimu, batchdir=folder katalogo skenavimu su pasirenkama rekursija ir stabiliu pagal kelią rūšiuojamu apdorojimu, outdir=reports ataskaitų nukreipimu, nuo konfliktų apsaugotais dublikuojamų įvesties failų pavadinimų ataskaitų vardais, TXT / JSON / HTML santraukomis su bendrais ir pagal standartus suvestais būsenų skaičiais, CSV eilučių aprašais su kiekvienam įrašui pakartotais paleidimo nustatymais ir režimu be argumentų scenarijams bei CI darbams. Sugeneruota ataskaita nurodo, kad įtaisyti tikrintuvai apima žymeklio lygio ir pasirinktus failo lygio patikrinimus, todėl pilną turinio lygio preflight vis dar galima perduoti specializuotam tikrinimo varikliui

Srautinis įkėlimas ir dideli dokumentai

PDF įkėlimas pagal poreikį su 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;

Asinchroninis atšaukimas ir progresinis atvaizdavimas

Bendradarbiaujantys atšaukimo žetonai

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

Atšaukiamas progresinis puslapio atvaizdavimas

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

Fone vykdomi atvaizdavimai su 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;

Transformacijų matricos

Poslinkio / mastelio / pasukimo / posvyrio sudarymas

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

Puslapių kompozicija

Puslapių poaibio importavimas pagal indeksą

// 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 kompozitinė išvestis

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

Puslapių pertvarkymas vietoje

// 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
//
// Pavyzdys: 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');

Vandenženklinimas naudojant Form XObject puslapio pakartotinį naudojimą

// 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 ir Demo\CBuilder\WatermarkStamp projektai paverčia šį modelį vykdomu darbo srautu: jie sukuria tikslinį PDF ir pakartotinai naudojamą štampo PDF, apgaubia štampo puslapį su CreateXObjectFromPage, įterpia tą patį Form XObject į kiekvieną tikslinį puslapį, taiko TPdfMatrix transformacijas centruotiems vandenženkliams ir viršutinio dešiniojo kampo štampams bei prideda pasirenkamas puslapių numerių etiketes prieš įrašydami rezultatą

Vaizdų įterpimas (tiesioginiai AddImage perkrovimai)

Įregistruoto vaizdo failo arba TBitmap pridėjimas

// 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 ir Demo\Lazarus\ImageToPDF projektai paverčia tai visa paketinio darbo eiga: pasirenkami keli vaizdų failai, peržiūrimas pasirinktas elementas, kiekvienam vaizdui sukuriamas vienas PDF puslapis, kiekvienas vaizdas masteliuojamas į A4 stačiosios arba gulsčiosios orientacijos puslapį, rezultatas įrašomas ir sugeneruotas PDF atidaromas

Žiūryklės paieškos paryškinimas

Kiekvieno atitikmens paryškinimas dabartiniame puslapyje

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;

Žiūryklės išdėstymas ir puslapio spalva

Talpinimo režimas ir puslapio fonas

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

Žiūryklės sąveikos tyrinėjimas ViewerInteractionLab

Demo\Delphi\ViewerInteractionLab, Demo\CBuilder\ViewerInteractionLab ir Demo\Lazarus\ViewerInteractionLab projektai vienoje kompaktiškoje formoje išlaiko modernią TPdfView sąveikos sąsają: atidarykite arba sukurkite pavyzdinį PDF, perjunkite DisplayMode, taikykite FitMode, keiskite PageColor, pasukite puslapius, paryškinkite dabartinio puslapio paieškos radinius su HighlightSearchText, įjunkite arba išjunkite naudotojo teksto pažymėjimą, peržiūrėkite SelectedText, kvieskite SelectAll, CopySelectionToClipboard ir ClearSelection, o judant pele virš puslapio stebėkite, kaip būsenos juostoje atsinaujina DeviceToPage koordinatės

Teksto paieška ir pažymėjimas SearchAndSelect

Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect ir Demo\Lazarus\SearchAndSelect projektai paverčia žiūryklės paieškos ir pažymėjimo darbo eigą atskirais pavyzdžiais. Jie atidaro arba sukuria PDF, pateikia visų puslapių paieškos rezultatus su puslapio numeriu, simbolio indeksu ir peržiūros tekstu, palaiko Previous / Next navigaciją ir dukart spustelėjimu pasiekiamą rezultatą, paryškina dabartinio puslapio atitikmenis su HighlightSearchText, pateikia match-case ir whole-word parinktis, perjungia AllowUserTextSelection, peržiūri SelectedText, valdo SelectAll, CopySelectionToClipboard ir ClearSelection mygtukais ir leidžia naudotojams perjungti vieno puslapio bei išplėstą rodymo režimą

PDF spausdinimo nuostatų skaitymas PrintPreferences

Demo\Delphi\PrintPreferences, Demo\CBuilder\PrintPreferences ir Demo\Lazarus\PrintPreferences projektai prieš spausdinimą nuskaito autoriaus spausdinimo nuostatas. Jie rodo PrintCopies, PrintPageRanges, PrintScaling ir PrintPaperHandling, gali nukopijuoti autoriaus nurodytas kopijas ir ribas į spausdinimo įvestis ir parodo, kaip SetPdfPrintPaperHandlingDevMode susieja PDF dvipusio spausdinimo ketinimą su Windows DEVMODE

Standartinis PDF spausdinimas PrintPDF

Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF ir Demo\Lazarus\PrintPDF projektai rodo standartinę spausdinimo eigą: atidarykite PDF, peržiūrėkite puslapius, pasirinkite puslapių ribas ir kopijas platformos spausdinimo dialoge, laikykitės grupavimo režimo, atvaizduokite kiekvieną puslapį per TPdf.RenderPage ir pateikite spausdinimo eigą su atšaukimu. Delphi pavyzdys taip pat priima nutemptus PDF failus greitam įkėlimui

Spartus kelių puslapių peržiūrėjimas MultiPageViewer

Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer ir Demo\Lazarus\MultiPageViewer projektai išbando nuolatinį, išskleistą ir viršelį suprantantį peržiūros režimą su įprasta puslapių navigacija ir mastelio keitimo eiga. Jie taip pat naudingi tikrinant atidarymo iki pirmo puslapio greitį ir atvaizdavimo spartą labai dideliuose PDF: atliekant didelių failų bandymus, 2.x GB dokumentai, kuriems Acrobat arba Foxit iki pirmo vaizdo gali skirti 20-30 sekundžių, PDFiumPas žiūryklės kelyje gali tapti naudojami beveik iš karto

Peržiūra greta SplitView

Demo\Delphi\SplitView, Demo\CBuilder\SplitView ir Demo\Lazarus\SplitView projektai rodo PDF peržiūrą greta. C++Builder ir Lazarus pavyzdžiai sutelkia dėmesį į dviejų arba trijų dalių palyginimą, aktyvios peržiūros parinkimą, pasirenkamas sinchronizuotas navigacijos komandas, bendrus mastelio nustatymus ir pasirinktai peržiūrai arba visoms įkeltoms peržiūroms taikomą pasukimą. Naudokite šiuos pavyzdžius dideliems dokumentams lyginti išlaikydami pirmą naudojamą peržiūrą ir tolesnį puslapių atvaizdavimą reaguojančius; tie patys 2.x GB PDF failai, kuriems Acrobat arba Foxit gali prireikti 20-30 sekundžių atidarymui, PDFiumPas žiūryklės kelyje gali tapti naudojami beveik iš karto

PDF rizikos paviršiaus auditas SecurityAudit

Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit ir Demo\Lazarus\SecurityAudit projektai atidaro PDF tik skaitymui ir pateikia leidimų būseną, įterptus priedus, dokumento JavaScript veiksmus, URI ir Launch nuorodų anotacijas, žiniatinklio nuorodas, parašų santraukas, XFA būseną, V8 pagalbinių priemonių prieinamumą ir nepalaikomų funkcijų iškvietas. Tą pačią suvestinę ir radinių eilutes galima įrašyti arba nukopijuoti kaip TXT audito ataskaitą arba įrašyti kaip struktūruotą JSON. Jos skirtos pagrindinės programos rizikos panelėms, o ne kenkėjiškos programinės įrangos aptikimui

Žiūryklės nuorodų apdorojimas

Saugus spustelėjimas ir sekimas su kiekvieno veiksmo leidimų sąrašais

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

Žiūryklės formų valdiklių redagavimas

Pažymėjimas ir Atšaukti / Pakartoti

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

Žiūryklės ribojimas kioskams

Puslapio navigacijos gestų išjungimas

// 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+Pradžia/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.

Miniatiūrų šoninė sritis

TPdfThumbnailView susiejimas su 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.PdfView1PageNumberPakeista(Sender: TObject);
begin
  ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;

Bendrai atšaukiamas masinis eksportas

Kelių failų PDF į JPG su pažanga kiekvienam failui ir puslapiui

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

Žiūryklės koordinatės ir pataikymo testavimas

Dabartinio puslapio pritaikymas ir teksto po pele tikrinimas

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;

Klaidų apdorojimas

Tvirtos PDF operacijos

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;

Pažymėtas PDF ir prieinamumas

Pažymėto PDF aptikimas ir struktūros medžio perėjimas

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

Spausdinimo režimo pasirinkimas

EMF / PostScript / vaizdo kaukės spausdinimo režimo nustatymas

// 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

Autoriaus numatytų spausdinimo nustatymų skaitymas

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

Dokumento JavaScript veiksmai

JavaScript vardų medžio peržiūra

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

Našumo patarimai

PDF operacijų optimizavimas

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;