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
| Demo | Do czego służy | Czym różni się od pokrewnych dem |
|---|---|---|
PDFViewer | Ogólne przeglądanie i ocena funkcji | Główna przeglądarka łączy nawigację, wyszukiwanie, miniatury, tryby wyświetlania, drukowanie i pokaz możliwości |
MultiPageViewer | Strony 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 |
SplitView | Porównywanie stron lub dokumentów w osobnych panelach | Demonstruje niezależne pozycje widoków i kierowanie poleceń do aktywnego panelu, a nie układ dwustronowy w jednym widoku |
SearchAndSelect | Wyniki wyszukiwania i zaznaczanie po wielu stronach | Lista wyników i opcje wyszukiwania odsłaniają przepływ wyszukiwania bardziej bezpośrednio niż pasek narzędzi przeglądarki |
PrintPDF | Podgląd i zwykłe zadania drukowania | Zakresy stron, skalowanie, postęp i anulowanie tworzą główny przepływ drukowania |
ContentExtractionLab | Wspólne sprawdzanie kilku kategorii treści | Inwentarze TXT/JSON opisują obiekty i tekst podglądu; nie zastępują kompletnego eksportu tekstu ani plików obrazów |
ExtractImages | Eksport osadzonych obiektów obrazów | Wyodrę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 |
TableExtractionLab | Wykrywanie tabel i eksport CSV/JSON | Tabele 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 |
Attachment | Odczyt, dodawanie i eksport osadzonych załączników | Operacje na zawartości załączników wykraczają poza wypisywanie nazw i rozmiarów w ContentExtractionLab |
BatchExport | Eksport obrazów stron z wielu dokumentów | Wyjście strumieniowe, status dla każdego pliku i odizolowane niepowodzenia demonstrują przetwarzanie wsadowe, a nie pojedynczą konwersję |
CreatePDF | Tworzenie treści stron z podglądem na żywo | Wszystkie trzy natywne warianty tworzą przeszukiwalny tekst, kształty wektorowe, prawdziwy obraz rastrowy, tabele i adnotację rewizyjną; opcje przebudowują podgląd przed jawnym zapisem |
ImageToPDF | Budowanie stron z wejściowych plików obrazów | Układ obrazów, dopasowanie, kolejność i obsługa JPEG tworzą przepływ konwersji dokumentów |
MergePDF | Składanie stron z kilku PDF-ów | Sprawdź 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ę |
SplitPDF | Zapisywanie wybranych grup stron do osobnych PDF-ów | Nazewnictwo wyjścia i walidacja grup stron odróżniają go od scalania i renderowania obrazów stron |
WatermarkStamp | Nakładanie powtarzanych nakładek na istniejące strony | Wybierz docelowy PDF, wielokrotnego użytku PDF stempla i interwał stron; stemple skalują się do każdej strony, a niewybrane strony pozostają bez zmian |
FormFill | Interaktywne wypełnianie AcroForm i spłaszczanie | Wprowadzanie danych do pól i zapisane wyglądy odróżniają go od wymiany XFDF i zachowań specyficznych dla XFA |
AccessibilityReader | Interaktywne czytanie i mowa | Czytnik GUI demonstruje nawigację w czytaniu i podświetlanie, a nie audyt zgodności |
AccessibilityWorkbenchCli | Wsadowy przegląd dostępności i generowanie raportów | Ustalenia, podsumowania i bramki przeglądu służą automatyzacji; ustalenia nie zastępują ręcznego przeglądu dostępności |
StandardsLab | Walidacja i konwersja pod konkretne standardy | Interaktywne laboratorium odsłania operacje i opcje, zamiast wyłącznie generować raport zbiorczy |
PreflightReport | Interaktywne raporty standardów | GUI wspiera ręczną inspekcję i eksport raportów |
PreflightReportCli | Zautomatyzowane raporty standardów | Wsadowe wejścia, formaty raportów i bramki kodów wyjścia dostarczają automatyczny odpowiednik PreflightReport |
IntakeWorkbenchCli | Wsadowe przyjmowanie, triaż i routing | Raporty zbiorcze, bramki niepowodzeń i decyzje routingu czynią z niego przepływ przetwarzania wykraczający poza GUI SecurityAudit |
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
| Demo | Do czego służy | Czym różni się od pokrewnych dem |
|---|---|---|
SecurityAudit | Interaktywne sprawdzanie postawy bezpieczeństwa | GUI kładzie nacisk na uprawnienia, skrypty, podpisy i szczegóły bezpieczeństwa, a nie na routing plików |
XfdfLab | Import i eksport danych XFDF | Wymiana danych oraz jawny zapis zaimportowanego PDF demonstrują trwałość zmian; sam eksport XFDF nie zapisuje zmodyfikowanego PDF |
AccessibilityLab | Przejście przez API czytnika w konsoli | Kompaktowy, wykonywalny przewodnik odsłania jednostki czytania, ramki słów, strukturę i wyjście skryptu mowy |
ExtractText | Eksport kompletnego tekstu z wybranych stron | Wyjście z warstwy tekstowej, separatory stron i anulowanie odróżniają go od podglądów inwentarza i detekcji tabel; OCR nie jest wykonywany |
FontProperties | Sprawdzanie metryk czcionek i znaków | Otwiera się z rzeczywistymi metrykami czcionek i znaków pierwszego obiektu tekstowego; wybór innego wiersza pozwala porównać czcionki bez eksportu zawartości dokumentu |
NavigationLab | Zakładki, destynacje i akcje nawigacyjne | Kompaktowy przegląd API uzupełnia widoczne kontrolki nawigacji w PDFViewer |
PDFtoJpg | Renderowanie jednego dokumentu do obrazów stron | Kompaktowy przykład renderowania pojedynczego dokumentu; wariant Delphi udostępnia osobne zakresy stron, a BatchExport skupia się na wielu dokumentach wejściowych |
PrintPreferences | Arkusze N-up i preferencje drukowania autora PDF | Liczba kopii, filtrowanie stron parzystych i nieparzystych oraz preferencje podane przez autora są tu głównym tematem; przykład towarzyszy demu PrintPDF |
ViewerInteractionLab | Diagnozowanie interakcji myszy, klawiatury i współrzędnych | Log interakcji i konwersja współrzędnych strona/urządzenie czynią z niego narzędzie diagnostyczne API |
XfaLab | Statyczne pakiety XFA i możliwości runtime | Otwiera pakiety template i datasets zwykłym runtime; interaktywne renderowanie XFA wymaga runtime z włączonym XFA, w wariantach dla Delphi i Lazarus |
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
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
Pdf1.FileName := 'C:\MyDocument.pdf';
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
ShowMessage('Title: ' + Pdf1.Title);
ShowMessage('Author: ' + Pdf1.Author);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile('C:\MyDocument.pdf');
Pdf1.LoadDocument(Stream, True);
Pdf1.Active := True;
ShowMessage('PDF loaded from stream');
finally
Stream.Free;
end;
end;
Pdf1.CreateDocument;
Pdf1.Active := True;
Pdf1.AddPage(0, 612, 792);
Pdf1.PageNumber := 1;
Pdf1.AddText('Hello World!', 'Arial', 12, 100, 700, clBlack, $FF, 0.0);
Pdf1.UpdatePage;
Pdf1.SaveAs('C:\NewDocument.pdf');
Pdf1.Active := False;
var
PageText: WString;
RectText: WString;
begin
Pdf1.PageNumber := 1;
PageText := Pdf1.Text;
Memo1.Text := PageText;
RectText := Pdf1.TextInRectangle(100, 100, 500, 200);
ShowMessage('Text in rectangle: ' + RectText);
end;
var
Position: Integer;
begin
Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
while Position >= 0 do
begin
ShowMessage('Found at character: ' + IntToStr(Position));
Position := Pdf1.FindNext;
end;
end;
Pdf1.PageNumber := 1;
Pdf1.AddText('Document Title', 'Times New Roman', 16, 100, 750, clBlue);
Pdf1.AddText('This is the document content.', 'Arial', 12, 100, 700, clBlack);
Pdf1.UpdatePage;
var
I: Integer;
MetricSize: Single;
FontBytes: TBytes;
begin
Pdf1.PageNumber := 1;
for I := 0 to Pdf1.ObjectCount - 1 do
if Pdf1.ObjectType[I] = otText then
begin
MetricSize := 12.0;
FontBytes := Pdf1.FontData[I];
Memo1.Lines.Add('Object ' + IntToStr(I));
Memo1.Lines.Add('Base name: ' + Pdf1.FontBaseName[I]);
Memo1.Lines.Add('Family: ' + Pdf1.FontFamilyName[I]);
Memo1.Lines.Add('Embedded: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
Memo1.Lines.Add('Weight: ' + IntToStr(Pdf1.FontWeight[I]));
Memo1.Lines.Add('Italic angle: ' + IntToStr(Pdf1.FontItalicAngle[I]));
Memo1.Lines.Add('Ascent: ' + FloatToStr(Pdf1.FontAscent[I, MetricSize]));
Memo1.Lines.Add('Descent: ' + FloatToStr(Pdf1.FontDescent[I, MetricSize]));
Memo1.Lines.Add('Font data bytes: ' + IntToStr(Length(FontBytes)));
end;
if Pdf1.CharacterCount > 0 then
begin
Memo1.Lines.Add('First character size: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
Memo1.Lines.Add('First character weight: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
Memo1.Lines.Add('First character angle: ' + FloatToStr(Pdf1.CharacterAngle[0]));
end;
end;
Projekty Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties i Demo\Lazarus\Miscellaneous\FontProperties pokazują te same metadane poprzez TPdf i TPdfView
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
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
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;
// 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;
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);
// 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');
// 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;
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;
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
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
// 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;
// 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;
// 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;
// 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;
// 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;
// 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;
// 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;
// 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');
// 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
// 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
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;
// 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;
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ą
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
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
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
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
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
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
// 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;
// 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;
// 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.
// 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;
// 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;
procedure FitCurrentPage;
begin
PdfView1.Zoom := PdfView1.PageZoom[PdfView1.PageNumber];
end;
procedure InspectViewerPoint(X, Y: Integer);
var
PageNo: Integer;
PageX, PageY: Double;
CharIndex: Integer;
Ch: WString;
begin
PageNo := PdfView1.PageNumber;
if not PdfView1.DeviceToPage(X, Y, PageNo, PageX, PageY) then
Exit;
CharIndex := PdfView1.CharacterIndexAtPos(X, Y, 8, 8);
if CharIndex >= 0 then
begin
Ch := PdfView1.Text(CharIndex, 1);
ShowMessage(Format('Page %d, X %.2f, Y %.2f, character %s',
[PageNo, PageX, PageY, string(Ch)]));
end;
end;
function LoadPdfSafely(const FileName: string): Boolean;
begin
Result := False;
if not FileExists(FileName) then
Exit;
try
Pdf1.FileName := FileName;
Pdf1.Active := True;
Result := Pdf1.Active;
except
Result := False;
end;
end;
function ExtractTextSafely(PageNo: Integer): WString;
begin
Result := '';
if not Pdf1.Active then
Exit;
if (PageNo < 1) or (PageNo > Pdf1.PageCount) then
Exit;
Pdf1.PageNumber := PageNo;
Result := Pdf1.Text;
end;
// IsTagged 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;
// 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
// 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;
// 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;
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;