PDFium Component Docs

Przykłady programowania PDFium VCL

Wybór dema do uruchomienia

Kolekcja dem obejmuje 33 tematy: 33 projekty Delphi, 32 projekty C++Builder i 33 projekty Lazarus, czyli łącznie 98 natywnych projektów. Każda platforma utrzymuje 24 kompletne dema przepływów pracy w swoim katalogu głównym. Dziewięć skoncentrowanych tematów znajduje się w Miscellaneous, co daje 26 natywnych projektów na trzy platformy łącznie; XfaLab jest dostępny dla Delphi i Lazarusa

Najpierw otwórz przepływ pracy z katalogu głównego: PDFViewer jako przewodnik po funkcjach, CreatePDF do tworzenia dokumentów na żywo, ContentExtractionLab do błyskawicznej inwentaryzacji, FormFill do edytowalnych formularzy, StandardsLab do walidacji i konwersji albo IntakeWorkbenchCli do zautomatyzowanego przyjmowania dokumentów. Te sześć punktów wejścia natychmiast daje działające rezultaty; skoncentrowane próbki poniżej przydają się, gdy trzeba przyjrzeć się jednemu API w szczegółach

Główne dema przepływów pracy

DemoDo czego służyCzym różni się od pokrewnych dem
PDFViewerOgólne przeglądanie i ocena funkcjiGłówna przeglądarka łączy nawigację, wyszukiwanie, miniatury, tryby wyświetlania, drukowanie i pokaz możliwości
MultiPageViewerStrony ciągłe, rozkładówki i układy z okładkąSkoncentrowany przykład układu oparty na wbudowanych API zaznaczania przeglądarki; po pełniejsze wrażenia przeglądarki użyj PDFViewer
SplitViewPorównywanie stron lub dokumentów w osobnych panelachDemonstruje niezależne pozycje widoków i kierowanie poleceń do aktywnego panelu, a nie układ dwustronowy w jednym widoku
SearchAndSelectWyniki wyszukiwania i zaznaczanie po wielu stronachLista wyników i opcje wyszukiwania odsłaniają przepływ wyszukiwania bardziej bezpośrednio niż pasek narzędzi przeglądarki
PrintPDFPodgląd i zwykłe zadania drukowaniaZakresy stron, skalowanie, postęp i anulowanie tworzą główny przepływ drukowania
ContentExtractionLabWspólne sprawdzanie kilku kategorii treściInwentarze TXT/JSON opisują obiekty i tekst podglądu; nie zastępują kompletnego eksportu tekstu ani plików obrazów
ExtractImagesEksport osadzonych obiektów obrazówWyodrębnia bitmapy obrazów zamiast zrzutów całych stron; wbudowana próbka zawiera po dwa prawdziwe obiekty obrazów na każdej z dwóch stron
TableExtractionLabWykrywanie tabel i eksport CSV/JSONTabele z liniami i wyrównane białymi znakami, scalone komórki, grupy kontynuacji i sterowanie pewnością wykrycia są niezależne od ekstrakcji czystego tekstu
AttachmentOdczyt, dodawanie i eksport osadzonych załącznikówOperacje na zawartości załączników wykraczają poza wypisywanie nazw i rozmiarów w ContentExtractionLab
BatchExportEksport obrazów stron z wielu dokumentówWyjście strumieniowe, status dla każdego pliku i odizolowane niepowodzenia demonstrują przetwarzanie wsadowe, a nie pojedynczą konwersję
CreatePDFTworzenie treści stron z podglądem na żywoWszystkie trzy natywne warianty tworzą przeszukiwalny tekst, kształty wektorowe, prawdziwy obraz rastrowy, tabele i adnotację rewizyjną; opcje przebudowują podgląd przed jawnym zapisem
ImageToPDFBudowanie stron z wejściowych plików obrazówUkład obrazów, dopasowanie, kolejność i obsługa JPEG tworzą przepływ konwersji dokumentów
MergePDFSkładanie stron z kilku PDF-ówSprawdź wejścia, aby zobaczyć liczby stron i interwały wyjścia, zmień kolejność źródeł, a scal dopiero gdy każde wejście przejdzie walidację
SplitPDFZapisywanie wybranych grup stron do osobnych PDF-ówNazewnictwo wyjścia i walidacja grup stron odróżniają go od scalania i renderowania obrazów stron
WatermarkStampNakładanie powtarzanych nakładek na istniejące stronyWybierz docelowy PDF, wielokrotnego użytku PDF stempla i interwał stron; stemple skalują się do każdej strony, a niewybrane strony pozostają bez zmian
FormFillInteraktywne wypełnianie AcroForm i spłaszczanieWprowadzanie danych do pól i zapisane wyglądy odróżniają go od wymiany XFDF i zachowań specyficznych dla XFA
AccessibilityReaderInteraktywne czytanie i mowaCzytnik GUI demonstruje nawigację w czytaniu i podświetlanie, a nie audyt zgodności
AccessibilityWorkbenchCliWsadowy przegląd dostępności i generowanie raportówUstalenia, podsumowania i bramki przeglądu służą automatyzacji; ustalenia nie zastępują ręcznego przeglądu dostępności
StandardsLabWalidacja i konwersja pod konkretne standardyInteraktywne laboratorium odsłania operacje i opcje, zamiast wyłącznie generować raport zbiorczy
PreflightReportInteraktywne raporty standardówGUI wspiera ręczną inspekcję i eksport raportów
PreflightReportCliZautomatyzowane raporty standardówWsadowe wejścia, formaty raportów i bramki kodów wyjścia dostarczają automatyczny odpowiednik PreflightReport
IntakeWorkbenchCliWsadowe przyjmowanie, triaż i routingRaporty zbiorcze, bramki niepowodzeń i decyzje routingu czynią z niego przepływ przetwarzania wykraczający poza GUI SecurityAudit

