La colección de demos tiene 32 temas: 32 proyectos Delphi, 31 proyectos C++Builder y 32 proyectos Lazarus, con 95 proyectos nativos en total. Cada plataforma mantiene 22 demos de flujos completos en su directorio principal. Diez temas especializados están bajo Miscellaneous, con 29 proyectos nativos entre las tres plataformas; XfaLab está disponible para Delphi y Lazarus
Abra primero un flujo de trabajo del directorio principal: PDFViewer para un recorrido por las funciones, 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; las muestras focalizadas de más abajo son útiles cuando necesita inspeccionar una API en detalle
| Demo | Para qué sirve | En qué se diferencia de las demos relacionadas |
|---|---|---|
PDFViewer | Visualización general y evaluación de funciones | El visor principal combina navegación, búsqueda, miniaturas, modos de visualización, impresión y un escaparate de funciones |
MultiPageViewer | Páginas continuas, doble página y layouts con portada | Un ejemplo de layout focalizado que usa las APIs de selección integradas del visor; use 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 | Previsualización y trabajos de impresión corrientes | Rangos de páginas, escalado, progreso y cancelación proporcionan el flujo de impresión principal |
ContentExtractionLab | Inspeccionar varias categorías de contenido a la vez | Los inventarios TXT/JSON describen objetos y previsualizan texto; no sustituyen la exportación completa de texto o de ficheros de imagen |
ExtractImages | Exportar objetos de imagen incrustados | Extrae bitmaps de imagen en lugar de capturas de páginas completas; el fixture integrado contiene dos objetos de imagen reales en cada una de sus dos páginas |
TableExtractionLab | Detectar tablas y exportar CSV/JSON | Las tablas con líneas y las alineadas por espacios, las celdas combinadas, los grupos de continuación y los controles de confianza son independientes de la extracción de texto plano |
Attachment | Leer, añadir y exportar archivos adjuntos incrustados | Las operaciones sobre el contenido 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 fichero y los fallos aislados demuestran procesamiento por lotes en lugar de una conversión única |
CreatePDF | Crear contenido de página con previsualización en vivo | 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 previsualización antes de un guardado explícito |
ImageToPDF | Construir páginas a partir de ficheros de imagen de entrada | El layout de las imágenes, el ajuste, la ordenación y el manejo de JPEG proporcionan un flujo de conversión de documentos |
MergePDF | Ensamblar páginas a partir de varios PDF | Demuestra la importación de documentos y la composición ordenada; dividir resuelve el flujo inverso |
SplitPDF | Escribir los grupos de páginas seleccionados en PDF separados | El nombrado de la salida y la validación de grupos de páginas se distinguen de la fusión o del renderizado a imágenes de página |
WatermarkStamp | Aplicar superposiciones repetidas a páginas existentes | La colocación y el sellado de páginas por lotes complementan las APIs básicas de creación |
FormFill | Entrada interactiva en 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 con GUI demuestra la navegación de lectura y el resaltado, en lugar de una auditoría de conformidad |
AccessibilityWorkbenchCli | Revisión de accesibilidad por lotes y generación de informes | Los hallazgos, los resúmenes y las puertas de revisión dan servicio 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 limitarse a generar un informe agregado |
PreflightReport | Informes interactivos de estándares | La GUI admite la inspección manual y la exportación de informes |
PreflightReportCli | Informes automatizados de estándares | Entradas por lotes, formatos de informe y puertas de código de salida proporcionan la contrapartida automatizada de PreflightReport |
IntakeWorkbenchCli | Intake, triaje y enrutado por lotes | Informes agregados, puertas de fallo y decisiones de enrutado lo convierten en un flujo de procesamiento que va más allá de la GUI de SecurityAudit |
Abra estos proyectos desde Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous o Demo\Lazarus\Miscellaneous. Conservan recetas útiles de API y tareas concretas de exportación, mientras que el directorio principal se centra en experiencias completas. Las comprobaciones básicas de Unicode y el recorrido fijo de creación y listado de anotaciones están cubiertos por creación, extracción, intercambio XFDF y pruebas de API; ya no tienen proyectos de demo separados
| Demo | Para qué sirve | En qué se diferencia de las demos relacionadas |
|---|---|---|
SecurityAudit | Inspeccionar la postura de seguridad de forma interactiva | La GUI hace hincapié en permisos, scripts, firmas y detalles de seguridad en lugar del enrutado de ficheros |
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 y compacto expone unidades de lectura, cajas de palabras, estructura y salida de guiones 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 previsualizaciones de inventario y de la detección de tablas; no se realiza OCR |
FontProperties | Inspeccionar métricas de fuente y de caracteres | Arranca con las métricas reales de fuente y de caracteres del primer objeto de texto; seleccione otra línea para comparar fuentes sin exportar el contenido del documento |
NavigationLab | Marcadores, destinos y acciones de navegación | El recorrido compacto por la API 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 único documento; la variante de Delphi expone rangos de páginas discretos, mientras que BatchExport se centra en múltiples documentos de entrada |
PrintPreferences | Hojas N-up y preferencias de impresión del autor del PDF | Las copias, el filtrado impar/par y las preferencias definidas por el autor son el foco didáctico; es un complemento de PrintPDF |
ViewerInteractionLab | Diagnosticar interacciones de ratón, teclado y coordenadas | El registro de interacciones y la conversión entre coordenadas de página y de dispositivo lo convierten en una herramienta de diagnóstico de API |
XfaLab | Paquetes XFA estáticos y capacidades del runtime | Abre los paquetes de template y de datasets con el runtime ordinario; el renderizado interactivo de XFA requiere un runtime con XFA habilitado, con variantes para Delphi y Lazarus |
PDFViewer abre el PDFiumDemoShowcase.pdf que incluye, un documento de seis páginas con texto buscable, gráficos vectoriales, dos imágenes incrustadas, una tabla, cuatro campos AcroForm, marcadores de capítulos, enlaces, 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 previsualización en vivo de un informe de dos páginas. Edite su título y su autor, o active y desactive las formas, la tabla y la marca de agua para reconstruir el contenido real de las páginas; la opción Unicode añade una tercera página. No se escribe nada hasta que guarde, y el PDF guardado sigue siendo buscable
MultiPageViewer, SearchAndSelect, ContentExtractionLab y FormFill abren el mismo documento para sus propios flujos de trabajo, 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 la API de marcadores y destinos
Attachment arranca con dos ficheros incrustados 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 notifican. XfaLab arranca con paquetes reales de template y de datasets para la inspección de XFA estático; el renderizado interactivo de XFA requiere un runtime adecuado y es una capacidad aparte
Cada proyecto de visualización, formularios, extracción y navegación contiene su propio PDFiumDemoShowcase.pdf. Copie el directorio del proyecto y conserve este dato de entrada incluido junto al ejecutable distribuido; las compilaciones de Lazarus lo colocan automáticamente. El recorrido funciona offline, y los visores generales y las muestras de extracción también proporcionan contenido de respaldo generado cuando el PDF local no está disponible
Cada demo nativo contiene su propia implementación de ejemplo. Los puntos de entrada de Delphi y Lazarus para AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli y PreflightReportCli incluyen el flujo de trabajo completo en el directorio del proyecto, incluidas la inicialización específica del compilador y la escritura JPEG. Los ejemplos de adjuntos, preferencias de impresión y XFA también generan localmente sus propios datos de entrada específicos de cada función. Solo se necesitan la librería, el runtime nativo correspondiente y las dependencias normales del framework del compilador fuera del proyecto copiado
Elija la extracción de objetos de imagen cuando necesite bitmaps incrustados, el renderizado de páginas cuando necesite la página visible y la extracción de texto cuando el PDF ya tenga una capa de texto. Un informe que lista estas categorías no exporta su contenido completo. Estos límites mantienen útiles los ejemplos focalizados 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 flujo de trabajo único. Abren o crean un PDF, permiten a los usuarios elegir metadatos, texto de página, objetos de página, imágenes, archivos adjuntos, enlaces, anotaciones, marcadores y métricas de fuente / carácter, y a continuación generan un resumen junto con un informe detallado TXT o JSON. El laboratorio incluye también selección de categorías todas / ninguna, copia del informe al portapapeles y acciones de guardado del PDF de origen para que los usuarios puedan conservar el PDF de ejemplo generado junto a su informe de extracción. ExtractImages y Attachment proporcionan flujos de exportación del contenido completo, mientras que Miscellaneous\ExtractText y Miscellaneous\FontProperties conservan ejemplos focalizados de API; ExtractText admite opciones de rango de páginas y separador de páginas para generar texto de salida por página en Delphi, C++Builder y Lazarus, mientras que ContentExtractionLab es la muestra de inventario transversal
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 después ejecuta ExtractTables para la página actual o ExtractDocumentTables para todo el documento, e informa de las filas, las columnas, los valores RowSpan y ColumnSpan, los indicadores de encabezado, el modo de detección, el nivel de 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, informa de los recuentos 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;
// Sin aplanar, FormField[i] := value escribe solo la entrada /V —
// la apariencia visible proviene del stream /AP y puede no refrescarse.
// GenerateFormAppearances regenera /AP para cada widget, luego
// FlattenAllPages incorpora las anotaciones y widgets de todas las
// páginas como contenido permanente no editable.
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);
// Crear un documento PDF comprimido
Pdf1.CreateDocument;
Pdf1.Compressed := True; // garantizar que todos los streams se comprimen con FlateDecode (por defecto)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // tamaño A4
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Guardar con opciones
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // guardado incremental
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // eliminar seguridad
// Guardar para una versión PDF de destino específica. El validador de versión PDF rechaza
// cualquier característica introducida después de la versión de destino elegida (JBIG2Decode, MarkInfo,
// cifrado AES, anotaciones Polygon / Caret / Watermark / Redact, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Save rejected: document contains features newer than PDF 1.5');
// SaveAsPdfA postprocesa el guardado base con una actualización incremental que
// inyecta un stream de metadatos XMP, un OutputIntent ICC sRGB y un catálogo
// de documento actualizado, de modo que el resultado sea conforme a PDF/A-1b.
// El perfil sRGB IEC61966-2.1 incluido se utiliza automáticamente cuando no se
// suministra ningún perfil personalizado.
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 con un perfil ICC personalizado (canalizaciones de impresión CMYK, por ejemplo)
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;
// Salida PDF/A en memoria
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;
// Sondeo barato de tipo cabecera — lee la conformidad sin iterar
// por el validador completo. Resultado: pacNone, pac1a, pac1b, pac2b, pac3b, o
// 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;
// Validador completo con diagnósticos por incidencia
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 recuento de incidencias en una sola cuadrícula. Sus botones de guardado invocan SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR y SaveAsPdfVT para que el flujo de salida con marcadores sea visible sin escribir un arnés personalizado
La unidad FPdfPreflightReport envuelve ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR y ValidatePdfVT en un único objeto de informe consultable con severidad Info / Warning / Error, agregación de estado e incidencias, búsqueda por nombre, filtrado y huellas SHA-256 estables. Los informes 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 previsualización, mientras que Demo\Delphi\PreflightReportCli añade argumentos de entrada / salida programables, filtrado de estándares, incrustación opcional del adjunto de informe, puertas de código de salida para CI, procesamiento por lotes de listas y directorios, enrutamiento a prueba de colisiones, resúmenes agregados y manifiestos CSV. El informe generado indica que los validadores integrados cubren comprobaciones a nivel de marcador y a nivel de fichero seleccionado, por lo que el preflight completo a nivel de contenido puede seguir delegándose en un motor de validación dedicado
// LoadCustomDocument permite a PDFium obtener bloques de cualquier TStream
// con seek bajo demanda. El stream NO se copia en memoria, por lo que los PDF de varios GB,
// los streams de cuerpo HTTP remotos y las fuentes respaldadas por base de datos son
// todos viables sin un búfer previo íntegro.
var
FileStream: TFileStream;
begin
// Streaming de lectura desde fichero (sin copia en memoria)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ propiedad transferida — Pdf1 libera FileStream en UnloadDocument.
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Stream propiedad externa (el llamador lo libera tras 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 expone IPdfCancellationToken /
// IPdfCancellationTokenSource para semánticas de cancelación desde la UI que funcionan
// a lo largo de las rutas largas de exportación y renderizado.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... el usuario hace clic en Cancelar ...
CancelSource.Cancel;
// El trabajador comprueba periódicamente CancelToken.IsCancelled, o la
// ruta de renderizado lo consulta a través del callback IFSDK_PAUSE de PDFium.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive permite que un renderizado largo a alta DPI se cancele
// a mitad de página cuando el usuario hace clic en Cancelar, en lugar de bloquear al
// llamador hasta el final.
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> arranca un trabajador en un hilo en segundo plano y devuelve
// un sobre TPdfFutureResult<T> al hilo principal.
//
// Importante: TPdf serializa las llamadas de renderizado por instancia, pero el trabajador
// sigue siendo responsable del despacho y del ciclo de vida del documento. No mute un TPdf
// mientras hay un renderizado en curso; la exportación por lotes suele mantener un TPdf por fichero.
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 envuelve FS_MATRIX de PDFium para que los llamadores puedan construir una transformación
// de forma declarativa y pasarla a FPDFPageObj_SetMatrix.
uses FPdfMatrix, FPdfView;
var
M: TPdfMatrix;
RawMatrix: FS_MATRIX;
PageObj: FPDF_PAGEOBJECT;
begin
M := TPdfMatrix.Create;
try
M.Translate(72, 200); // mover 1in a la derecha, ~2.8in hacia arriba
M.Scale(0.5, 0.5); // sello a la mitad de tamaño
M.Rotate(15); // rotación CCW de 15 grados
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // postmultiplicar con otra matriz
// Aplicar a cualquier objeto de página PDFium (texto / trayectoria / imagen / form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex copia un array de índices basado en cero desde un
// PDF de origen al documento. InsertAt = 0 inserta antes de la página 1;
// PageCount añade al final.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Importar páginas 0, 2, 4 (basado en uno: páginas 1, 3, 5) desde Source
// y añadirlas al final de Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Un array vacío importa todas las páginas del origen
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne devuelve un TPdf totalmente nuevo cuyas páginas son composiciones
// NumX*NumY de ESTE documento. OutputWidth/Height son unidades de usuario PDF
// (1 unidad = 1/72 in).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// A4 horizontal con 4-up: 842 x 595 pt, 2 columnas x 2 filas
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages toma los índices basados en cero de las páginas a mover, más el
// índice de destino de la primera página movida tras completarse el movimiento.
// El resto de páginas se desplazan alrededor del bloque movido para que la longitud del documento
// se mantenga igual.
//
// Ejemplo: en un documento de 5 páginas con páginas numeradas [0,1,2,3,4],
// MovePages([2, 3], 0) reordena a [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Invalid indices passed to MovePages');
// CreateXObjectFromPage fabrica un handle Form XObject reutilizable a partir
// de cualquier página de cualquier otro TPdf. Estampe ese handle sobre tantas páginas
// de ESTE documento como desee — cada sello es un único objeto de página PDFium
// que puede posicionarse, escalarse y rotarse mediante la API de matrices.
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;
// Envolver la página 0 de WatermarkSource como un XObject reutilizable
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;
// Centrar la marca de agua en la página
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; // cierra el handle FPDF_XOBJECT
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 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 añaden etiquetas opcionales con el número de página antes de guardar el resultado
// AddImage(FileName) acepta cualquier formato registrado en las unidades gráficas
// VCL o LCL (BMP, PNG vía PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) omite el intermediario TPicture, ideal cuando el
// bitmap ya proviene de un renderizado o de un trabajo de generación por lotes.
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 de lote completo: seleccionar varios ficheros de imagen, previsualizar el elemento seleccionado, crear una página PDF por imagen, escalar cada imagen en una página A4 vertical u horizontal, guardar el resultado y abrir el PDF generado
var
MatchCount: Integer;
begin
// Pintar una máscara clYellow sobre cada coincidencia en la página actual del visor.
// Cambiar a una página diferente borra el resaltado automáticamente.
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d match(es) on this page', [MatchCount]);
// Eliminar la superposición programáticamente antes de cambiar de página
PdfView1.ClearHighlight;
end;
// FitMode mantiene los documentos largos encuadrados durante Resize o cambios de página.
// Establecer Zoom directamente cancela FitMode (vuelve a pfmNone).
PdfView1.FitMode := pfmFitPage; // página completa en el viewport
// PdfView1.FitMode := pfmFitWidth; // el ancho de la página coincide con el del viewport
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor desacopla la página PDF renderizada del Color del control anfitrión
// — la configuración típica de visor en modo oscuro mantiene el área de scroll oscura mientras
// la página PDF permanece blanca como papel.
PdfView1.Color := clBlack; // área de scroll
PdfView1.PageColor := clWhite; // fondo de la página PDF
// Sombra paralela y borde de página opcionales para destacar la página sobre un fondo oscuro
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
Los proyectos Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab y Demo\Lazarus\Miscellaneous\ViewerInteractionLab mantienen la superficie moderna de interacción de TPdfView en un único formulario compacto: abra o cree un PDF de muestra, cambie DisplayMode, aplique FitMode, modifique PageColor, rote páginas, resalte coincidencias de búsqueda en la página actual con HighlightSearchText, habilite o deshabilite la selección de texto por parte del usuario, inspeccione SelectedText, llame a SelectAll, CopySelectionToClipboard y ClearSelection, y observe cómo las coordenadas DeviceToPage se actualizan en la barra de estado mientras el ratón 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 previsualización, soportan navegación Previo / Siguiente y salto a resultado con doble clic, resaltan las coincidencias de la página actual con HighlightSearchText, exponen las opciones de distinción de mayúsculas y palabra completa, alternan AllowUserTextSelection, previsualizan SelectedText, controlan SelectAll, CopySelectionToClipboard y ClearSelection desde botones, y permiten a los usuarios alternar entre los modos de visualización de página única y de doble página
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 en las entradas de impresión, y muestran cómo SetPdfPrintPaperHandlingDevMode mapea la intención de dúplex 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: abren un PDF, previsualizan las páginas, eligen rangos de páginas y copias en el cuadro de diálogo de impresión de la plataforma, respetan el modo de intercalado, renderizan cada página mediante TPdf.RenderPage, y exponen el progreso de impresión con cancelación. La muestra Delphi también acepta ficheros PDF arrastrados para una carga rápida
Los proyectos Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer y Demo\Lazarus\MultiPageViewer ejercitan la visualización continua, doble página y con portada con flujos normales de navegación y zoom. También son útiles para probar la velocidad de apertura a la primera página y la capacidad de respuesta del renderizado en PDF muy grandes: en pruebas con ficheros grandes, documentos de 2.x GB que pueden hacer que Acrobat o Foxit tarden entre 20 y 30 segundos antes de la primera vista, pueden volverse usables casi instantáneamente 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 centran en la comparación de dos o tres paneles, selección de la vista activa, comandos opcionales de navegación sincronizada, ajustes de zoom compartidos y rotación para la vista seleccionada o todas las vistas cargadas. Utilice estas muestras para comparar documentos grandes mientras se mantiene la primera vista usable y el renderizado de páginas posteriores reactivos; los mismos ficheros PDF de 2.x GB que pueden tardar 20-30 segundos en abrirse en Acrobat o Foxit pueden ser usables casi instantáneamente mediante 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 muestran permisos, adjuntos incrustados, acciones JavaScript del documento, anotaciones de enlace URI y Launch, enlaces web, resúmenes de firmas, estado XFA, disponibilidad de helpers V8 y callbacks de funciones no admitidas. El mismo resumen y las filas de hallazgos se pueden guardar o copiar como informe de auditoría TXT o guardar como JSON estructurado. Están pensados como paneles de riesgo para la aplicación anfitriona, no como detección de malware
// LinkOptions controla el manejo automático de los cuatro tipos de acción
// de enlace PDF. Los valores por defecto habilitan únicamente goto y URI; launch (ejecutar un programa)
// y embedded GotoR (saltar a otro fichero) permanecen DESACTIVADOS para que un clic accidental no pueda
// ejecutar código arbitrario.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // valores por defecto seguros
// OnAnnotationLinkClick se dispara para destinos dentro del documento (saltos de página,
// destinos con nombre, cadenas de acciones). Marque Handled = True para evitar que la
// vista siga el enlace automáticamente.
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; // suprimir el manejo automático
end;
end;
// OnWebLinkClick se dispara para las cadenas URI descubiertas por el escáner de enlaces
// web de PDFium (URLs autodetectadas en el stream de texto, incluso sin una
// anotación /A <</S/URI...>>).
procedure TForm1.PdfView1WebLinkClick(Sender: TObject;
WebLinkIndex: Integer; const Url: WString;
var Handled: Boolean);
begin
Log.Add('Web link clicked: ' + string(Url));
end;
// En el widget AcroForm con foco, seis nuevos métodos controlan el historial
// de edición de formulario de PDFium. Los seis cortocircuitan de forma segura si ningún widget tiene el foco
// o el documento no contiene un 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;
// Los tres tienen True como valor por defecto para que las aplicaciones existentes se actualicen sin
// cambios de comportamiento. Cámbielos a False para quioscos, paneles de previsualización o
// empotraciones de solo lectura sin necesidad de subclasear TPdfView.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Inicio/Fin
PdfView1.ChangePageOnMouseScrolling := False; // saltos con rueda arriba/abajo
PdfView1.AllowUserTextSelection := False; // selección de texto con ratón/teclado
// Ctrl+rueda está reservado para el zoom y lo omite el manejador de navegación
// independientemente de ChangePageOnMouseScrolling.
// TPdfThumbnailView (unidad FPdfThumbnail) renderiza una miniatura de página por
// fila en un panel lateral desplazable.
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // resaltado cálido
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex es basado en cero
end;
procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Patrón utilizado por Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport,
// y Demo\Lazarus\BatchExport. Un TPdf por fichero, IPdfCancellationToken
// para cancelar desde la UI, TPdfStreamAdapter para carga de fichero con búfer.
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 es un sondeo barato del catálogo — True cuando /StructTreeRoot existe.
// StructureElements materializa el árbol en un array plano de
// records TPdfStructureElement con tipo, título, texto alternativo, texto real,
// texto de expansión, idioma, nivel, índice de padre y recuentos de hijos / contenido
// marcado / atributos.
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 es una función global que mapea a
// FPDF_SetPrintMode de PDFium. Utilice el valor TPdfPrintMode correspondiente para el
// controlador de impresora en uso.
SetPdfPrintMode(pmEmf); // GDI EMF (por defecto)
// SetPdfPrintMode(pmTextOnly); // renderizado solo de texto
// SetPdfPrintMode(pmPostScript2); // PostScript Nivel 2
// SetPdfPrintMode(pmPostScript3); // PostScript Nivel 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + máscaras de imagen
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + fuentes Type 42
// PrintCopies, PrintPageRanges, PrintScaling y PrintPaperHandling son
// las entradas del diccionario de preferencias del visor — codifican lo que el
// autor del documento quería que los lectores PDF eligieran por defecto.
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Suggested copies: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Print scaling: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // rangos basados en uno
for Range in Ranges do
Log.Add(Format('Pages %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// El JavaScript a nivel de documento se almacena en el árbol de nombres
// /Names /JavaScript. JavaScriptAction[i] devuelve una entrada; JavaScriptActions devuelve
// el array completo.
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;
// Ruta de renderizado zero-copy (por defecto desde v1.21.0): RenderPage escribe
// directamente en el búfer DIB del TBitmap de destino cuando los llamadores pasan un
// bitmap preasignado, evitando una copia de anchura * altura * 4 bytes.
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;