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 načtený ze streamu');
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 v obdélníku: ' + RectText);
end;
var
Position: Integer;
begin
Position := Pdf1.FindFirst('Hello', [seCaseSensitive]);
while Position >= 0 do
begin
ShowMessage('Nalezeno na znaku: ' + 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('Objekt ' + IntToStr(I));
Memo1.Lines.Add('Základní název: ' + Pdf1.FontBaseName[I]);
Memo1.Lines.Add('Rodina: ' + Pdf1.FontFamilyName[I]);
Memo1.Lines.Add('Vložený: ' + BoolToStr(Pdf1.FontIsEmbedded[I], True));
Memo1.Lines.Add('Tloušťka: ' + IntToStr(Pdf1.FontWeight[I]));
Memo1.Lines.Add('Kurzíva: ' + 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('Počet bajtů fontu: ' + IntToStr(Length(FontBytes)));
end;
if Pdf1.CharacterCount > 0 then
begin
Memo1.Lines.Add('Velikost prvního znaku: ' + FloatToStr(Pdf1.CharacterFontSize[0]));
Memo1.Lines.Add('Tloušťka prvního znaku: ' + IntToStr(Pdf1.CharacterFontWeight[0]));
Memo1.Lines.Add('Úhel prvního znaku: ' + FloatToStr(Pdf1.CharacterAngle[0]));
end;
end;
Projekty Demo\Delphi\FontProperties, Demo\CBuilder\FontProperties a Demo\Lazarus\FontProperties zobrazují stejná metadata přes TPdf i TPdfView
Projekty Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab a Demo\Lazarus\ContentExtractionLab převádějí extrakci obsahu do jednoho pracovního toku. Otevírají nebo vytvářejí PDF, umožňují vybrat metadata, text stránky, objekty stránky, obrázky, přílohy, odkazy, anotace, záložky a metriky fontů či znaků a pak vygenerují souhrn i podrobný report TXT nebo JSON. Laboratoř obsahuje také volbu kategorií vše nebo nic, kopírování reportu do schránky a akce pro uložení zdrojového PDF, aby uživatelé mohli mít vygenerovaný ukázkový PDF vedle reportu extrakce. Starší ukázky ExtractText, ExtractImages, Attachment a FontProperties zůstávají cílenými příklady; ExtractText podporuje volby rozsahu stránek a oddělovače stránek pro vytvoření textového výstupu po jednotlivých stránkách napříč Delphi, C++Builderem a Lazarusem, zatímco ContentExtractionLab je průřezová ukázka inventáře
var
I: Integer;
FieldInfo: TPdfFormFieldInfo;
begin
Pdf1.FormField[0] := 'John';
for I := 0 to Pdf1.FormFieldCount - 1 do
begin
FieldInfo := Pdf1.FormFieldInfo[I];
ShowMessage(FieldInfo.Name + ': ' + Pdf1.FormField[I]);
end;
end;
// Without flattening, FormField[i] := value writes only the /V entry —
// viditelný vzhled pochází z /AP streamu a nemusí se hned obnovit
// GenerateFormAppearances regenerates /AP for every widget, then
// FlattenAllPages bakes every page's annotations and widgets into
// trvalý, needitovatelný obsah
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := 'john@example.com';
Pdf1.GenerateFormAppearances;
if Pdf1.FlattenAllPages then
Pdf1.SaveAs('C:\Application.flat.pdf');
Pdf1.Active := False;
var
I: Integer;
Bitmap: TBitmap;
begin
for I := 0 to Pdf1.BitmapCount - 1 do
begin
Bitmap := Pdf1.Bitmap[I];
try
Bitmap.SaveToFile('C:\ExtractedImage' + IntToStr(I) + '.bmp');
finally
Bitmap.Free;
end;
end;
end;
var
JpegStream: TFileStream;
begin
JpegStream := TFileStream.Create('C:\MyImage.jpg', fmOpenRead or fmShareDenyWrite);
try
Pdf1.AddJpegImage(JpegStream, 100, 500, 200, 150);
finally
JpegStream.Free;
end;
Pdf1.AddPicture(Image1.Picture, 100, 300, 150, 100);
Pdf1.UpdatePage;
end;
var
I: Integer;
Annotation: TPdfAnnotation;
begin
for I := 0 to Pdf1.AnnotationCount - 1 do
begin
Annotation := Pdf1.Annotation[I];
ShowMessage('Annotation ' + IntToStr(I) + ': ' + Annotation.ContentsText);
end;
end;
Pdf1.CreatePath(100, 100, 200, 150, fmAlternate, clYellow, $FF, True, clBlack, $FF, 2.0);
Pdf1.AddPath;
Pdf1.CreatePath(100, 100, fmNone, clBlack, $FF, True, clRed, $FF, 3.0);
Pdf1.LineTo(200, 100);
Pdf1.LineTo(150, 200);
Pdf1.ClosePath;
Pdf1.AddPath;
Pdf1.UpdatePage;
var
I: Integer;
Bookmarks: TBookmarks;
begin
Bookmarks := Pdf1.Bookmarks;
for I := 0 to Length(Bookmarks) - 1 do
ShowMessage(Bookmarks[I].Title + ' -> Page ' + IntToStr(Bookmarks[I].PageNumber));
end;
var
I: Integer;
Destination: TDestination;
begin
for I := 0 to Pdf1.DestinationCount - 1 do
begin
Destination := Pdf1.Destination[I];
if Destination.Name = 'Chapter1' then
begin
Pdf1.PageNumber := Destination.PageNumber;
Break;
end;
end;
end;
var
I: Integer;
AttachmentData: TBytes;
AttachmentName: WString;
FileStream: TFileStream;
begin
for I := 0 to Pdf1.AttachmentCount - 1 do
begin
AttachmentName := Pdf1.AttachmentName[I];
AttachmentData := Pdf1.Attachment[I];
FileStream := TFileStream.Create('C:\Extracted_' + string(AttachmentName), fmCreate);
try
if Length(AttachmentData) > 0 then
FileStream.WriteBuffer(AttachmentData[0], Length(AttachmentData));
finally
FileStream.Free;
end;
end;
if Pdf1.CreateAttachment('MyFile.txt') then
Pdf1.Attachment[Pdf1.AttachmentCount - 1] := TFile.ReadAllBytes('C:\MyFile.txt');
end;
Pdf1.AddPage(Pdf1.PageCount + 1, 612, 792);
Pdf1.AddPage(Pdf1.PageCount + 1, 595, 842);
Pdf1.AddPage(Pdf1.PageCount + 1, 400, 600);
var
SourcePdf: TPdf;
begin
SourcePdf := TPdf.Create(nil);
try
SourcePdf.FileName := 'C:\SourceDocument.pdf';
SourcePdf.Active := True;
Pdf1.ImportPages(SourcePdf, '1', Pdf1.PageCount + 1);
finally
SourcePdf.Free;
end;
end;
if Pdf1.PageCount > 1 then
Pdf1.DeletePage(Pdf1.PageCount);
// Vytvořit komprimovaný dokument PDF
Pdf1.CreateDocument;
Pdf1.Compressed := True; // zajistí kompresi všech streamů FlateDecode (výchozí)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // formát A4
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Uložit s volbami
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // přírůstkové uložení
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // odstranit zabezpečení
// Uložit do konkrétní cílové verze PDF. Kontrola verze PDF odmítne
// jakoukoli funkci zavedenou po zvoleném cíli (JBIG2Decode, MarkInfo,
// šifrování AES, anotace Polygon / Caret / Watermark / Redact, ...)
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Uložení odmítnuto: dokument obsahuje funkce novější než PDF 1.5');
// SaveAsPdfA post-processes the base save with an incremental update that
// injects an XMP metadata stream, an sRGB ICC OutputIntent, and an updated
// document catalog so the result is PDF/A-1b conformant. The bundled
// sRGB IEC61966-2.1 profile is used automatically when no custom profile
// je k dispozici
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('Archiv PDF/A-1b uložen');
// PDF/A s vlastním ICC profilem (například pro CMYK tiskové workflow)
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;
// Výstup PDF/A v paměti
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;
// Rychlá kontrola hlavičky — načte shodu bez spuštění
// plného validátoru. Výsledek: pacNone, pac1a, pac1b, pac2b, pac3b nebo
// 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 := 'Neznámá shoda';
end;
// Plný validátor s diagnostikou jednotlivých problémů
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 a Demo\Lazarus\StandardsLab načtou nebo vytvoří PDF, spustí ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR a ValidatePdfVT, a pak v jedné tabulce zobrazí každou zjištěnou úroveň shody i počet problémů. Tlačítka pro uložení volají SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR a SaveAsPdfVT, takže je pracovní tok markerového výstupu vidět bez psaní vlastního harnessu
Jednotka FPdfPreflightReport sdružuje ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR a ValidatePdfVT do jednoho objektu reportu. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport a Demo\CBuilder\PreflightReport umožňují uživatelům vybrat standardy, vygenerovat souhrn, prohlédnout stav, prioritu, kategorie problémů, počty kategorií, další akce, kódy problémů a doporučené akce, přepínat náhled mezi textem, Markdownem, JSON a CSV a exportovat reporty TXT, HTML, Markdown, JSON nebo CSV. Delphi GUI ukázka navíc přidává náhled Action Plan, který shrnuje nevyhovující standardy, priority, kódy problémů a doporučení do seznamu kroků k nápravě. Demo\Delphi\PreflightReportCli zpřístupňuje stejný tok reportu jako konzolový pracovní postup s vstupními a výstupními argumenty, volitelným heslem, volbou výstupního formátu včetně plan / actionplan, filtrováním standardů, volitelným vložením reportu do jediného souboru přes attach=output.pdf, chybovými kódy pro CI přes failon=, zpracováním batch=list.txt, prohledáváním adresáře přes batchdir=folder s volitelnou rekurzí a stabilním řazením podle cesty, směrováním reportů přes outdir=reports, názvy reportů odolnými proti kolizím při duplicitních názvech vstupních souborů, souhrny TXT / JSON / HTML s celkovými součty a součty podle standardů, manifesty CSV s opakovaným nastavením pro každou položku a ukázkový režim bez argumentů pro skripty a CI joby. Vygenerovaný report uvádí, že vestavěné validátory pokrývají kontroly na úrovni markerů a vybraných souborových kontrol, takže plný content-level preflight lze stále předat specializovanému validačnímu enginu.
// LoadCustomDocument umožňuje PDFium načítat bloky z libovolného sekvenčně
// přístupného TStream na vyžádání. Stream se NEkopíruje do paměti, takže
// vícegigabajtové PDF, vzdálené HTTP body streamy i zdroje v databázi jsou
// použitelné bez předběžného bufferu
var
FileStream: TFileStream;
begin
// Streamování ze souboru (bez kopie do paměti)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ vlastnictví je předáno — Pdf1 uvolní FileStream při UnloadDocument
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Externě vlastněný stream (volající jej uvolní 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 zpřístupňuje IPdfCancellationToken /
// IPdfCancellationTokenSource pro zrušení z UI, které funguje
// napříč dlouhotrvajícími exportními a vykreslovacími cestami
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... uživatel klikne na Zrušit ...
CancelSource.Cancel;
// Pracovník průběžně kontroluje CancelToken.IsCancelled nebo jej
// vykreslovací cesta dotazuje přes PDFium callback IFSDK_PAUSE
if CancelToken.IsCancelled then
Memo1.Lines.Add('Zrušeno uživatelem');
end;
// RenderPageProgressive umožňuje dlouhé vykreslování ve vysokém DPI
// přerušit uprostřed stránky, když uživatel klikne na Cancel, místo aby
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('Vykreslení zrušeno — k dispozici je částečný výsledek');
prsFailed: Memo1.Lines.Add('PDFium nahlásilo FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> spustí pracovník na pozadí a pošle obálku
// TPdfFutureResult<T> zpět na hlavní vlákno
//
// Důležité: TPdf serializuje volání vykreslení pro každou instanci, ale
// pracovník stále řídí dispatch i životnost dokumentu. Neměňte TPdf, když
// právě běží render; dávkový export obvykle drží jednu instanci TPdf na soubor
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('Zrušeno');
pfsFailed: Log.Add('Pracovník selhal: ' + AResult.ErrorMessage);
end;
end);
end;
// FPdfMatrix zapouzdřuje FS_MATRIX z PDFium, takže volající mohou
// sestavovat transformaci deklarativně a předat ji do FPDFPageObj_SetMatrix
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // posun o 1 in doprava, ~2,8 in nahoru
M.Scale(0.5, 0.5); // razítko na polovinu velikosti
M.Rotate(15); // otočení proti směru hodin o 15 stupňů
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // post-multiply s další maticí
// Aplikovat na libovolný PDFium page object (text / path / image / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex kopíruje explicitní pole indexů od nuly ze zdrojového
// PDF do tohoto dokumentu. InsertAt = 0 vloží před stránku 1; PageCount
// přidá na konec
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Importovat stránky 0, 2, 4 (jedna-based: stránky 1, 3, 5) ze Source
// a připojit je na konec Pdf1
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Prázdné pole importuje každou zdrojovou stránku
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne vrací zcela nový TPdf, jehož stránky jsou kompozity
// NumX*NumY tohoto dokumentu. OutputWidth/Height jsou uživatelské jednotky PDF
// (1 jednotka = 1/72 in)
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 landscape: 842 x 595 pt, 2 columns x 2 rows
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages bere indexy stránek od nuly, které se mají přesunout, a také
// cílový index první přesunuté stránky po dokončení přesunu
// Ostatní stránky se přesunou kolem posunutého bloku, takže délka dokumentu
// zůstane stejná
//
// Příklad: v 5stránkovém dokumentu s čísly stránek [0,1,2,3,4]
// MovePages([2, 3], 0) přeuspořádá na [2, 3, 0, 1, 4]
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage vytvoří z libovolné stránky libovolného jiného TPdf
// znovupoužitelný handle Form XObject. Tento handle pak můžete otisknout na
// libovolný počet stránek TOHOTO dokumentu — každý otisk je jediný PDFium
// page object, který lze umístit, škálovat a otočit přes matrix API
uses FPdfMatrix, FPdfView;
var
WatermarkSource: TPdf;
XObj: TPdfXObject;
PageObj: FPDF_PAGEOBJECT;
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
I: Integer;
begin
WatermarkSource := TPdf.Create(nil);
try
WatermarkSource.FileName := 'C:\Watermarks\Confidential.pdf';
WatermarkSource.Active := True;
// Zabalit stránku 0 z WatermarkSource jako znovupoužitelný 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;
// Vycentrovat vodoznak na stránce
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; // zavře FPDF_XOBJECT handle
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
Projekty Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp a Demo\CBuilder\WatermarkStamp převádějí tento vzor do spustitelného workflow: vytvoří cílové PDF a znovupoužitelný razítkový PDF, obalí stránku razítka pomocí CreateXObjectFromPage, vloží stejné Form XObject na každou cílovou stránku, použijí transformace TPdfMatrix pro centrované watermarky a razítka vpravo nahoře a před uložením výsledku přidají volitelné štítky čísel stránek
// AddImage(FileName) přijímá libovolný formát registrovaný ve VCL nebo LCL
// grafických jednotkách (BMP, PNG přes PngImage, JPG, ...)
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) přeskočí mezičlánek TPicture, ideální když bitmapa už
// pochází z vykreslování nebo dávkové generace
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 a Demo\Lazarus\ImageToPDF převádějí toto do plného dávkového pracovního toku: vybrat více souborů s obrázky, zobrazit náhled vybrané položky, vytvořit jednu PDF stránku na obrázek, přizpůsobit každý obrázek na stránku A4 na výšku nebo na šířku, uložit výsledek a otevřít vygenerované PDF
var
MatchCount: Integer;
begin
// Vykreslit masku clYellow přes každou shodu na aktuální stránce zobrazení
// Přepnutí na jinou stránku zvýraznění automaticky vymaže
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d shod na této stránce', [MatchCount]);
// Programově odstranit překrytí před změnou stránky
PdfView1.ClearHighlight;
end;
// FitMode udržuje dlouhé dokumenty ve výřezu při změně velikosti nebo stránky
// Přímé nastavení Zoom FitMode zruší (vrátí se na pfmNone)
PdfView1.FitMode := pfmFitPage; // celá stránka ve výřezu
// PdfView1.FitMode := pfmFitWidth; // šířka stránky odpovídá šířce výřezu
// PdfView1.FitMode := pfmActualSize; // 100 %
// PageColor odděluje vykreslenou PDF stránku od Color hostitelského ovládacího prvku
// typické nastavení pro tmavý režim ponechá posuvnou oblast tmavou, zatímco
// PDF stránka zůstává papírově bílá
PdfView1.Color := clBlack; // oblast posuvu
PdfView1.PageColor := clWhite; // pozadí PDF stránky
// Volitelný stín a okraj stránky, aby stránka vystoupila z tmavého pozadí
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
Projekty Demo\Delphi\ViewerInteractionLab, Demo\CBuilder\ViewerInteractionLab a Demo\Lazarus\ViewerInteractionLab udržují moderní interakční povrch TPdfView v jednom kompaktním formuláři: otevřít nebo vytvořit ukázkové PDF, přepnout DisplayMode, použít FitMode, změnit PageColor, otáčet stránky, zvýraznit shody na aktuální stránce pomocí HighlightSearchText, zapnout nebo vypnout uživatelský výběr textu, zkontrolovat SelectedText, volat SelectAll, CopySelectionToClipboard a ClearSelection, a sledovat, jak se souřadnice DeviceToPage mění ve stavovém řádku při pohybu myši nad stránkou
Projekty Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect a Demo\Lazarus\SearchAndSelect převádějí pracovní tok prohlížeče pro vyhledávání a výběr do samostatných ukázek. Otevírají nebo vytvářejí PDF, vypisují výsledky hledání na všech stránkách s číslem stránky, indexem znaku a náhledem textu, podporují navigaci Previous / Next a přechod na výsledek dvojklikem, zvýrazňují shody na aktuální stránce pomocí HighlightSearchText, zpřístupňují volby match-case a whole-word, přepínají AllowUserTextSelection, zobrazují náhled SelectedText, ovládají SelectAll, CopySelectionToClipboard a ClearSelection z tlačítek a umožňují přepínat mezi single a spread režimem zobrazení
Projekty Demo\Delphi\PrintPreferences, Demo\CBuilder\PrintPreferences a Demo\Lazarus\PrintPreferences čtou tiskové předvolby autora před tiskem. Zobrazují PrintCopies, PrintPageRanges, PrintScaling a PrintPaperHandling, mohou zkopírovat autorem dodané počty kopií a rozsahy do vstupů tisku a ukazují, jak SetPdfPrintPaperHandlingDevMode mapuje záměr oboustranného tisku PDF do Windows DEVMODE
Projekty Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF a Demo\Lazarus\PrintPDF ukazují standardní pracovní tok tisku: otevřít PDF, zobrazit náhled stránek, zvolit rozsahy stránek a počet kopií v tiskovém dialogu platformy, respektovat režim řazení kopií, vykreslit každou stránku přes TPdf.RenderPage a zobrazit průběh tisku s možností zrušení. Delphi ukázka také přijímá přetažené PDF soubory pro rychlé načtení
Projekty Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer a Demo\Lazarus\MultiPageViewer zkoušejí plynulé, rozložené a obálkové zobrazení s běžnou navigací po stránkách a zoom workflow. Hodí se také pro testování rychlosti otevření první stránky a odezvy vykreslování u velmi velkých PDF: v testech velkých souborů mohou dokumenty velikosti 2.x GB, které v Acrobat nebo Foxit potřebují před prvním zobrazením 20-30 sekund, být přes cestu prohlížeče PDFiumPas použitelné téměř okamžitě
Projekty Demo\Delphi\SplitView, Demo\CBuilder\SplitView a Demo\Lazarus\SplitView ukazují porovnávání PDF vedle sebe. Ukázky v C++Builderu a Lazarusu se zaměřují na porovnání ve dvou nebo třech panelech, výběr aktivního pohledu, volitelné synchronizované navigační příkazy, sdílené zoom předvolby a rotaci pro vybraný pohled nebo všechny načtené pohledy. Tyto ukázky použijte pro porovnávání velkých dokumentů při zachování odezvy první použitelné části pohledu i následného vykreslování stránek; stejné PDF soubory velikosti 2.x GB, které mohou Acrobat nebo Foxit otevírat 20-30 sekund, mohou být v cestě prohlížeče PDFiumPas použitelné téměř okamžitě
Projekty Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit a Demo\Lazarus\SecurityAudit otevírají PDF jen pro čtení a vypisují stav oprávnění, vložené přílohy, akce JavaScriptu v dokumentu, anotace odkazů URI a Launch, webové odkazy, souhrny podpisů, stav XFA, dostupnost pomocných funkcí V8 a callbacky nepodporovaných funkcí. Stejné řádky souhrnu a nálezů lze uložit nebo zkopírovat jako TXT audit report nebo jako strukturovaný JSON. Jsou určené jako panely rizik hostitelské aplikace, ne jako detekce malwaru
// LinkOptions řídí automatické zpracování čtyř typů akcí PDF odkazu
// Výchozí hodnoty zapínají pouze goto a URI; launch (spustit program) a
// embedded GotoR (skok do jiného souboru) zůstávají VYPNUTÉ, aby náhodné kliknutí
// nemohlo spustit libovolný kód
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // safe defaults
// OnAnnotationLinkClick se vyvolá pro cíle v dokumentu (skoky na stránku,
// pojmenované cíle, řetězce akcí). Nastavte Handled = True, aby prohlížeč
// odkaz automaticky nenásledoval
procedure TForm1.PdfView1AnnotationLinkClick(Sender: TObject;
LinkIndex: Integer; const Action: TPdfAction;
var Handled: Boolean);
begin
if Action.Kind = paUri then
begin
if MessageDlg('Otevřít ' + Action.Uri + '?', mtConfirmation, [mbYes, mbNo], 0)
<> mrYes then
Handled := True; // potlačí automatické zpracování
end;
end;
// OnWebLinkClick se vyvolá pro řetězce URI zjištěné web-link skenerem PDFium
// (automaticky nalezené URL v textovém proudu, i bez anotace /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;
// On the focused AcroForm widget, six new methods drive PDFium's form
// edit history. All six short-circuit safely if no widget is focused or
// dokument neobsahuje 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;
// All three default to True so existing apps upgrade with no behaviour
// change. Flip them False for kiosks, preview panes, or read-only
// vložení bez nutnosti dědit z TPdfView
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // wheel up/down jumps
PdfView1.AllowUserTextSelection := False; // mouse/keyboard text selection
// Ctrl+wheel is reserved for zoom and is skipped by the navigation
// handler regardless of ChangePageOnMouseScrolling.
// TPdfThumbnailView (unit FPdfThumbnail) renders one page thumbnail per
// řádek v posuvném bočním panelu
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // warm highlight
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex is zero-based
end;
procedure TForm1.PdfView1PageNumberZměněno (Changed)(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Pattern used by Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport,
// and Demo\Lazarus\BatchExport. One TPdf per file, IPdfCancellationToken
// pro zrušení z UI, TPdfStreamAdapter pro bufferované načtení souboru
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 je levná kontrola katalogu - True, když existuje /StructTreeRoot
// StructureElements materialises the tree into a flat array of
// TPdfStructureElement records with type, title, alternate text, actual
// text, expansion text, language, level, parent index, and child / marked
// počty obsahu / atributů
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 is a global function that maps to PDFium's
// FPDF_SetPrintMode. Use the matching TPdfPrintMode value for the
// používaný ovladač tiskárny
SetPdfPrintMode(pmEmf); // GDI EMF (default)
// SetPdfPrintMode(pmTextOnly); // text-only rendering
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + image masks
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + Type 42 fonts
// PrintCopies, PrintPageRanges, PrintScaling, and PrintPaperHandling are
// the viewer-preference dictionary entries — they encode what the
// ke kterému chtěl autor dokumentu, aby se PDF čtečky chovaly jako výchozí
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // one-based ranges
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// Document-level JavaScript is stored in the /Names /JavaScript name
// tree. JavaScriptAction[i] returns one entry; JavaScriptActions returns
// celé pole
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;
// Bezkopírová renderovací cesta (výchozí od v1.21.0): RenderPage zapisuje
// directly into the destination TBitmap's DIB buffer when callers pass a
// předem alokovanou bitmapu, čímž se vyhne jedné kopii o velikosti width * height * 4 bajtů
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;