Skoncentrowane próbki w Miscellaneous

Te projekty otwierasz z Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous lub Demo\Lazarus\Miscellaneous. Zachowują przydatne przepisy API i wąskie zadania eksportowe, podczas gdy katalog główny skupia się na kompletnych doświadczeniach. Podstawowe sprawdzenia Unicode oraz stały przewodnik zapisu i listowania adnotacji obejmują przepływy tworzenia dokumentów, ekstrakcji, wymiany XFDF i testy API; nie mają już osobnych projektów demo

DemoDo czego służyCzym różni się od pokrewnych dem
SecurityAuditInteraktywne sprawdzanie postawy bezpieczeństwaGUI kładzie nacisk na uprawnienia, skrypty, podpisy i szczegóły bezpieczeństwa, a nie na routing plików
XfdfLabImport i eksport danych XFDFWymiana danych oraz jawny zapis zaimportowanego PDF demonstrują trwałość zmian; sam eksport XFDF nie zapisuje zmodyfikowanego PDF
AccessibilityLabPrzejście przez API czytnika w konsoliKompaktowy, wykonywalny przewodnik odsłania jednostki czytania, ramki słów, strukturę i wyjście skryptu mowy
ExtractTextEksport kompletnego tekstu z wybranych stronWyjście z warstwy tekstowej, separatory stron i anulowanie odróżniają go od podglądów inwentarza i detekcji tabel; OCR nie jest wykonywany
FontPropertiesSprawdzanie metryk czcionek i znakówOtwiera się z rzeczywistymi metrykami czcionek i znaków pierwszego obiektu tekstowego; wybór innego wiersza pozwala porównać czcionki bez eksportu zawartości dokumentu
NavigationLabZakładki, destynacje i akcje nawigacyjneKompaktowy przegląd API uzupełnia widoczne kontrolki nawigacji w PDFViewer
PDFtoJpgRenderowanie jednego dokumentu do obrazów stronKompaktowy przykład renderowania pojedynczego dokumentu; wariant Delphi udostępnia osobne zakresy stron, a BatchExport skupia się na wielu dokumentach wejściowych
PrintPreferencesArkusze N-up i preferencje drukowania autora PDFLiczba kopii, filtrowanie stron parzystych i nieparzystych oraz preferencje podane przez autora są tu głównym tematem; przykład towarzyszy demu PrintPDF
ViewerInteractionLabDiagnozowanie interakcji myszy, klawiatury i współrzędnychLog interakcji i konwersja współrzędnych strona/urządzenie czynią z niego narzędzie diagnostyczne API
XfaLabStatyczne pakiety XFA i możliwości runtimeOtwiera pakiety template i datasets zwykłym runtime; interaktywne renderowanie XFA wymaga runtime z włączonym XFA, w wariantach dla Delphi i Lazarus

Zacznij od działającego przewodnika po funkcjach

PDFViewer otwiera dołączony PDFiumDemoShowcase.pdf — sześciostronicowy dokument z przeszukiwalnym tekstem, wykresami wektorowymi, dwoma osadzonymi obrazami, tabelą, czterema polami AcroForm, zakładkami rozdziałów, linkami, notatką rewizyjną i dwoma załącznikami. Pasek funkcji udostępnia Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF i Explore forms; każda akcja działa na bieżącym dokumencie

CreatePDF otwiera dwustronicowy podgląd raportu na żywo. Zmień jego tytuł i autora albo przełącz kształty, tabelę i znak wodny, żeby przebudować rzeczywistą treść stron; opcja Unicode dodaje trzecią stronę. Nic nie trafia na dysk przed zapisem, a zapisany PDF pozostaje przeszukiwalny

MultiPageViewer, SearchAndSelect, ContentExtractionLab i FormFill otwierają ten sam dokument dla własnych przepływów pracy, z wynikami wyszukiwania, inwentarzem ekstrakcji i edytowalnymi polami gotowymi od razu. Miscellaneous\NavigationLab używa własnej lokalnej kopii do przeglądu API zakładek i destynacji

