La raccolta comprende 32 argomenti: 32 progetti Delphi, 31 C++Builder e 32 Lazarus, per un totale di 95 progetti nativi. Ogni piattaforma mantiene 22 demo di workflow completi nella directory principale. Dieci argomenti mirati si trovano sotto Miscellaneous, con 29 progetti nativi nelle tre piattaforme; XfaLab è disponibile per Delphi e Lazarus
Si apre prima un workflow della directory principale: PDFViewer per il feature tour, CreatePDF per la creazione live, ContentExtractionLab per un inventario immediato, FormFill per i moduli modificabili, StandardsLab per validazione e conversione, oppure IntakeWorkbenchCli per l'acquisizione automatizzata. Questi sei entry point producono risultati funzionanti all'istante; gli esempi mirati qui sotto servono quando bisogna esaminare una singola API nel dettaglio
| Demo | A cosa serve | In cosa differisce dai demo correlati |
|---|---|---|
PDFViewer | Visualizzazione generale e valutazione delle funzionalità | Il visualizzatore principale combina navigazione, ricerca, miniature, modalità di visualizzazione, stampa e una panoramica delle funzionalità |
MultiPageViewer | Pagine continue, doppie pagine e layout con copertina | Un esempio mirato sui layout che usa le API di selezione integrate nel visualizzatore; per l'esperienza di visualizzatore più ampia si usa PDFViewer |
SplitView | Confrontare pagine o documenti in riquadri separati | Dimostra posizioni delle view indipendenti e l'instradamento dei comandi al riquadro attivo, invece del layout a due pagine in un'unica view |
SearchAndSelect | Risultati di ricerca tra le pagine e selezione | Un elenco di risultati e le opzioni di ricerca espongono il workflow di ricerca in modo più diretto di una barra degli strumenti del visualizzatore |
PrintPDF | Anteprima e lavori di stampa ordinari | Intervalli di pagine, ridimensionamento, progresso e annullamento costituiscono il workflow di stampa principale |
ContentExtractionLab | Ispezionare insieme più categorie di contenuto | Gli inventari TXT/JSON descrivono gli oggetti e mostrano testi in anteprima; non sostituiscono l'esportazione completa del testo o dei file immagine |
ExtractImages | Esportare oggetti immagine incorporati | Estrae bitmap delle immagini invece di screenshot di pagine intere; il campione integrato contiene due oggetti immagine reali su ciascuna delle due pagine |
TableExtractionLab | Rilevare tabelle ed esportare CSV/JSON | Tabelle con righe di bordo e tabelle allineate con spazi bianchi, celle unite, gruppi di continuazione e controlli di confidenza sono indipendenti dall'estrazione di testo semplice |
Attachment | Leggere, aggiungere ed esportare allegati incorporati | Le operazioni sui payload degli allegati vanno oltre l'elenco di nomi e dimensioni di ContentExtractionLab |
BatchExport | Esportare immagini di pagina da più documenti | Output in streaming, stato per file e guasti isolati dimostrano l'elaborazione batch invece di una singola conversione |
CreatePDF | Creare contenuto di pagina con un'anteprima live | Tutte e tre le varianti native creano testo ricercabile, forme vettoriali, un'immagine raster reale, tabelle e un'annotazione di revisione; le opzioni ricostruiscono l'anteprima prima di un salvataggio esplicito |
ImageToPDF | Costruire pagine da file immagine in input | Layout delle immagini, adattamento, ordinamento e gestione JPEG costituiscono un workflow di conversione di documenti |
MergePDF | Assemblare pagine da più PDF | Esaminare gli input per controllare conteggi delle pagine e intervalli di output, riordinare le sorgenti e avviare l'unione solo dopo la validazione di tutti gli input |
SplitPDF | Scrivere gruppi di pagine selezionati in PDF separati | Denominazione degli output e validazione dei gruppi di pagine si distinguono dall'unione e dal rendering in immagini di pagina |
WatermarkStamp | Applicare overlay ripetuti a pagine esistenti | Scegliere un PDF di destinazione, un PDF timbro riutilizzabile e un intervallo di pagine; i timbri si adattano a ogni pagina e quelle non selezionate restano invariate |
FormFill | Inserimento interattivo in AcroForm e appiattimento | L'input nei campi e le appearance salvate si distinguono dall'interscambio XFDF e dal comportamento specifico di XFA |
AccessibilityReader | Lettura interattiva e sintesi vocale | Il lettore GUI dimostra navigazione in lettura ed evidenziazione, non un audit di conformità |
AccessibilityWorkbenchCli | Revisione di accessibilità batch e generazione di report | Riscontri, riepiloghi e gate di revisione servono l'automazione; i riscontri non sostituiscono la revisione manuale di accessibilità |
StandardsLab | Validazione e conversione specifiche per gli standard | Il laboratorio interattivo espone operazioni e opzioni invece di generare soltanto un report aggregato |
PreflightReport | Report sugli standard interattivi | La GUI supporta l'ispezione manuale e l'esportazione dei report |
PreflightReportCli | Report sugli standard automatizzati | Input in batch, formati di report e gate sul codice di uscita costituiscono la controparte automatizzata di PreflightReport |
IntakeWorkbenchCli | Acquisizione batch, triage e instradamento | Report aggregati, gate sui guasti e decisioni di instradamento ne fanno un workflow di elaborazione che va oltre la GUI di SecurityAudit |
Aprire questi progetti da Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous o Demo\Lazarus\Miscellaneous. Mantengono ricette API e attività di esportazione mirate, mentre la directory principale si concentra su esperienze complete. Verifiche Unicode di base e la guida fissa per creare ed elencare annotazioni sono coperte da creazione, estrazione, scambio XFDF e test API; non hanno più progetti demo separati
| Demo | A cosa serve | In cosa differisce dai demo correlati |
|---|---|---|
SecurityAudit | Esaminare interattivamente la sicurezza del documento | La GUI si concentra su permessi, script, firme e dettagli di sicurezza, anziché sull'instradamento dei file |
XfdfLab | Importare ed esportare dati XFDF | Lo scambio e il salvataggio esplicito del PDF importato mostrano la persistenza; esportare solo XFDF non salva il PDF modificato |
AccessibilityLab | Percorrere le API di lettura in una console | Un percorso eseguibile compatto espone unità di lettura, box delle parole, struttura e output degli script di sintesi vocale |
ExtractText | Esportare il testo completo dalle pagine selezionate | Output dal livello di testo, separatori di pagina e annullamento si distinguono dalle anteprime di inventario e dal rilevamento delle tabelle; non viene eseguito alcun OCR |
FontProperties | Ispezionare le metriche di font e caratteri | Parte con le metriche reali di font e caratteri del primo oggetto di testo; si seleziona un'altra riga per confrontare i font senza esportare i payload del documento |
NavigationLab | Segnalibri, destinazioni e azioni di navigazione | La panoramica compatta delle API completa i controlli di navigazione visibili in PDFViewer |
PDFtoJpg | Renderizzare un documento in immagini di pagina | Un esempio compatto di rendering su un singolo documento; Delphi espone intervalli di pagine discreti, mentre BatchExport si concentra su più documenti in input |
PrintPreferences | Fogli N-up e preferenze di stampa dell'autore del PDF | Copie, filtro pari/dispari e preferenze fornite dall'autore sono il focus didattico; è un complemento a PrintPDF |
ViewerInteractionLab | Diagnosticare le interazioni di mouse, tastiera e coordinate | Il log delle interazioni e la conversione tra coordinate pagina e dispositivo ne fanno uno strumento di diagnostica delle API |
XfaLab | Pacchetti XFA statici e capacità del runtime | Apre i pacchetti template e datasets con il runtime ordinario; il rendering XFA interattivo richiede un runtime con supporto XFA, con varianti Delphi e Lazarus |
PDFViewer apre il proprio PDFiumDemoShowcase.pdf in bundle, un documento di sei pagine con testo ricercabile, grafici vettoriali, due immagini incorporate, una tabella, quattro campi AcroForm, segnalibri dei capitoli, link, una nota di revisione e due allegati. La barra delle esperienze offre Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF ed Explore forms; ogni azione agisce sul documento corrente
CreatePDF apre un'anteprima live del report su due pagine. Se ne modificano titolo e autore, oppure si attivano e disattivano forme, tabella e filigrana per ricostruire il contenuto reale delle pagine; l'opzione Unicode aggiunge una terza pagina. Non si scrive nulla finché non si salva, e il PDF salvato resta ricercabile
MultiPageViewer, SearchAndSelect, ContentExtractionLab e FormFill aprono lo stesso documento per i rispettivi workflow, con risultati di ricerca, inventario di estrazione e campi modificabili pronti all'istante. Miscellaneous\NavigationLab usa la propria copia locale per un percorso tra le API di segnalibri e destinazioni
Attachment parte con due file incorporati reali. PrintPreferences parte con quattro pagine e le preferenze dell'autore per due copie, intervalli di pagine selezionati, ridimensionamento e duplex; il workflow di stampa attuale applica copie e intervalli di pagine, mentre ridimensionamento e duplex vengono ispezionati e riportati. XfaLab parte con pacchetti template e datasets effettivi per l'ispezione dello XFA statico; il rendering XFA interattivo richiede un runtime appropriato e resta una funzionalità separata
Ogni progetto di visualizzazione, moduli, estrazione e navigazione contiene il proprio PDFiumDemoShowcase.pdf. Si copia la directory del progetto e si conserva questo input in bundle accanto all'eseguibile distribuito; le build Lazarus lo predispongono automaticamente. Il tour funziona offline, e anche i visualizzatori generici e gli esempi di estrazione offrono contenuti di fallback generati quando il PDF locale non è disponibile
Ogni demo nativo contiene la propria implementazione di esempio. Gli entry point Delphi e Lazarus di AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli e PreflightReportCli includono il workflow completo nella directory del progetto, comprese l'inizializzazione specifica del compilatore e la scrittura JPEG. Anche gli esempi di allegati, preferenze di stampa e XFA costruiscono localmente i propri input specifici di ciascuna funzione. Fuori dal progetto copiato servono solo la libreria, il runtime nativo corrispondente e le normali dipendenze del framework del compilatore
L'estrazione di oggetti immagine è la scelta giusta quando servono bitmap incorporate, il rendering di pagina quando serve la pagina visibile, l'estrazione del testo quando il PDF ha già un livello di testo. Un report che elenca queste categorie non esporta i payload completi. Questi confini mantengono utili gli esempi mirati senza dilatare ogni demo in un altro visualizzatore o workbench per usi generali
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;
I progetti Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties e Demo\Lazarus\Miscellaneous\FontProperties mostrano gli stessi metadati sia tramite TPdf sia tramite TPdfView
I progetti Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab e Demo\Lazarus\ContentExtractionLab trasformano l'estrazione di contenuti in un unico workflow. Aprono o creano un PDF, permettono di scegliere metadati, testo di pagina, oggetti di pagina, immagini, allegati, link, annotazioni, segnalibri e metriche di font / caratteri, quindi generano un riepilogo più un report TXT o JSON dettagliato. Il laboratorio include anche la selezione di categorie tutto / niente, la copia del report negli appunti e le azioni di salvataggio del PDF sorgente affinché gli utenti possano conservare il PDF di esempio generato accanto al suo report di estrazione. ExtractImages e Attachment offrono workflow di esportazione dei payload, mentre Miscellaneous\ExtractText e Miscellaneous\FontProperties conservano esempi mirati sulle API; ExtractText supporta le opzioni di intervallo di pagine e di separatore di pagine per produrre output di testo per pagina in Delphi, C++Builder e Lazarus, mentre ContentExtractionLab è l'esempio trasversale di inventario
I progetti Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab e Demo\Lazarus\TableExtractionLab trasformano il rilevamento delle tabelle in un unico flusso di lavoro. Il laboratorio costruisce un documento di esempio contenente una tabella con righe di bordo e celle di intestazione unite, una tabella allineata con spazi bianchi senza bordi e una tabella lunga che si interrompe oltre il confine di pagina, poi esegue ExtractTables per la pagina corrente oppure ExtractDocumentTables per l'intero documento e riporta righe, colonne, valori RowSpan e ColumnSpan, flag di intestazione, modalità di rilevamento, confidenza e gruppi di continuazione. Le opzioni DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings e MinConfidence sono modificabili nell'interfaccia utente, e la tabella selezionata viene esportata tramite TPdfTable.ToCsv e TPdfTable.ToJson. Il laboratorio elabora anche un'intera cartella in batch: Batch folder esegue ExtractDocumentTables su ogni PDF, riporta i conteggi delle tabelle per documento, segnala le scansioni prive di livello di testo e riprova i documenti vuoti con un preset di colonne compatte; Export all CSV scrive ogni tabella rilevata accanto ai file di origine. Ogni documento si apre nella propria istanza TPdf, così un file illeggibile non può influire sul resto del batch
var
I: Integer;
FieldInfo: TPdfFormFieldInfo;
begin
Pdf1.FormField[0] := 'John';
for I := 0 to Pdf1.FormFieldCount - 1 do
begin
FieldInfo := Pdf1.FormFieldInfo[I];
ShowMessage(FieldInfo.Name + ': ' + Pdf1.FormField[I]);
end;
end;
// Without flattening, FormField[i] := value writes only the /V entry —
// the visible appearance comes from the /AP stream and may not refresh
// GenerateFormAppearances regenerates /AP for every widget, then
// FlattenAllPages bakes every page's annotations and widgets into
// permanent, non-editable content
Pdf1.FileName := 'C:\Application.pdf';
Pdf1.Active := True;
Pdf1.FormField[0] := 'John Smith';
Pdf1.FormField[1] := '[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);
// Create a compressed PDF document
Pdf1.CreateDocument;
Pdf1.Compressed := True; // ensure all streams are FlateDecode compressed (default)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // A4 size
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Save with options
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // incremental save
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // remove security
// Save to a specific PDF version target. The PDF version validator rejects
// any feature introduced after the chosen target (JBIG2Decode, MarkInfo,
// AES encryption, Polygon / Caret / Watermark / Redact annotations, ...)
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Save rejected: document contains features newer than PDF 1.5');
// SaveAsPdfA post-processes the base save with an incremental update that
// injects an XMP metadata stream, an sRGB ICC OutputIntent, and an updated
// document catalog so the result is PDF/A-1b conformant. The bundled
// sRGB IEC61966-2.1 profile is used automatically when no custom profile
// is supplied
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('Saved PDF/A-1b archive');
// PDF/A with a custom ICC profile (CMYK printing pipelines for example)
var
Opts: TPdfASaveOptions;
begin
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
Opts.IccProfileData := TFile.ReadAllBytes('C:\Profiles\Coated_GRACoL_2006.icc');
Pdf1.SaveAsPdfA('C:\Report.cmyk.pdfa.pdf', Opts);
end;
// In-memory PDF/A output
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
Opts := Default(TPdfASaveOptions);
Opts.Conformance := pac1b;
if Pdf1.SaveAsPdfAToStream(Stream, Opts) then
UploadToArchive(Stream);
finally
Stream.Free;
end;
end;
var
Validation: TPdfAValidationResult;
Issue: TPdfAValidationIssue;
begin
Pdf1.FileName := 'C:\Incoming\report.pdf';
Pdf1.Active := True;
// Cheap header-style probe — reads the conformance without iterating
// the full validator. Result: pacNone, pac1a, pac1b, pac2b, pac3b, or
// pacUnknown
case Pdf1.PdfAConformance of
pac1b: Status.Caption := 'PDF/A-1b';
pac2b: Status.Caption := 'PDF/A-2b';
pacNone: Status.Caption := 'Not PDF/A';
else
Status.Caption := 'Unknown conformance';
end;
// Full validator with per-issue diagnostics
Validation := Pdf1.ValidatePdfA;
Memo1.Lines.Add('Conformance: ' + GetEnumName(TypeInfo(TPdfAConformance),
Ord(Validation.Conformance)));
for Issue in Validation.Issues do
Memo1.Lines.Add('- ' + Issue.Description);
end;
I progetti Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab e Demo\Lazarus\StandardsLab caricano o creano un PDF, eseguono ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR e ValidatePdfVT, quindi mostrano in un'unica griglia ciascun livello di conformità rilevato e il conteggio dei problemi. I loro pulsanti di salvataggio chiamano SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR e SaveAsPdfVT in modo che il workflow di output con marcatori sia visibile senza scrivere un harness personalizzato
L'unità FPdfPreflightReport avvolge ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR e ValidatePdfVT in un unico oggetto report interrogabile con gravità Info / Warning / Error, aggregazione di stati e problemi, lookup, ricerca, filtraggio e impronte SHA-256 stabili. I report possono essere emessi come testo, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON o XML nativo. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport e Demo\CBuilder\PreflightReport forniscono workflow interattivi di selezione e anteprima, mentre Demo\Delphi\PreflightReportCli aggiunge argomenti di input / output scriptabili, filtro per standard, incorporamento opzionale dell'allegato del report, gating del codice di uscita per la CI, elaborazione di elenchi batch e di directory, routing a prova di collisione, riepiloghi aggregati e manifest CSV. Il report generato dichiara che i validatori incorporati coprono i controlli a livello di marcatore e una selezione di controlli a livello di file, quindi il preflight completo a livello di contenuto può comunque essere delegato a un motore di validazione dedicato
// LoadCustomDocument lets PDFium pull blocks from any seekable TStream on
// demand. The stream is NOT copied into memory, so multi-GB PDFs, remote
// HTTP body streams, and database-backed sources are all viable without
// an up-front buffer
var
FileStream: TFileStream;
begin
// Read-from-file streaming (no in-memory copy)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ ownership transferred — Pdf1 frees FileStream on UnloadDocument
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Externally-owned stream (caller frees it after UnloadDocument)
var
Stream: TFileStream;
begin
Stream := TFileStream.Create('C:\Live.pdf',
fmOpenRead or fmShareDenyNone);
try
Pdf1.LoadCustomDocument(Stream, False);
Pdf1.Active := True;
DoWork;
Pdf1.Active := False;
finally
Stream.Free;
end;
end;
// FPdfAsync exposes IPdfCancellationToken /
// IPdfCancellationTokenSource for cancel-from-UI semantics that work
// across the long-running export and render paths
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// user clicks Cancel
CancelSource.Cancel;
// The worker periodically checks CancelToken.IsCancelled, or the render
// path polls it through PDFium's IFSDK_PAUSE callback
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive lets a long high-DPI render abort mid-page when
// the user clicks Cancel, instead of blocking the caller until done
var
Status: TPdfProgressiveStatus;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Status := Pdf1.RenderPageProgressive(Bitmap, 0, 0, Bitmap.Width,
Bitmap.Height, CancelToken, ro0, [reAnnotations], clWhite);
case Status of
prsDone: SaveBitmap(Bitmap);
prsCancelled: Memo1.Lines.Add('Render cancelled — partial result available');
prsFailed: Memo1.Lines.Add('PDFium reported FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> spins up a worker on a background thread and posts a
// TPdfFutureResult<T> envelope back to the main thread
//
// Important: TPdf serializes render calls per instance, but the worker still
// owns dispatch and document lifetime. Do not mutate a TPdf while a render is
// in flight; batch export usually keeps one TPdf per file
type
TRenderResult = record
Bitmap : TBitmap;
PageNo : Integer;
end;
var
Future: TPdfFuture<TRenderResult>;
begin
Future := TPdfFuture<TRenderResult>.Create(
function (const ACancelToken: IPdfCancellationToken): TRenderResult
var
LocalPdf: TPdf;
begin
LocalPdf := TPdf.Create(nil);
try
LocalPdf.FileName := 'C:\Huge.pdf';
LocalPdf.Active := True;
LocalPdf.PageNumber := 1;
Result.Bitmap := LocalPdf.RenderPage(0, 0, 2480, 3508);
Result.PageNo := 1;
finally
LocalPdf.Free;
end;
end,
procedure (const AResult: TPdfFutureResult<TRenderResult>)
begin
case AResult.State of
pfsSuccess: PaintBitmapToView(AResult.Value.Bitmap);
pfsCancelled: Log.Add('Cancelled');
pfsFailed: Log.Add('Worker failed: ' + AResult.ErrorMessage);
end;
end);
end;
// FPdfMatrix wraps PDFium's FS_MATRIX so callers can build a transform
// declaratively and hand it to FPDFPageObj_SetMatrix
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // move 1in right, ~2.8in up
M.Scale(0.5, 0.5); // half-size stamp
M.Rotate(15); // 15-degree CCW rotation
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // post-multiply with another matrix
// Apply to any PDFium page object (text / path / image / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex copies an explicit zero-based index array from a
// source PDF into this document. InsertAt = 0 inserts before page 1;
// PageCount appends
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Import pages 0, 2, 4 (one-based: pages 1, 3, 5) from Source
// and append them at the end of Pdf1
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Empty array imports every source page
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne returns a brand-new TPdf whose pages are NumX*NumY
// composites of THIS document. OutputWidth/Height are PDF user units
// (1 unit = 1/72 in)
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// 4-up A4 landscape: 842 x 595 pt, 2 columns x 2 rows
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages takes the zero-based indices of the pages to move plus the
// destination index for the first moved page after the move completes
// Other pages shift around the moved block so the document length stays
// the same
//
// Example: in a 5-page document with pages numbered [0,1,2,3,4],
// MovePages([2, 3], 0) reorders to [2, 3, 0, 1, 4]
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage manufactures a reusable Form XObject handle from
// any page of any other TPdf. Stamp that handle onto as many pages of
// THIS document as you want — each stamp is a single PDFium page object
// that can be positioned, scaled, and rotated through the matrix API
uses FPdfMatrix, FPdfView;
var
WatermarkSource: TPdf;
XObj: TPdfXObject;
PageObj: FPDF_PAGEOBJECT;
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
I: Integer;
begin
WatermarkSource := TPdf.Create(nil);
try
WatermarkSource.FileName := 'C:\Watermarks\Confidential.pdf';
WatermarkSource.Active := True;
// Wrap page 0 of WatermarkSource as a reusable XObject
XObj := Pdf1.CreateXObjectFromPage(WatermarkSource, 0);
try
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageObj := Pdf1.InsertFormObjectFromXObject(XObj);
if PageObj = nil then Continue;
// Centre the watermark on the page
M := TPdfMatrix.Create;
try
M.Scale(0.5, 0.5);
M.Translate(0.25 * Pdf1.PageWidth, 0.5 * Pdf1.PageHeight);
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
Pdf1.UpdatePage;
end;
finally
XObj.Free; // closes the FPDF_XOBJECT handle
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
I progetti Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp e Demo\CBuilder\WatermarkStamp trasformano questo pattern in un workflow eseguibile: creano un PDF di destinazione e un PDF timbro riutilizzabile, incapsulano la pagina del timbro con CreateXObjectFromPage, inseriscono lo stesso Form XObject su ogni pagina di destinazione, applicano trasformazioni TPdfMatrix per filigrane centrate e timbri in alto a destra, e aggiungono etichette di numero di pagina opzionali prima di salvare il risultato
// AddImage(FileName) accepts any format registered with the VCL or LCL
// graphics units (BMP, PNG via PngImage, JPG, ...)
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) skips the TPicture intermediary, ideal when the
// bitmap already comes from rendering or batch generation work
var
Bitmap: TBitmap;
begin
Bitmap := Pdf1.RenderPage(0, 0, 595, 842);
try
Pdf1.PageNumber := 2;
Pdf1.AddImage(Bitmap, 50, 50, 250, 350);
Pdf1.UpdatePage;
finally
Bitmap.Free;
end;
end;
I progetti Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF e Demo\Lazarus\ImageToPDF trasformano tutto ciò in un workflow batch completo: selezione di più file immagine, anteprima dell'elemento selezionato, creazione di una pagina PDF per immagine, ridimensionamento di ciascuna immagine in una pagina A4 verticale o orizzontale, salvataggio del risultato e apertura del PDF generato
var
MatchCount: Integer;
begin
// Paint a clYellow mask over every match on the view's current page
// Switching to a different page clears the highlight automatically
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d match(es) on this page', [MatchCount]);
// Programmatically remove the overlay before the page changes
PdfView1.ClearHighlight;
end;
// FitMode keeps long documents framed during Resize or page changes
// Setting Zoom directly cancels FitMode (it reverts to pfmNone)
PdfView1.FitMode := pfmFitPage; // whole page in viewport
// PdfView1.FitMode := pfmFitWidth; // page width matches viewport width
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor decouples the rendered PDF page from the host control's Color
// — typical dark-mode viewer setup keeps the scroll area dark while the
// PDF page stays paper-white
PdfView1.Color := clBlack; // scroll area
PdfView1.PageColor := clWhite; // PDF page background
// Optional drop shadow and page border to lift the page off a dark bg
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
I progetti Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab e Demo\Lazarus\Miscellaneous\ViewerInteractionLab mantengono la moderna superficie di interazione di TPdfView in un unico form compatto: aprire o creare un PDF di esempio, alternare DisplayMode, applicare FitMode, cambiare PageColor, ruotare le pagine, evidenziare le occorrenze di ricerca della pagina corrente con HighlightSearchText, abilitare o disabilitare la selezione del testo da parte dell'utente, ispezionare SelectedText, chiamare SelectAll, CopySelectionToClipboard e ClearSelection, e osservare l'aggiornamento delle coordinate DeviceToPage nella barra di stato mentre il mouse si muove sulla pagina
I progetti Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect e Demo\Lazarus\SearchAndSelect trasformano il workflow di ricerca e selezione del visualizzatore in esempi autonomi. Aprono o creano un PDF, elencano i risultati di ricerca su tutte le pagine con numero di pagina, indice di carattere e testo di anteprima, supportano la navigazione Precedente / Successivo e il salto al risultato con doppio clic, evidenziano le corrispondenze della pagina corrente con HighlightSearchText, espongono le opzioni maiuscole/minuscole e parola intera, alternano AllowUserTextSelection, mostrano l'anteprima di SelectedText, pilotano SelectAll, CopySelectionToClipboard e ClearSelection dai pulsanti, e permettono di passare tra le modalità di visualizzazione singola e a doppia pagina
I progetti Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences e Demo\Lazarus\Miscellaneous\PrintPreferences leggono le preferenze di stampa dell'autore prima di stampare. Visualizzano PrintCopies, PrintPageRanges, PrintScaling e PrintPaperHandling, possono copiare le copie e gli intervalli forniti dall'autore negli input di stampa, e mostrano come SetPdfPrintPaperHandlingDevMode mappa l'intento duplex PDF in un DEVMODE di Windows
I progetti Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF e Demo\Lazarus\PrintPDF mostrano il workflow di stampa standard: apertura di un PDF, anteprima delle pagine, scelta degli intervalli di pagine e delle copie nella finestra di dialogo di stampa della piattaforma, rispetto della modalità di fascicolazione, rendering di ciascuna pagina tramite TPdf.RenderPage ed esposizione del progresso di stampa con annullamento. L'esempio Delphi accetta anche file PDF trascinati per un caricamento rapido
I progetti Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer e Demo\Lazarus\MultiPageViewer esercitano la visualizzazione continua, a doppia pagina e con gestione della copertina con i consueti workflow di navigazione e zoom delle pagine. Sono utili anche per testare la velocità di apertura alla prima pagina e la reattività del rendering su PDF molto grandi: nei test con file di grandi dimensioni, documenti da 2,x GB che possono far spendere ad Acrobat o Foxit 20-30 secondi prima della prima vista possono diventare usabili quasi immediatamente attraverso il percorso del visualizzatore di PDFium Delphi Component
I progetti Demo\Delphi\SplitView, Demo\CBuilder\SplitView e Demo\Lazarus\SplitView mostrano la revisione PDF side-by-side. Gli esempi C++Builder e Lazarus si concentrano sul confronto a due o tre riquadri, sulla selezione della view attiva, su comandi di navigazione sincronizzati opzionali, su preset di zoom condivisi e sulla rotazione per la view selezionata o per tutte le view caricate. Usare questi esempi per confrontare documenti di grandi dimensioni mantenendo reattive la prima vista utilizzabile e il rendering successivo delle pagine; gli stessi file PDF da 2,x GB che possono richiedere ad Acrobat o Foxit 20-30 secondi per l'apertura possono diventare usabili quasi immediatamente nel percorso del visualizzatore di PDFium Delphi Component
I progetti Demo\Delphi\Miscellaneous\SecurityAudit, Demo\CBuilder\Miscellaneous\SecurityAudit e Demo\Lazarus\Miscellaneous\SecurityAudit aprono un PDF in sola lettura ed elencano permessi, allegati incorporati, azioni JavaScript del documento, annotazioni di link URI e Launch, web link, riepiloghi delle firme, stato XFA, disponibilità degli helper V8 e Callback di funzionalità non supportate. Riepilogo e segnalazioni possono essere salvati o copiati come report TXT, oppure salvati in JSON strutturato. Sono pannelli di rischio per applicazioni host, non rilevatori di malware
// LinkOptions controls automatic handling of the four PDF link action
// types. Defaults enable goto and URI only; launch (run a program) and
// embedded GotoR (jump to another file) stay OFF so a stray click cannot
// run arbitrary code
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // safe defaults
// OnAnnotationLinkClick fires for in-document destinations (page jumps,
// named destinations, action chains). Mark Handled = True to prevent the
// view from auto-following the link
procedure TForm1.PdfView1AnnotationLinkClick(Sender: TObject;
LinkIndex: Integer; const Action: TPdfAction;
var Handled: Boolean);
begin
if Action.Kind = paUri then
begin
if MessageDlg('Open ' + Action.Uri + '?', mtConfirmation, [mbYes, mbNo], 0)
<> mrYes then
Handled := True; // suppress auto-handling
end;
end;
// OnWebLinkClick fires for URI strings discovered by PDFium's web-link
// scanner (auto-detected URLs in the text stream, even without an
// /A <</S/URI...>> annotation)
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('Web link clicked: ' + string(Url));
end;
// On the focused AcroForm widget, six new methods drive PDFium's form
// edit history. All six short-circuit safely if no widget is focused or
// the document carries no AcroForm
procedure TForm1.btnSelectAllClick(Sender: TObject);
begin
PdfView1.SelectAllFormText;
EditMenuCopy.Caption := 'Copy: ' + string(PdfView1.GetSelectedFormText);
end;
procedure TForm1.btnUndoClick(Sender: TObject);
begin
btnUndo.Enabled := PdfView1.FormCanUndo;
btnRedo.Enabled := PdfView1.FormCanRedo;
if PdfView1.FormCanUndo then
PdfView1.FormUndo;
end;
procedure TForm1.btnRedoClick(Sender: TObject);
begin
if PdfView1.FormCanRedo then
PdfView1.FormRedo;
end;
// All three default to True so existing apps upgrade with no behaviour
// change. Flip them False for kiosks, preview panes, or read-only
// embeddings without subclassing TPdfView
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // wheel up/down jumps
PdfView1.AllowUserTextSelection := False; // mouse/keyboard text selection
// Ctrl+wheel is reserved for zoom and is skipped by the navigation
// handler regardless of ChangePageOnMouseScrolling.
// TPdfThumbnailView (unit FPdfThumbnail) renders one page thumbnail per
// row in a scrollable side panel
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // warm highlight
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex is zero-based
end;
procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Pattern used by Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport,
// and Demo\Lazarus\BatchExport. One TPdf per file, IPdfCancellationToken
// for cancel-from-UI, TPdfStreamAdapter for buffered file load
uses FPdfAsync;
procedure ExportBatch(const Files: TArray<string>;
const OutDir: string; DPI: Integer; Quality: Integer;
const ACancelToken: IPdfCancellationToken);
var
I, J: Integer;
Job: TPdf;
Bmp: TBitmap;
Jpeg: TJPEGImage;
begin
for I := 0 to High(Files) do
begin
if ACancelToken.IsCancelled then Break;
OverallProgress.Position := I;
Job := TPdf.Create(nil);
try
Job.FileName := Files[I];
Job.Active := True;
PageProgress.Max := Job.PageCount;
for J := 1 to Job.PageCount do
begin
if ACancelToken.IsCancelled then Break;
PageProgress.Position := J;
Job.PageNumber := J;
Bmp := Job.RenderPage(
0, 0,
Round(Job.PageWidth * DPI / 72),
Round(Job.PageHeight * DPI / 72));
try
Jpeg := TJPEGImage.Create;
try
Jpeg.CompressionQuality := Quality;
Jpeg.Assign(Bmp);
Jpeg.SaveToFile(Format('%s\%s.p%.3d.jpg',
[OutDir, ExtractFileName(Files[I]), J]));
finally
Jpeg.Free;
end;
finally
Bmp.Free;
end;
end;
finally
Job.Free;
end;
end;
end;
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 is a cheap catalog probe — True when /StructTreeRoot exists
// StructureElements materialises the tree into a flat array of
// TPdfStructureElement records with type, title, alternate text, actual
// text, expansion text, language, level, parent index, and child / marked
// content / attribute counts
var
Elements: TPdfStructureElements;
I: Integer;
begin
if not Pdf1.IsTagged then
begin
Log.Add('Document is NOT tagged — accessibility tools may struggle.');
Exit;
end;
if Pdf1.Language = '' then
Log.Add('Tagged PDF without /Lang — fails PDF/UA.');
Elements := Pdf1.StructureElements;
for I := 0 to High(Elements) do
Log.Add(StringOfChar(' ', Elements[I].Level * 2)
+ Elements[I].StructType + ' "' + Elements[I].Title + '"');
end;
// SetPdfPrintMode is a global function that maps to PDFium's
// FPDF_SetPrintMode. Use the matching TPdfPrintMode value for the
// printer driver in use
SetPdfPrintMode(pmEmf); // GDI EMF (default)
// SetPdfPrintMode(pmTextOnly); // text-only rendering
// SetPdfPrintMode(pmPostScript2); // PostScript Level 2
// SetPdfPrintMode(pmPostScript3); // PostScript Level 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + image masks
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + Type 42 fonts
// PrintCopies, PrintPageRanges, PrintScaling, and PrintPaperHandling are
// the viewer-preference dictionary entries — they encode what the
// document author wanted PDF readers to default to
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // one-based ranges
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// Document-level JavaScript is stored in the /Names /JavaScript name
// tree. JavaScriptAction[i] returns one entry; JavaScriptActions returns
// the full array
var
I: Integer;
Action: TPdfJavaScriptAction;
begin
for I := 0 to Pdf1.JavaScriptActionCount - 1 do
begin
Action := Pdf1.JavaScriptAction[I];
Memo1.Lines.Add('Name: ' + string(Action.Name));
Memo1.Lines.Add('Script: ' + string(Action.Script));
Memo1.Lines.Add('---');
end;
end;
procedure ProcessMultiplePages;
var
I: Integer;
PageText: WString;
begin
for I := 1 to Pdf1.PageCount do
begin
Pdf1.PageNumber := I;
PageText := Pdf1.Text;
ProcessPageText(PageText);
end;
end;
procedure SetOptimalRenderOptions;
begin
PdfView1.Options := [reAnnotations, reLcd];
end;
// Zero-copy render path (default since v1.21.0): RenderPage writes
// directly into the destination TBitmap's DIB buffer when callers pass a
// pre-allocated bitmap, avoiding one width * height * 4 bytes copy
procedure RenderIntoCallerBitmap(Bitmap: TBitmap);
begin
Bitmap.PixelFormat := pf32bit;
Bitmap.SetSize(2480, 3508); // A4 @ 300 DPI
Pdf1.RenderPage(Bitmap, 0, 0, Bitmap.Width, Bitmap.Height);
end;