PDFium Delphi Component Docs

Ejemplos de programación del componente PDFium VCL

Elige un demo ejecutable

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

Demos de flujos de trabajo principales

DemoÚsalo paraEn qué se diferencia de los demos relacionados
PDFViewerVisualización general y evaluación de característicasEl visor principal combina navegación, búsqueda, miniaturas, modos de visualización, impresión y una muestra de características
MultiPageViewerPáginas continuas, vistas dobles y layouts conscientes de portadaUn ejemplo enfocado de layout que usa las APIs de selección integradas del visor; usa PDFViewer para la experiencia de visor más amplia
SplitViewComparar páginas o documentos en paneles separadosDemuestra 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
SearchAndSelectResultados de búsqueda entre páginas y selecciónUna 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
PrintPDFVista previa y trabajos de impresión comunesRangos de páginas, escalado, progreso y cancelación proporcionan el flujo principal de impresión
ContentExtractionLabInspeccionar varias categorías de contenido juntasLos inventarios TXT/JSON describen objetos y previsualizan texto; no reemplazan la exportación completa de texto ni de archivos de imagen
ExtractImagesExportar objetos de imagen embebidosExtrae 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
TableExtractionLabDetectar tablas y exportar CSV/JSONLas 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
AttachmentLeer, agregar y exportar adjuntos incrustadosLas operaciones sobre el payload de los adjuntos van más allá de listar nombres y tamaños en ContentExtractionLab
BatchExportExportar imágenes de página de múltiples documentosLa salida en streaming, el estado por archivo y las fallas aisladas demuestran procesamiento por lotes en lugar de una conversión única
CreatePDFCrear contenido de página con una vista previa activaLas 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
ImageToPDFConstruir páginas a partir de archivos de imagen de entradaEl layout, el ajuste, el orden y el manejo de JPEG proporcionan un flujo de conversión de documentos
MergePDFArmar páginas a partir de varios PDFInspecciona 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
SplitPDFEscribir grupos de páginas seleccionados en PDF separadosEl 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
WatermarkStampAplicar superposiciones repetidas sobre páginas existentesElige 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
FormFillLlenado interactivo de AcroForm y aplanadoLa entrada en campos y las apariencias guardadas se distinguen del intercambio XFDF y del comportamiento específico de XFA
AccessibilityReaderLectura interactiva y vozEl lector GUI demuestra navegación y resaltado de lectura, no una auditoría de cumplimiento
AccessibilityWorkbenchCliRevisión de accesibilidad por lotes y generación de reportesLos 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
StandardsLabValidación y conversión específicas de estándaresEl laboratorio interactivo expone operaciones y opciones en lugar de solo generar un reporte agregado
PreflightReportReportes interactivos de estándaresLa GUI admite inspección manual y exportación de reportes
PreflightReportCliReportes automatizados de estándaresEntradas por lotes, formatos de reporte y controles por código de salida proporcionan la contraparte automatizada de PreflightReport
IntakeWorkbenchCliIntake, triage y enrutamiento por lotesLos 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

Ejemplos enfocados en Miscellaneous

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 paraEn qué se diferencia de los demos relacionados
SecurityAuditInspeccionar la postura de seguridad de forma interactivaLa GUI enfatiza permisos, scripts, firmas y detalles de seguridad en lugar del enrutamiento de archivos
XfdfLabImportar y exportar datos XFDFEl intercambio y un guardado explícito del PDF importado demuestran la persistencia; exportar XFDF por sí solo no guarda el PDF modificado
AccessibilityLabRecorrer las APIs de lectura en una consolaUn recorrido ejecutable compacto expone unidades de lectura, cajas de palabras, estructura y salida de scripts de voz
ExtractTextExportar el texto completo de las páginas seleccionadasLa 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
FontPropertiesEmpieza con métricas reales de fuentes y caracteres del primer objeto de textoSelecciona otra línea para comparar fuentes sin exportar payloads del documento
NavigationLabMarcadores, destinos y acciones de navegaciónEl recorrido compacto por las APIs complementa los controles de navegación visibles en PDFViewer
PDFtoJpgRenderizar un documento a imágenes de páginaUn 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
PrintPreferencesHojas N-up y preferencias de impresión del autor del PDFLas 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
ViewerInteractionLabDiagnosticar interacciones de mouse, teclado y coordenadasEl registro de interacciones y la conversión de coordenadas página/dispositivo lo convierten en una herramienta de diagnóstico de APIs
XfaLabPaquetes XFA estáticos y capacidades del runtimeAbre 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

Comienza con un recorrido funcional de características

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

Copiar y mantener los ejemplos nativos

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

Operaciones básicas con documentos

Cargar y mostrar un documento PDF