Attachment startuje z dwoma prawdziwymi osadzonymi plikami. PrintPreferences startuje z czterema stronami i preferencjami autora: dwie kopie, wybrane zakresy stron, skalowanie i druk dwustronny; bieżący przepływ drukowania stosuje kopie i zakresy stron, natomiast skalowanie i druk dwustronny są sprawdzane i raportowane. XfaLab startuje z rzeczywistymi pakietami template i datasets do inspekcji statycznego XFA; interaktywne renderowanie XFA wymaga odpowiedniego runtime i jest osobną możliwością

Każdy projekt przeglądania, formularzy, ekstrakcji i nawigacji zawiera własny PDFiumDemoShowcase.pdf. Skopiuj katalog projektu i trzymaj to dołączone wejście obok dystrybuowanego pliku wykonywalnego; buildy Lazarusa umieszczają go automatycznie. Przewodnik działa offline, a ogólne przeglądarki i próbki ekstrakcji zapewniają także wygenerowaną treść zastępczą, gdy lokalny PDF jest niedostępny

Kopiowanie i utrzymywanie natywnych próbek

Każde natywne demo zawiera własną implementację próbki. Punkty wejścia Delphi i Lazarus dla AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli i PreflightReportCli obejmują pełny przepływ pracy w katalogu projektu, łącznie ze specyficzną dla kompilatora inicjalizacją i zapisem JPEG. Przykłady załączników, preferencji drukowania i XFA budują ponadto lokalnie własne dane wejściowe specyficzne dla danej funkcji. Poza skopiowanym projektem wymagane są tylko biblioteka, pasujący natywny runtime i zwykłe zależności frameworka kompilatora

Wybierz ekstrakcję obiektów obrazów, gdy potrzebujesz osadzonych bitmap, renderowanie stron, gdy zależy Ci na widocznej stronie, i ekstrakcję tekstu, gdy PDF ma już warstwę tekstową. Raport, który wylicza te kategorie, nie eksportuje ich pełnej zawartości. Te granice utrzymują skoncentrowane przykłady w użytecznej postaci, bez rozrastania każdego dema w kolejną ogólnego przeznaczenia przeglądarkę czy warsztat

Podstawowe operacje na dokumentach

Ładowanie i wyświetlanie dokumentu 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;

Tworzenie nowego dokumentu 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;

Operacje na tekście

Ekstrakcja tekstu z 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;

Wyszukiwanie tekstu

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;

Dodawanie tekstu z formatowaniem

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;

Inspekcja metadanych znaków i czcionek

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;

Projekty Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties i Demo\Lazarus\Miscellaneous\FontProperties pokazują te same metadane poprzez TPdf i TPdfView

Budowanie raportu ekstrakcji treści wielu kategorii

Projekty Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab i Demo\Lazarus\ContentExtractionLab przekształcają ekstrakcję treści w jeden przepływ pracy. Otwierają lub tworzą PDF, umożliwiają użytkownikom wybór metadanych, tekstu stron, obiektów stron, obrazów, załączników, linków, adnotacji, zakładek oraz metryk czcionek / znaków, a następnie generują podsumowanie wraz ze szczegółowym raportem TXT lub JSON. Laboratorium obejmuje również wybór wszystkich / żadnych kategorii, kopiowanie raportu do schowka oraz akcje zapisu źródłowego PDF, dzięki czemu użytkownicy mogą zachować wygenerowany przykładowy PDF obok jego raportu ekstrakcji. ExtractImages i Attachment dostarczają przepływów eksportu zawartości, podczas gdy Miscellaneous\ExtractText i Miscellaneous\FontProperties zachowują skoncentrowane przykłady API; ExtractText obsługuje opcje zakresu stron i separatora stron do generowania wyjścia tekstowego na stronę w Delphi, C++Builder i Lazarus, podczas gdy ContentExtractionLab jest przekrojowym przykładem inwentaryzacji

Wykrywanie i wyodrębnianie tabel

Projekty Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab i Demo\Lazarus\TableExtractionLab zamieniają detekcję tabel w jeden przepływ pracy. Laboratorium buduje przykładowy dokument zawierający tabelę z liniami i scalonymi komórkami nagłówka, tabelę wyrównaną białą przestrzenią bez linii oraz długą tabelę łamiącą się na granicy strony, a następnie uruchamia ExtractTables dla bieżącej strony lub ExtractDocumentTables dla całego dokumentu i raportuje wiersze, kolumny, wartości RowSpan i ColumnSpan, flagi nagłówka, tryb detekcji, pewność i grupy kontynuacji. Opcje DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings i MinConfidence są edytowalne w interfejsie, a wybrana tabela jest eksportowana przez TPdfTable.ToCsv i TPdfTable.ToJson. Laboratorium przetwarza też wsadowo cały katalog: Batch folder uruchamia ExtractDocumentTables dla każdego PDF, raportuje liczby tabel na dokument, oznacza skanowanie bez warstwy tekstu i ponawia puste dokumenty z ustawieniem kompaktowych kolumn; Export all CSV zapisuje każdą wykrytą tabelę obok plików źródłowych. Każdy dokument otwiera się we własnej instancji TPdf, dzięki czemu jeden nieczytelny plik nie może wpłynąć na resztę partii

