La colección de demos cubre 32 temas: 32 proyectos de Delphi, 31 de C++Builder y 32 de Lazarus, para un total de 95 proyectos nativos. Cada plataforma mantiene 22 demos de flujos de trabajo completos en su directorio principal. Diez temas específicos se encuentran bajo Miscellaneous, con 29 proyectos nativos entre las tres plataformas; XfaLab está disponible para Delphi y Lazarus
Abre primero un flujo de trabajo del directorio principal: PDFViewer para el recorrido de características, CreatePDF para creación en vivo, ContentExtractionLab para un inventario inmediato, FormFill para formularios editables, StandardsLab para validación y conversión, o IntakeWorkbenchCli para intake automatizado. Estos seis puntos de entrada producen resultados funcionales de inmediato; los ejemplos enfocados de más abajo sirven cuando necesitas inspeccionar una API a detalle
| Demo | Úsalo para | En qué se diferencia de los demos relacionados |
|---|---|---|
PDFViewer | Visualización general y evaluación de características | El visor principal combina navegación, búsqueda, miniaturas, modos de visualización, impresión y una muestra de características |
MultiPageViewer | Páginas continuas, vistas dobles y layouts conscientes de portada | Un ejemplo enfocado de layout que usa las APIs de selección integradas del visor; usa PDFViewer para la experiencia de visor más amplia |
SplitView | Comparar páginas o documentos en paneles separados | Demuestra posiciones de vista independientes y el enrutamiento de comandos al panel activo, en lugar de un layout de dos páginas en una sola vista |
SearchAndSelect | Resultados de búsqueda entre páginas y selección | Una lista de resultados y opciones de búsqueda exponen el flujo de búsqueda de forma más directa que una barra de herramientas del visor |
PrintPDF | Vista previa y trabajos de impresión comunes | Rangos de páginas, escalado, progreso y cancelación proporcionan el flujo principal de impresión |
ContentExtractionLab | Inspeccionar varias categorías de contenido juntas | Los inventarios TXT/JSON describen objetos y previsualizan texto; no reemplazan la exportación completa de texto ni de archivos de imagen |
ExtractImages | Exportar objetos de imagen embebidos | Extrae bitmaps de imagen en lugar de capturas de páginas completas; el fixture incorporado contiene dos objetos de imagen reales en cada una de dos páginas |
TableExtractionLab | Detectar tablas y exportar CSV/JSON | Las tablas con líneas y por espacios en blanco, las celdas combinadas, los grupos de continuación y los controles de confianza son independientes de la extracción de texto plano |
Attachment | Leer, agregar y exportar adjuntos incrustados | Las operaciones sobre el payload de los adjuntos van más allá de listar nombres y tamaños en ContentExtractionLab |
BatchExport | Exportar imágenes de página de múltiples documentos | La salida en streaming, el estado por archivo y las fallas aisladas demuestran procesamiento por lotes en lugar de una conversión única |
CreatePDF | Crear contenido de página con una vista previa activa | Las tres variantes nativas crean texto buscable, formas vectoriales, una imagen raster real, tablas y una anotación de revisión; las opciones reconstruyen la vista previa antes de un guardado explícito |
ImageToPDF | Construir páginas a partir de archivos de imagen de entrada | El layout, el ajuste, el orden y el manejo de JPEG proporcionan un flujo de conversión de documentos |
MergePDF | Armar páginas a partir de varios PDF | Inspecciona las entradas para ver los conteos de páginas y los intervalos de salida, reordena los orígenes y combina solo cuando todas las entradas pasen la validación |
SplitPDF | Escribir grupos de páginas seleccionados en PDF separados | El nombrado de la salida y la validación de grupos de páginas se diferencian de la fusión y del renderizado a imágenes de página |
WatermarkStamp | Aplicar superposiciones repetidas sobre páginas existentes | Elige un PDF de destino, un PDF reutilizable como sello y un intervalo de páginas; los sellos se ajustan a cada página y las páginas no seleccionadas permanecen intactas |
FormFill | Llenado interactivo de AcroForm y aplanado | La entrada en campos y las apariencias guardadas se distinguen del intercambio XFDF y del comportamiento específico de XFA |
AccessibilityReader | Lectura interactiva y voz | El lector GUI demuestra navegación y resaltado de lectura, no una auditoría de cumplimiento |
AccessibilityWorkbenchCli | Revisión de accesibilidad por lotes y generación de reportes | Los hallazgos, los resúmenes y los controles de revisión sirven a la automatización; los hallazgos no sustituyen la revisión manual de accesibilidad |
StandardsLab | Validación y conversión específicas de estándares | El laboratorio interactivo expone operaciones y opciones en lugar de solo generar un reporte agregado |
PreflightReport | Reportes interactivos de estándares | La GUI admite inspección manual y exportación de reportes |
PreflightReportCli | Reportes automatizados de estándares | Entradas por lotes, formatos de reporte y controles por código de salida proporcionan la contraparte automatizada de PreflightReport |
IntakeWorkbenchCli | Intake, triage y enrutamiento por lotes | Los reportes agregados, los controles de fallas y las decisiones de enrutamiento lo convierten en un flujo de procesamiento que va más allá de la GUI de SecurityAudit |
Abre estos proyectos desde Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous o Demo\Lazarus\Miscellaneous. Conservan recetas útiles de API y tareas de exportación específicas, mientras el directorio principal se concentra en experiencias completas. Las comprobaciones básicas de Unicode y el recorrido fijo de escritura y listado de anotaciones quedan cubiertos por la creación, extracción, intercambio XFDF y pruebas de API; ya no tienen proyectos de demo separados
| Demo | Úsalo para | En qué se diferencia de los demos relacionados |
|---|---|---|
SecurityAudit | Inspeccionar la postura de seguridad de forma interactiva | La GUI enfatiza permisos, scripts, firmas y detalles de seguridad en lugar del enrutamiento de archivos |
XfdfLab | Importar y exportar datos XFDF | El intercambio y un guardado explícito del PDF importado demuestran la persistencia; exportar XFDF por sí solo no guarda el PDF modificado |
AccessibilityLab | Recorrer las APIs de lectura en una consola | Un recorrido ejecutable compacto expone unidades de lectura, cajas de palabras, estructura y salida de scripts de voz |
ExtractText | Exportar el texto completo de las páginas seleccionadas | La salida de la capa de texto, los separadores de página y la cancelación se distinguen de las vistas previas de inventario y de la detección de tablas; no se realiza OCR |
FontProperties | Empieza con métricas reales de fuentes y caracteres del primer objeto de texto | Selecciona otra línea para comparar fuentes sin exportar payloads del documento |
NavigationLab | Marcadores, destinos y acciones de navegación | El recorrido compacto por las APIs complementa los controles de navegación visibles en PDFViewer |
PDFtoJpg | Renderizar un documento a imágenes de página | Un ejemplo compacto de renderizado de un solo documento; Delphi expone rangos discretos de páginas, mientras que BatchExport se enfoca en múltiples documentos de entrada |
PrintPreferences | Hojas N-up y preferencias de impresión del autor del PDF | Las copias, el filtrado de páginas pares e impares y las preferencias definidas por el autor son el foco didáctico; es un complemento de PrintPDF |
ViewerInteractionLab | Diagnosticar interacciones de mouse, teclado y coordenadas | El registro de interacciones y la conversión de coordenadas página/dispositivo lo convierten en una herramienta de diagnóstico de APIs |
XfaLab | Paquetes XFA estáticos y capacidades del runtime | Abre los paquetes de template y datasets con el runtime ordinario; el renderizado interactivo de XFA requiere un runtime con XFA habilitado, con variantes para Delphi y Lazarus |
PDFViewer abre su PDFiumDemoShowcase.pdf incluido, un documento de seis páginas con texto buscable, gráficos vectoriales, dos imágenes embebidas, una tabla, cuatro campos AcroForm, marcadores por capítulo, links, una nota de revisión y dos archivos adjuntos. La barra de experiencia ofrece Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF y Explore forms; cada acción funciona sobre el documento actual
CreatePDF abre una vista previa activa de un reporte de dos páginas. Edita su título y autor, o activa y desactiva las formas, la tabla y la marca de agua para reconstruir el contenido real de las páginas; la opción Unicode agrega una tercera página. No se escribe nada hasta que guardas, y el PDF guardado sigue siendo buscable
MultiPageViewer, SearchAndSelect, ContentExtractionLab y FormFill abren el mismo documento para sus propios flujos, con resultados de búsqueda, un inventario de extracción y campos editables listos de inmediato. Miscellaneous\NavigationLab usa su propia copia local para un recorrido por las APIs de marcadores y destinos
Attachment arranca con dos archivos embebidos reales. PrintPreferences arranca con cuatro páginas y preferencias del autor para dos copias, rangos de páginas seleccionados, escalado y dúplex; el flujo de impresión actual aplica las copias y los rangos de páginas, mientras que el escalado y el dúplex se inspeccionan y se reportan. XfaLab arranca con paquetes reales de template y datasets para inspección de XFA estático; el renderizado interactivo de XFA requiere un runtime apropiado y es una capacidad aparte
Cada proyecto de visualización, formularios, extracción y navegación contiene su propio PDFiumDemoShowcase.pdf. Copia el directorio del proyecto y deja esta entrada incluida junto al ejecutable que distribuyas; los builds de Lazarus la colocan automáticamente. El recorrido funciona offline, y los visores generales y los ejemplos de extracción también generan contenido de respaldo cuando el PDF local no está disponible
Cada demo nativo contiene su propia implementación de muestra. Los puntos de entrada de Delphi y Lazarus para AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli y PreflightReportCli incluyen el flujo de trabajo completo dentro del directorio del proyecto, incluyendo la inicialización específica del compilador y la escritura JPEG. Los ejemplos de Attachment, preferencias de impresión y XFA también generan localmente sus propias entradas específicas de cada función. Fuera del proyecto copiado solo se requieren la biblioteca, el runtime nativo correspondiente y las dependencias normales del framework del compilador
Elige la extracción de objetos de imagen cuando necesitas los bitmaps embebidos, el renderizado de páginas cuando necesitas la página visible y la extracción de texto cuando el PDF ya tiene una capa de texto. Un reporte que lista estas categorías no exporta su contenido completo. Estos límites mantienen útiles los ejemplos enfocados sin convertir cada demo en otro visor o workbench de propósito general
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;
Los proyectos Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties y Demo\Lazarus\Miscellaneous\FontProperties muestran los mismos metadatos tanto a través de TPdf como de TPdfView
Los proyectos Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab y Demo\Lazarus\ContentExtractionLab convierten la extracción de contenido en un único flujo de trabajo. Abren o crean un PDF, permiten elegir metadatos, texto de página, objetos de página, imágenes, adjuntos, enlaces, anotaciones, marcadores y métricas de fuente / carácter, y luego generan un resumen más un reporte detallado en TXT o JSON. El laboratorio incluye además selección de categorías todas / ninguna, copia del reporte al portapapeles y acciones de guardado del PDF de origen, de modo que los usuarios puedan conservar el PDF de muestra generado junto a su reporte de extracción. ExtractImages y Attachment proporcionan flujos de exportación de payloads, mientras que Miscellaneous\ExtractText y Miscellaneous\FontProperties conservan ejemplos enfocados de APIs; ExtractText admite opciones de rango de páginas y de separador por página para producir texto por página en Delphi, C++Builder y Lazarus, mientras que ContentExtractionLab es la muestra transversal de inventario
Los proyectos Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab y Demo\Lazarus\TableExtractionLab convierten la detección de tablas en un único flujo de trabajo. El laboratorio construye un documento de ejemplo que contiene una tabla con líneas y celdas de encabezado combinadas, una tabla alineada por espacios en blanco sin líneas y una tabla larga que se corta en el límite de una página, y luego ejecuta ExtractTables para la página actual o ExtractDocumentTables para todo el documento, y reporta las filas, las columnas, los valores RowSpan y ColumnSpan, las banderas de encabezado, el modo de detección, la confianza y los grupos de continuación. Las opciones DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings y MinConfidence se pueden editar en la interfaz, y la tabla seleccionada se exporta mediante TPdfTable.ToCsv y TPdfTable.ToJson. El laboratorio también procesa por lotes una carpeta completa: Batch folder ejecuta ExtractDocumentTables sobre cada PDF, reporta los conteos de tablas por documento, marca los escaneos sin capa de texto y reintenta los documentos vacíos con un preajuste de columnas compactas; Export all CSV escribe cada tabla detectada junto a los archivos de origen. Cada documento se abre en su propia instancia de TPdf, de modo que un archivo ilegible no puede afectar al resto del lote
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;
Los proyectos Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab y Demo\Lazarus\StandardsLab cargan o crean un PDF, ejecutan ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR y ValidatePdfVT, y luego muestran cada nivel de conformidad detectado y el conteo de problemas en una sola cuadrícula. Sus botones de guardado llaman a SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR y SaveAsPdfVT, de modo que el flujo de salida de marcadores queda visible sin necesidad de escribir un arnés personalizado
La unidad FPdfPreflightReport agrupa ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR y ValidatePdfVT en un único objeto de reporte consultable, con severidad Info / Warning / Error, agregación de estados y problemas, búsqueda, consulta, filtrado y huellas SHA-256 estables. Los reportes pueden emitirse como texto, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON o XML nativo. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport y Demo\CBuilder\PreflightReport proporcionan flujos interactivos de selección y vista previa, mientras que Demo\Delphi\PreflightReportCli agrega argumentos de entrada / salida programables, filtrado estándar, incrustación opcional de adjuntos de reporte, control del código de salida para CI, procesamiento por lotes de listas y directorios, enrutamiento seguro ante colisiones, resúmenes agregados y manifiestos CSV. El reporte generado indica que los validadores incorporados cubren comprobaciones a nivel de marcadores y algunas a nivel de archivo, de modo que el preflight completo a nivel de contenido aún puede delegarse en un motor de validación dedicado
// 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;
Los proyectos Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp y Demo\CBuilder\WatermarkStamp convierten este patrón en un flujo de trabajo ejecutable: crean un PDF de destino y un PDF de sello reutilizable, envuelven la página del sello con CreateXObjectFromPage, insertan el mismo Form XObject en cada página de destino, aplican transformaciones TPdfMatrix para marcas de agua centradas y sellos en la esquina superior derecha, y agregan etiquetas opcionales de número de página antes de guardar el resultado
// 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;
Los proyectos Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF y Demo\Lazarus\ImageToPDF convierten esto en un flujo por lotes completo: seleccione varios archivos de imagen, obtenga una vista previa del elemento seleccionado, cree una página PDF por imagen, escale cada imagen a una página A4 vertical u horizontal, guarde el resultado y abra el PDF generado
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;
Los proyectos Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab y Demo\Lazarus\Miscellaneous\ViewerInteractionLab reúnen la superficie de interacción moderna de TPdfView en un formulario compacto: abren o crean un PDF de muestra, cambian el DisplayMode, aplican el FitMode, cambian el PageColor, rotan páginas, resaltan las coincidencias de búsqueda de la página actual con HighlightSearchText, habilitan o deshabilitan la selección de texto del usuario, inspeccionan el SelectedText, invocan SelectAll, CopySelectionToClipboard y ClearSelection, y muestran las coordenadas de DeviceToPage actualizarse en la barra de estado mientras el mouse se mueve sobre la página
Los proyectos Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect y Demo\Lazarus\SearchAndSelect convierten el flujo de búsqueda y selección del visor en muestras independientes. Abren o crean un PDF, listan los resultados de búsqueda de todas las páginas con número de página, índice de carácter y texto de vista previa, admiten navegación Anterior / Siguiente y salto a un resultado con doble clic, resaltan las coincidencias de la página actual con HighlightSearchText, exponen las opciones de coincidencia de mayúsculas y minúsculas y de palabra completa, alternan AllowUserTextSelection, previsualizan el SelectedText, accionan SelectAll, CopySelectionToClipboard y ClearSelection desde botones, y permiten alternar entre modos de visualización simple y en vista doble
Los proyectos Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences y Demo\Lazarus\Miscellaneous\PrintPreferences leen las preferencias de impresión del autor antes de imprimir. Muestran PrintCopies, PrintPageRanges, PrintScaling y PrintPaperHandling, pueden copiar las copias y los rangos proporcionados por el autor a las entradas de impresión, y muestran cómo SetPdfPrintPaperHandlingDevMode mapea la intención de impresión a doble cara del PDF en un DEVMODE de Windows
Los proyectos Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF y Demo\Lazarus\PrintPDF muestran el flujo de impresión estándar: abrir un PDF, previsualizar páginas, elegir rangos de páginas y copias en el diálogo de impresión de la plataforma, respetar el modo de colación, renderizar cada página mediante TPdf.RenderPage y exponer el progreso de impresión con cancelación. La muestra de Delphi también acepta archivos PDF arrastrados para una carga rápida
Los proyectos Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer y Demo\Lazarus\MultiPageViewer ejercitan la visualización continua, en vista doble y consciente de portada, con flujos habituales de navegación de páginas y zoom. También son útiles para probar la velocidad de apertura hasta la primera página y la capacidad de respuesta del renderizado en PDF muy grandes: en pruebas con archivos grandes, documentos de 2,x GB que pueden hacer que Acrobat o Foxit tarden de 20 a 30 segundos antes de la primera vista pueden volverse utilizables casi de inmediato mediante la ruta del visor de PDFium Delphi Component
Los proyectos Demo\Delphi\SplitView, Demo\CBuilder\SplitView y Demo\Lazarus\SplitView muestran la revisión de PDF lado a lado. Las muestras de C++Builder y Lazarus se enfocan en la comparación de dos o tres paneles, la selección de la vista activa, los comandos de navegación sincronizada opcionales, los preajustes de zoom compartidos y la rotación de la vista seleccionada o de todas las vistas cargadas. Use estas muestras para comparar documentos grandes manteniendo ágil la primera vista utilizable y el renderizado de páginas posterior; los mismos archivos PDF de 2,x GB que pueden llevar a Acrobat o Foxit de 20 a 30 segundos para abrirse pueden volverse utilizables casi de inmediato en la ruta del visor de PDFium Delphi Component
Los proyectos Demo\Delphi\Miscellaneous\SecurityAudit, Demo\CBuilder\Miscellaneous\SecurityAudit y Demo\Lazarus\Miscellaneous\SecurityAudit abren un PDF en modo de solo lectura y listan el estado de permisos, los adjuntos incrustados, las acciones JavaScript del documento, las anotaciones de enlaces URI y Launch, los enlaces web, los resúmenes de firmas, el estado XFA, la disponibilidad de helpers V8 y las devoluciones de llamada de características no soportadas. Las mismas filas de resumen y de hallazgos pueden guardarse o copiarse como un reporte de auditoría TXT o guardarse como JSON estructurado. Están pensados como paneles de riesgo para aplicaciones anfitrionas, no como detección de 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;