Pdf1.FileName := 'C:\MyDocument.pdf';
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
ShowMessage('Title: ' + Pdf1.Title);
ShowMessage('Author: ' + Pdf1.Author);

var
  Stream: TMemoryStream;
begin
  Stream := TMemoryStream.Create;
  try
    Stream.LoadFromFile('C:\MyDocument.pdf');
    Pdf1.LoadDocument(Stream, True);
    Pdf1.Active := True;
    ShowMessage('PDF loaded from stream');
  finally
    Stream.Free;
  end;
end;

Crear un documento PDF nuevo

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;

Operaciones de texto

Extraer texto de un PDF

var
  PageText: WString;
  RectText: WString;
begin
  Pdf1.PageNumber := 1;
  PageText := Pdf1.Text;
  Memo1.Text := PageText;
  RectText := Pdf1.TextInRectangle(100, 100, 500, 200);
  ShowMessage('Text in rectangle: ' + RectText);
end;

Buscar texto

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;

Agregar texto con formato

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;

Inspeccionar metadatos de caracteres y fuentes

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

Crear un reporte de extracción de contenido de varias categorías

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

Detección y extracción de tablas

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

Operaciones de formularios

Trabajar con campos de formulario

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;

Aplanar los valores de un formulario completado en la página

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

Operaciones con imágenes

Extraer imágenes

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;

Agregar imágenes

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;

Operaciones de anotaciones

Trabajar con anotaciones

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;

Operaciones de dibujo

Dibujar formas

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;

Navegación y marcadores

Trabajar con marcadores

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;

Trabajar con destinos con nombre

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;

Operaciones con archivos adjuntos

Trabajar con archivos adjuntos

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;

Gestión de páginas

Operaciones de página

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

Guardado y compresión

Guardar con compresión

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

Crear salida de archivo PDF/A-1b

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

Validar la conformidad PDF/A

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;

Inspeccionar varios estándares PDF en StandardsLab

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

Generar reportes de preflight

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

Carga por streaming y documentos grandes

Cargar un PDF bajo demanda con LoadCustomDocument

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

Cancelación asíncrona y renderizado progresivo

Tokens de cancelación cooperativa

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

Renderizado progresivo de página cancelable

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

Ejecutar renderizados en un hilo en segundo plano con TPdfFuture

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

Matrices de transformación

Componer Translate / Scale / Rotate / Skew

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

Composición de páginas

Importar un subconjunto de páginas por índice

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

Salida compuesta N-up

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

Reordenar páginas en el mismo documento

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

Marcas de agua mediante reutilización de páginas con Form XObject

// 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

Inserción de imágenes (overloads directos de AddImage)

Agregar un archivo de imagen registrado o un TBitmap

// 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

Resaltado de búsqueda en el visor

Resaltar todas las coincidencias de la página actual

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;

Diseño del visor y color de página

Modo de ajuste y fondo de página

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

Explorar la interacción del visor en ViewerInteractionLab

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

Buscar y seleccionar texto en SearchAndSelect

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

Leer las preferencias de impresión PDF en PrintPreferences

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

Impresión PDF estándar en PrintPDF

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

Visualización rápida de varias páginas en MultiPageViewer

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

Revisión lado a lado en SplitView

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

Auditar la superficie de riesgo PDF en SecurityAudit

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

Manejo de enlaces en el visor

Seguimiento seguro de enlaces con listas de permitidos por acción

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

Edición de widgets de formulario en el visor

Selección y deshacer / rehacer

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

Bloquear el visor para kioscos

Deshabilitar los gestos de navegación de páginas

// 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.

Panel lateral de miniaturas

Vincular un TPdfThumbnailView a un TPdfView

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

Exportación por lotes cancelable de forma cooperativa

Conversión de varios PDF a JPG con progreso por archivo y por página

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

Coordenadas del visor y detección de elementos en un punto

Ajustar la página actual e inspeccionar el texto bajo el mouse

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;

Manejo de errores

Operaciones PDF robustas

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;

PDF etiquetado y accesibilidad

Detectar PDF etiquetado y recorrer el árbol de estructura

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

Selección del modo de impresión

Establecer el modo de impresión EMF / PostScript / máscara de imagen

// 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

Leer las opciones de impresión previstas por el autor

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

Acciones JavaScript del documento

Enumerar el JavaScript del árbol de nombres

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

Consejos de rendimiento

Optimizar operaciones PDF

procedure ProcessMultiplePages;
var
  I: Integer;
  PageText: WString;
begin
  for I := 1 to Pdf1.PageCount do
  begin
    Pdf1.PageNumber := I;
    PageText := Pdf1.Text;
    ProcessPageText(PageText);
  end;
end;

procedure SetOptimalRenderOptions;
begin
  PdfView1.Options := [reAnnotations, reLcd];
end;

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