Operacje na formularzach

Praca z polami formularzy

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;

Spłaszczanie wypełnionych wartości formularzy w stronę

// Bez spłaszczania FormField[i] := value zapisuje tylko wpis /V —
// widoczny wygląd pochodzi ze strumienia /AP i może się nie odświeżyć.
// GenerateFormAppearances regeneruje /AP dla każdego widżetu, następnie
// FlattenAllPages wypala adnotacje i widżety każdej strony w
// trwałą, nieedytowalną zawartość.
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;

Operacje na obrazach

Ekstrakcja obrazów

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;

Dodawanie obrazów

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;

Operacje na adnotacjach

Praca z adnotacjami

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;

Operacje rysowania

Rysowanie kształtów

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;

Nawigacja i zakładki

Praca z zakładkami

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;

Praca z nazwanymi miejscami docelowymi

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;

Operacje na załącznikach

Praca z załącznikami

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;

Zarządzanie stronami

Operacje na stronach

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

Zapisywanie i kompresja

Zapisywanie z kompresją

// Utwórz skompresowany dokument PDF
Pdf1.CreateDocument;
Pdf1.Compressed := True; // upewnij się, że wszystkie strumienie są skompresowane FlateDecode (domyślnie)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // rozmiar A4
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;

// Zapisz z opcjami
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // zapis przyrostowy
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // usuń zabezpieczenia

// Zapisz z określonym celem wersji PDF. Walidator wersji PDF odrzuca
// każdą funkcję wprowadzoną po wybranym celu (JBIG2Decode, MarkInfo,
// szyfrowanie AES, adnotacje Polygon / Caret / Watermark / Redact, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
  ShowMessage('Save rejected: document contains features newer than PDF 1.5');

Tworzenie wyjścia archiwalnego PDF/A-1b

// SaveAsPdfA przetwarza wynik zapisu bazowego poprzez aktualizację przyrostową,
// która wstrzykuje strumień metadanych XMP, OutputIntent sRGB ICC oraz
// zaktualizowany Catalog dokumentu, dzięki czemu wynik jest zgodny z PDF/A-1b.
// Dołączony profil sRGB IEC61966-2.1 jest używany automatycznie, gdy nie podano
// niestandardowego profilu.
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 z niestandardowym profilem ICC (np. potoki druku CMYK)
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;

// Wyjście PDF/A w pamięci
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;

Walidacja zgodności PDF/A

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

  // Tania sonda w stylu nagłówka — odczytuje zgodność bez iteracji
  // pełnego walidatora. Wynik: pacNone, pac1a, pac1b, pac2b, pac3b lub
  // 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;

  // Pełny walidator z diagnostyką per problem
  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;

Sprawdzanie wielu standardów PDF w StandardsLab

Projekty Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab i Demo\Lazarus\StandardsLab ładują lub tworzą PDF, uruchamiają ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR i ValidatePdfVT, a następnie pokazują każdy wykryty poziom zgodności i liczbę problemów w jednej siatce. Ich przyciski zapisu wywołują SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR i SaveAsPdfVT, dzięki czemu przepływ pracy wyjścia z markerami jest widoczny bez pisania niestandardowego harnessu

Generowanie raportów preflight

Jednostka FPdfPreflightReport opakowuje ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR i ValidatePdfVT w jeden obiekt raportu, który można odpytywać, z wagami Info / Warning / Error, agregacją statusów i problemów, wyszukiwaniem, przeszukiwaniem, filtrowaniem oraz stabilnymi odciskami palców SHA-256. Raporty można emitować jako tekst, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON lub natywny XML. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport i Demo\CBuilder\PreflightReport zapewniają interaktywne przepływy wyboru i podglądu, a Demo\Delphi\PreflightReportCli dodaje skryptowalne argumenty wejścia / wyjścia, filtrowanie wg standardów, opcjonalne osadzanie załącznika z raportem, bramkowanie kodem wyjścia CI, wsadowe przetwarzanie list i katalogów, routing bezpieczny dla kolizji nazw, podsumowania zagregowane oraz manifesty CSV. Wygenerowany raport stwierdza, że wbudowane walidatory pokrywają kontrole na poziomie markerów oraz wybrane kontrole na poziomie pliku, dzięki czemu pełny preflight na poziomie treści można nadal delegować do dedykowanego silnika walidacji

Ładowanie strumieniowe i duże dokumenty

Ładowanie PDF na żądanie za pomocą LoadCustomDocument

// LoadCustomDocument pozwala PDFium pobierać bloki z dowolnego strumienia
// TStream z możliwością przeszukiwania na żądanie. Strumień NIE jest
// kopiowany do pamięci, więc wielogigabajtowe pliki PDF, zdalne strumienie
// treści HTTP i źródła bazodanowe są wszystkie wykonalne bez wstępnego
// buforowania.
var
  FileStream: TFileStream;
begin
  // Strumieniowe odczytywanie z pliku (bez kopii w pamięci)
  FileStream := TFileStream.Create('C:\Huge.pdf',
    fmOpenRead or fmShareDenyWrite);
  Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
  // ^^ własność przeniesiona — Pdf1 zwalnia FileStream przy UnloadDocument.
  Pdf1.Active := True;
  ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;

// Strumień zarządzany zewnętrznie (wywołujący zwalnia go po 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;

Anulowanie asynchroniczne i renderowanie progresywne

Kooperatywne tokeny anulowania

// FPdfAsync udostępnia IPdfCancellationToken /
// IPdfCancellationTokenSource dla semantyki anulowania z UI, która
// działa na długo wykonywanych ścieżkach eksportu i renderowania.
uses FPdfAsync;

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

  // ... użytkownik klika Anuluj ...
  CancelSource.Cancel;

  // Worker okresowo sprawdza CancelToken.IsCancelled, lub ścieżka
  // renderowania sprawdza go poprzez callback IFSDK_PAUSE PDFium.
  if CancelToken.IsCancelled then
    Memo1.Lines.Add('Cancelled by user');
end;

Anulowalne progresywne renderowanie strony

// RenderPageProgressive pozwala długiemu renderowaniu w wysokim DPI przerwać
// w połowie strony, gdy użytkownik kliknie Anuluj, zamiast blokować wywołującego
// do zakończenia.
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;

Uruchamianie renderowań w wątku tła za pomocą TPdfFuture

// TPdfFuture<T> uruchamia workera w wątku tła i wysyła kopertę
// TPdfFutureResult<T> z powrotem do głównego wątku.
//
// Ważne: TPdf serializuje wywołania renderowania per instancję, ale worker nadal
// posiada dyspozytora i czas życia dokumentu. Nie modyfikuj TPdf, gdy renderowanie
// jest w toku; eksport wsadowy zwykle utrzymuje jeden TPdf na plik.
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;

Macierze transformacji

Komponowanie Translate / Scale / Rotate / Skew

// FPdfMatrix opakowuje FS_MATRIX PDFium, dzięki czemu wywołujący mogą zbudować
// transformację deklaratywnie i przekazać ją do FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;

var
  M: TPdfMatrix;
  RawMatrix: FS_MATRIX;
  PageObj: FPDF_PAGEOBJECT;
begin
  M := TPdfMatrix.Create;
  try
    M.Translate(72, 200);       // przesuń o 1 cal w prawo, ~2.8 cala w górę
    M.Scale(0.5, 0.5);          // stempel o połowie rozmiaru
    M.Rotate(15);               // obrót o 15 stopni przeciwnie do ruchu wskazówek zegara
    // M.HorizontalFlip;
    // M.VerticalFlip;
    // M.CentralFlip;
    // M.Skew(10, 5);
    // M.Multiply(Other);       // post-multiplikacja z inną macierzą

    // Zastosuj do dowolnego obiektu strony PDFium (tekst / ścieżka / obraz / Form XObject)
    RawMatrix := M.Handle;
    FPDFPageObj_SetMatrix(PageObj, RawMatrix);
  finally
    M.Free;
  end;
end;

Kompozycja stron

Import podzbioru stron według indeksu

// ImportPagesByIndex kopiuje jawną tablicę indeksów liczonych od zera z
// źródłowego PDF do tego dokumentu. InsertAt = 0 wstawia przed stroną 1;
// PageCount dołącza na końcu.
var
  Source: TPdf;
begin
  Source := TPdf.Create(nil);
  try
    Source.FileName := 'C:\Report.pdf';
    Source.Active   := True;

    // Importuj strony 0, 2, 4 (liczone od 1: strony 1, 3, 5) ze Source
    // i dołącz je na końcu Pdf1.
    Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);

    // Pusta tablica importuje każdą stronę źródłową
    // Pdf1.ImportPagesByIndex(Source, [], 0);
  finally
    Source.Free;
  end;
end;

Wyjście kompozytowe N-up

// ImportNPagesToOne zwraca zupełnie nowy TPdf, którego strony są kompozytami
// NumX*NumY TEGO dokumentu. OutputWidth/Height to jednostki użytkownika PDF
// (1 jednostka = 1/72 cala).
var
  Composite: TPdf;
begin
  Pdf1.FileName := 'C:\Slides.pdf';
  Pdf1.Active   := True;
  // 4-up A4 poziomo: 842 x 595 pt, 2 kolumny x 2 wiersze
  Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
  try
    if Composite <> nil then
      Composite.SaveAs('C:\Slides_4up.pdf');
  finally
    Composite.Free;
  end;
end;

Zmiana kolejności stron w miejscu

// MovePages przyjmuje indeksy stron liczone od zera, które mają zostać
// przeniesione, plus indeks docelowy dla pierwszej przeniesionej strony
// po zakończeniu przenoszenia. Inne strony przesuwają się wokół przeniesionego
// bloku, dzięki czemu długość dokumentu pozostaje taka sama.
//
// Przykład: w 5-stronicowym dokumencie ze stronami ponumerowanymi [0,1,2,3,4],
// MovePages([2, 3], 0) zmienia kolejność na [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
  ShowMessage('Invalid indices passed to MovePages');

Znak wodny poprzez ponowne użycie strony Form XObject

// CreateXObjectFromPage tworzy wielokrotnie używalny uchwyt Form XObject z
// dowolnej strony dowolnego innego TPdf. Stempluj ten uchwyt na dowolnej liczbie
// stron TEGO dokumentu — każdy stempel jest pojedynczym obiektem strony PDFium,
// który może być pozycjonowany, skalowany i obracany poprzez API macierzy.
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;

    // Opakuj stronę 0 WatermarkSource jako wielokrotnie używalny 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;

        // Wycentruj znak wodny na stronie
        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; // zamyka uchwyt FPDF_XOBJECT
    end;

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

Projekty Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp i Demo\CBuilder\WatermarkStamp przekształcają ten wzorzec w uruchamialny przepływ pracy: tworzą docelowy PDF i wielokrotnie używalny PDF stempla, opakowują stronę stempla za pomocą CreateXObjectFromPage, wstawiają ten sam Form XObject na każdą docelową stronę, stosują transformacje TPdfMatrix dla wycentrowanych znaków wodnych i stempli w prawym górnym rogu oraz dodają opcjonalne etykiety numerów stron przed zapisaniem wyniku

Wstawianie obrazów (bezpośrednie przeciążenia AddImage)

Dodawanie zarejestrowanego pliku obrazu lub TBitmap

// AddImage(FileName) akceptuje każdy format zarejestrowany w jednostkach
// graficznych VCL lub LCL (BMP, PNG przez PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);

// AddImage(TBitmap) pomija pośrednika TPicture, idealne gdy bitmapa
// pochodzi już z renderowania lub generowania wsadowego.
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;

Projekty Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF i Demo\Lazarus\ImageToPDF przekształcają to w pełny przepływ pracy wsadowy: wybierz wiele plików obrazów, podgląd wybranego elementu, utwórz jedną stronę PDF na obraz, przeskaluj każdy obraz do strony A4 pionowej lub poziomej, zapisz wynik i otwórz wygenerowany PDF

Podświetlanie wyników wyszukiwania w przeglądarce

Podświetl każde dopasowanie na bieżącej stronie

var
  MatchCount: Integer;
begin
  // Nałóż maskę clYellow nad każdym dopasowaniem na bieżącej stronie widoku.
  // Przejście na inną stronę usuwa podświetlenie automatycznie.
  PdfView1.HighlightColor := clYellow;
  MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
  Status.Caption := Format('%d match(es) on this page', [MatchCount]);

  // Programowo usuń nakładkę przed zmianą strony
  PdfView1.ClearHighlight;
end;

Układ przeglądarki i kolor strony

Tryb dopasowania i tło strony

// FitMode utrzymuje długie dokumenty w ramach podczas zmiany rozmiaru lub zmiany strony.
// Ustawienie Zoom bezpośrednio anuluje FitMode (powraca do pfmNone).
PdfView1.FitMode := pfmFitPage;       // cała strona w obszarze wyświetlania
// PdfView1.FitMode := pfmFitWidth;   // szerokość strony pasuje do szerokości obszaru wyświetlania
// PdfView1.FitMode := pfmActualSize; // 100%

// PageColor oddziela renderowaną stronę PDF od koloru kontrolki hosta
// — typowa konfiguracja przeglądarki w trybie ciemnym utrzymuje obszar
// przewijania ciemny, podczas gdy strona PDF pozostaje papierowo biała.
PdfView1.Color     := clBlack;        // obszar przewijania
PdfView1.PageColor := clWhite;        // tło strony PDF

// Opcjonalny cień i obramowanie strony, aby unieść stronę nad ciemnym tłem
PdfView1.PageShadowSize  := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;

Eksplorowanie interakcji przeglądarki w ViewerInteractionLab

Projekty Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab i Demo\Lazarus\Miscellaneous\ViewerInteractionLab utrzymują nowoczesną powierzchnię interakcji TPdfView w jednym kompaktowym formularzu: otwórz lub utwórz przykładowy PDF, przełącz DisplayMode, zastosuj FitMode, zmień PageColor, obróć strony, podświetl dopasowania wyszukiwania bieżącej strony za pomocą HighlightSearchText, włącz lub wyłącz zaznaczanie tekstu przez użytkownika, sprawdź SelectedText, wywołaj SelectAll, CopySelectionToClipboard i ClearSelection oraz obserwuj współrzędne DeviceToPage aktualizujące się w pasku statusu, gdy mysz porusza się nad stroną

Wyszukiwanie i zaznaczanie tekstu w SearchAndSelect

Projekty Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect i Demo\Lazarus\SearchAndSelect przekształcają przepływ pracy wyszukiwania i zaznaczania w samodzielne próbki. Otwierają lub tworzą PDF, wymieniają wyniki wyszukiwania ze wszystkich stron z numerem strony, indeksem znaku i tekstem podglądu, obsługują nawigację Poprzedni / Następny i podwójne kliknięcie wyniku, podświetlają dopasowania bieżącej strony za pomocą HighlightSearchText, udostępniają opcje dopasowania wielkości liter i całego słowa, przełączają AllowUserTextSelection, podglądają SelectedText, sterują SelectAll, CopySelectionToClipboard i ClearSelection z przycisków oraz pozwalają użytkownikom przełączać się między pojedynczymi a rozkładówkowymi trybami wyświetlania

Odczyt preferencji druku PDF w PrintPreferences

Projekty Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences i Demo\Lazarus\Miscellaneous\PrintPreferences odczytują preferencje druku autora przed drukowaniem. Wyświetlają PrintCopies, PrintPageRanges, PrintScaling i PrintPaperHandling, mogą kopiować podane przez autora kopie i zakresy do wejść druku oraz pokazują, jak SetPdfPrintPaperHandlingDevMode mapuje intencję duplex PDF do Windows DEVMODE

Standardowe drukowanie PDF w PrintPDF

Projekty Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF i Demo\Lazarus\PrintPDF pokazują standardowy przepływ pracy druku: otwórz PDF, podgląd stron, wybierz zakresy stron i kopie w platformowym oknie dialogowym druku, uwzględnij tryb sortowania, renderuj każdą stronę poprzez TPdf.RenderPage i udostępnij postęp druku z anulowaniem. Przykład Delphi akceptuje również upuszczone pliki PDF dla szybkiego ładowania

Szybkie wielostronicowe przeglądanie w MultiPageViewer

Projekty Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer i Demo\Lazarus\MultiPageViewer ćwiczą przeglądanie ciągłe, rozkładówkowe i z okładką wraz z regularnymi przepływami pracy nawigacji po stronach i powiększenia. Są również użyteczne do testowania szybkości otwierania pierwszej strony i responsywności renderowania na bardzo dużych plikach PDF: w testach dużych plików dokumenty o rozmiarze 2.x GB, które mogą sprawić, że Acrobat lub Foxit spędzą 20-30 sekund przed pierwszym widokiem, mogą stać się użyteczne niemal natychmiast poprzez ścieżkę przeglądarki PDFium Delphi Component

Przegląd obok siebie w SplitView

Projekty Demo\Delphi\SplitView, Demo\CBuilder\SplitView i Demo\Lazarus\SplitView pokazują przegląd PDF obok siebie. Próbki C++Builder i Lazarus koncentrują się na porównaniu dwóch lub trzech paneli, wyborze aktywnego widoku, opcjonalnie synchronizowanych poleceniach nawigacji, współdzielonych presetach powiększenia i obrocie dla wybranego widoku lub wszystkich załadowanych widoków. Użyj tych próbek do porównywania dużych dokumentów przy zachowaniu pierwszego użytecznego widoku i responsywnego renderowania kolejnych stron; te same pliki PDF o rozmiarze 2.x GB, których otwarcie może zająć Acrobatowi lub Foxitowi 20-30 sekund, mogą stać się użyteczne niemal natychmiast na ścieżce przeglądarki PDFium Delphi Component

Audyt powierzchni ryzyka PDF w SecurityAudit

Projekty Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit i Demo\Lazarus\SecurityAudit otwierają PDF tylko do odczytu i wymieniają stan uprawnień, osadzone załączniki, akcje JavaScript dokumentu, adnotacje linków URI i Launch, linki webowe, podsumowania podpisów, stan XFA, dostępność pomocników V8 oraz callbacki nieobsługiwanych funkcji. To samo podsumowanie i wiersze wyników można zapisać lub skopiować jako raport audytu TXT lub zapisać jako ustrukturyzowany JSON. Są przeznaczone jako panele ryzyka aplikacji hosta, nie jako wykrywanie złośliwego oprogramowania

Obsługa linków w przeglądarce

Bezpieczne kliknięcie-aby-podążyć z listami dozwolonych per akcja

// LinkOptions kontroluje automatyczną obsługę czterech typów akcji linków PDF.
// Domyślnie włącza tylko goto i URI; launch (uruchom program) i embedded GotoR
// (przejdź do innego pliku) pozostają WYŁĄCZONE, aby przypadkowe kliknięcie
// nie mogło uruchomić dowolnego kodu.
PdfView1.LinkOptions :=
  [loAutoGoto, loAutoOpenURI];  // bezpieczne ustawienia domyślne

// OnAnnotationLinkClick uruchamia się dla miejsc docelowych w dokumencie
// (przejścia do stron, nazwane miejsca docelowe, łańcuchy akcji). Ustaw
// Handled = True, aby zapobiec automatycznemu podążaniu za linkiem.
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;  // wyciszanie automatycznej obsługi
  end;
end;

// OnWebLinkClick uruchamia się dla ciągów URI odkrytych przez skaner
// linków webowych PDFium (automatycznie wykryte URL w strumieniu tekstu,
// nawet bez adnotacji /A <</S/URI...>>).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
  WebLinkIndex: Integer; const Url: WString;
  var Handled: Boolean);
begin
  Log.Add('Web link clicked: ' + string(Url));
end;

Edycja widżetów formularzy w przeglądarce

Zaznaczanie i Undo / Redo

// Na sfokusowanym widżecie AcroForm sześć nowych metod steruje historią
// edycji formularzy PDFium. Wszystkie sześć bezpiecznie zwraca, jeśli żaden
// widżet nie jest sfokusowany lub dokument nie zawiera 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;

Blokowanie przeglądarki dla kiosków

Wyłącz gesty nawigacji po stronach

// Wszystkie trzy domyślnie ustawione na True, dzięki czemu istniejące aplikacje
// aktualizują się bez zmiany zachowania. Przełącz je na False dla kiosków,
// paneli podglądu lub osadzeń tylko do odczytu bez tworzenia podklasy TPdfView.
PdfView1.AllowUserPageChange       := False;  // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // skoki kółkiem w górę/dół
PdfView1.AllowUserTextSelection    := False;  // zaznaczanie tekstu myszą/klawiaturą

// Ctrl+kółko jest zarezerwowane dla powiększenia i jest pomijane przez
// moduł nawigacji niezależnie od ChangePageOnMouseScrolling.

Boczny panel miniatur

Powiązanie TPdfThumbnailView z TPdfView

// TPdfThumbnailView (jednostka FPdfThumbnail) renderuje jedną miniaturę strony
// w każdym wierszu w przewijalnym panelu bocznym.
uses FPdfThumbnail;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ThumbView.Pdf              := Pdf1;
  ThumbView.ThumbnailWidth   := 120;
  ThumbView.ThumbnailHeight  := 160;
  ThumbView.SelectionColor   := $00CFA85F;  // ciepłe podświetlenie
  ThumbView.OnPageClick      := ThumbViewPageClick;
end;

procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
  PdfView1.PageNumber := PageIndex + 1; // PageIndex jest liczony od zera
end;

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

Kooperatywnie anulowalny eksport wsadowy

Wieloplikowy PDF do JPG z postępem per plik i per strona

// Wzorzec używany przez Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// i Demo\Lazarus\BatchExport. Jeden TPdf na plik, IPdfCancellationToken
// dla anulowania z UI, TPdfStreamAdapter dla buforowanego ładowania pliku.
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;

Współrzędne przeglądarki i testowanie trafień

Dopasuj bieżącą stronę i sprawdź tekst pod kursorem myszy

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;

Obsługa błędów

Niezawodne operacje na 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 i dostępność

Wykryj Tagged PDF i przejdź po drzewie struktury

// IsTagged jest tanim sondowaniem Catalog — True, gdy istnieje /StructTreeRoot.
// StructureElements materializuje drzewo w płaską tablicę rekordów
// TPdfStructureElement z typem, tytułem, tekstem alternatywnym, tekstem
// rzeczywistym, tekstem rozwinięcia, językiem, poziomem, indeksem rodzica
// oraz liczbą dzieci / marked content / atrybutów.
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;

Wybór trybu druku

Ustawienie trybu druku EMF / PostScript / image-mask

// SetPdfPrintMode jest funkcją globalną, która mapuje do
// FPDF_SetPrintMode PDFium. Użyj pasującej wartości TPdfPrintMode dla
// używanego sterownika drukarki.
SetPdfPrintMode(pmEmf);                   // GDI EMF (domyślnie)
// SetPdfPrintMode(pmTextOnly);           // renderowanie tylko tekstu
// SetPdfPrintMode(pmPostScript2);        // PostScript Level 2
// SetPdfPrintMode(pmPostScript3);        // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks);      // EMF + maski obrazów
// SetPdfPrintMode(pmPostScript3Type42);  // PostScript 3 + czcionki Type 42

Odczyt ustawień druku zamierzonych przez autora

// PrintCopies, PrintPageRanges, PrintScaling i PrintPaperHandling to
// wpisy słownika viewer-preference — kodują to, czego autor dokumentu
// chciał, aby czytniki PDF używały domyślnie.
var
  Ranges: TPrintPageRanges;
  Range: TPrintPageRange;
begin
  ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
  ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
    Ord(Pdf1.PrintScaling)));

  Ranges := Pdf1.PrintPageRanges; // zakresy liczone od 1
  for Range in Ranges do
    Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));

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

Akcje JavaScript dokumentu

Wyliczanie JavaScript drzewa nazw

// JavaScript na poziomie dokumentu jest przechowywany w drzewie nazw
// /Names /JavaScript. JavaScriptAction[i] zwraca jeden wpis;
// JavaScriptActions zwraca pełną tablicę.
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;

Wskazówki dotyczące wydajności

Optymalizacja operacji na 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;

// Ścieżka renderowania bez kopiowania (domyślnie od v1.21.0): RenderPage zapisuje
// bezpośrednio do bufora DIB docelowej TBitmap, gdy wywołujący przekazują
// wstępnie zaalokowaną bitmapę, unikając jednej kopii o rozmiarze szerokość * wysokość * 4 bajty.
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;