A coleção de demos cobre 33 tópicos: 33 projetos Delphi, 32 projetos C++Builder e 33 projetos Lazarus, totalizando 98 projetos nativos. Cada plataforma mantém 24 demos de fluxos de trabalho completos em seu diretório principal. Nove tópicos focados ficam em Miscellaneous, com 26 projetos nativos nas três plataformas; o XfaLab está disponível para Delphi e Lazarus
Abra primeiro um fluxo de trabalho do diretório principal: PDFViewer para um passeio pelos recursos, CreatePDF para criação ao vivo, ContentExtractionLab para um inventário instantâneo, FormFill para formulários editáveis, StandardsLab para validação e conversão, ou IntakeWorkbenchCli para intake automatizado. Esses seis pontos de entrada produzem resultados funcionais imediatamente; os exemplos focados abaixo são úteis quando você precisa inspecionar uma API em detalhes
| Demo | Use para | Como se diferencia dos demos relacionados |
|---|---|---|
PDFViewer | Visualização geral e avaliação de recursos | O visualizador principal combina navegação, pesquisa, miniaturas, modos de exibição, impressão e uma vitrine de recursos |
MultiPageViewer | Páginas contínuas, layouts de página dupla e de capa | Um exemplo focado em layout usando as APIs de seleção embutidas do visualizador; use o PDFViewer para a experiência de visualizador mais ampla |
SplitView | Comparar páginas ou documentos em painéis separados | Demonstra posições de visualização independentes e roteamento de comandos para o painel ativo, em vez de um layout de duas páginas em uma única visualização |
SearchAndSelect | Resultados de pesquisa entre páginas e seleção | Uma lista de resultados e opções de pesquisa expõem o fluxo de pesquisa de forma mais direta do que uma barra de ferramentas do visualizador |
PrintPDF | Pré-visualização e trabalhos de impressão comuns | Intervalos de páginas, escala, progresso e cancelamento fornecem o fluxo principal de impressão |
ContentExtractionLab | Inspecionar várias categorias de conteúdo juntas | Inventários TXT/JSON descrevem objetos e pré-visualizam texto; eles não substituem a exportação completa de texto ou de arquivos de imagem |
ExtractImages | Exportar objetos de imagem incorporados | Extrai bitmaps de imagem em vez de capturas de tela de páginas inteiras; o fixture embutido contém dois objetos de imagem reais em cada uma das duas páginas |
TableExtractionLab | Detectar tabelas e exportar CSV/JSON | Tabelas com linhas e alinhadas por espaços em branco, células mescladas, grupos de continuação e controles de confiança são independentes da extração de texto puro |
Attachment | Ler, adicionar e exportar anexos incorporados | Operações com o payload dos anexos vão além da listagem de nomes e tamanhos feita no ContentExtractionLab |
BatchExport | Exportar imagens de páginas de múltiplos documentos | Saída em streaming, status por arquivo e falhas isoladas demonstram processamento em lote em vez de uma única conversão |
CreatePDF | Criar conteúdo de página com pré-visualização ao vivo | As três variantes nativas criam texto pesquisável, formas vetoriais, uma imagem raster real, tabelas e uma anotação de revisão; as opções reconstruem a pré-visualização antes de um salvamento explícito |
ImageToPDF | Construir páginas a partir de arquivos de imagem de entrada | Layout, ajuste, ordenação e tratamento de JPEG fornecem um fluxo de trabalho de conversão de documentos |
MergePDF | Montar páginas de vários PDFs | Demonstra importação de documentos e composição ordenada; a divisão resolve o fluxo inverso |
SplitPDF | Gravar grupos de páginas selecionados em PDFs separados | A nomeação da saída e a validação de grupos de páginas diferem da mesclagem e da renderização de imagens de página |
WatermarkStamp | Aplicar sobreposições repetidas em páginas existentes | Posicionamento e carimbagem de páginas em lote complementam as APIs básicas de criação |
FormFill | Preenchimento e achatamento interativos de AcroForm | A entrada em campos e as aparências salvas diferem do intercâmbio XFDF e do comportamento específico de XFA |
AccessibilityReader | Leitura e fala interativas | O leitor com GUI demonstra navegação e destaque de leitura, em vez de uma auditoria de conformidade |
AccessibilityWorkbenchCli | Revisão de acessibilidade em lote e geração de relatórios | Descobertas, resumos e gates de revisão servem à automação; as descobertas não substituem a revisão manual de acessibilidade |
StandardsLab | Validação e conversão específicas de padrões | O lab interativo expõe operações e opções em vez de apenas gerar um relatório agregado |
PreflightReport | Relatórios interativos de padrões | A GUI suporta inspeção manual e exportação de relatórios |
PreflightReportCli | Relatórios automatizados de padrões | Entradas em lote, formatos de relatório e gates de código de saída fornecem a contraparte automatizada do PreflightReport |
IntakeWorkbenchCli | Intake, triagem e roteamento em lote | Relatórios agregados, gates de falha e decisões de roteamento fazem dele um fluxo de processamento que vai além da GUI do SecurityAudit |
Abra esses projetos a partir de Demo\Delphi\Miscellaneous, Demo\CBuilder\Miscellaneous ou Demo\Lazarus\Miscellaneous. Eles mantêm receitas úteis de API e tarefas de exportação pontuais, enquanto o diretório principal se concentra em experiências completas. Verificações básicas de escrita e releitura de Unicode ficam cobertas pelos fluxos de trabalho de criação e de extração, e não têm mais projetos de demo separados
| Demo | Use para | Como se diferencia dos demos relacionados |
|---|---|---|
SecurityAudit | Inspecionar a postura de segurança de forma interativa | A GUI enfatiza permissões, scripts, assinaturas e detalhes de segurança em vez de roteamento de arquivos |
XfdfLab | Importar e exportar dados XFDF | O intercâmbio e um salvamento explícito do PDF importado demonstram persistência; exportar apenas o XFDF não salva o PDF modificado |
AccessibilityLab | Percorrer as APIs de leitura em um console | Um passeio compacto e executável expõe unidades de leitura, caixas de palavras, estrutura e saída de script de fala |
ExtractText | Exportar texto completo de páginas selecionadas | Saída da camada de texto, separadores de página e cancelamento diferem das pré-visualizações de inventário e da detecção de tabelas; o demo não faz OCR |
FontProperties | Inspecionar métricas de fonte e de caracteres | Abre com as métricas reais de fonte e de caracteres do primeiro objeto de texto; selecione outra linha para comparar fontes sem exportar payloads de documentos |
NavigationLab | Favoritos, destinos e ações de navegação | O passeio compacto pelas APIs complementa os controles de navegação visíveis no PDFViewer |
PDFtoJpg | Renderizar um documento em imagens de página | Um exemplo compacto de renderização de um único documento; o Delphi expõe intervalos discretos de páginas, enquanto o BatchExport foca em múltiplos documentos de entrada |
PrintPreferences | Folhas N-up e preferências de impressão do autor do PDF | O foco didático está em cópias, filtragem de páginas ímpares/pares e preferências fornecidas pelo autor; ele complementa o PrintPDF |
ViewerInteractionLab | Diagnosticar interações de mouse, teclado e coordenadas | O log de interações e a conversão entre coordenadas de página e de dispositivo fazem dele uma ferramenta de diagnóstico de API |
XfaLab | Pacotes XFA estáticos e capacidades do runtime | Abre pacotes de template e datasets com o runtime comum; a renderização interativa de XFA requer um runtime com XFA habilitado, com variantes para Delphi e Lazarus |
O PDFViewer abre seu PDFiumDemoShowcase.pdf embutido, um documento de seis páginas com texto pesquisável, gráficos vetoriais, duas imagens incorporadas, uma tabela, quatro campos AcroForm, favoritos por capítulo, links, uma nota de revisão e dois anexos. A barra de experiência oferece Restart showcase, Find live text, 2-page spread, Night reading, Inspect this PDF e Explore forms; cada ação funciona no documento atual
O CreatePDF abre uma pré-visualização ao vivo de um relatório de duas páginas. Edite o título e o autor ou alterne formas, a tabela e a marca d'água para reconstruir o conteúdo real das páginas; a opção Unicode adiciona uma terceira página. Nada é gravado até você salvar, e o PDF salvo continua pesquisável
MultiPageViewer, SearchAndSelect, ContentExtractionLab e FormFill abrem o mesmo documento para seus próprios fluxos de trabalho, com resultados de pesquisa, um inventário de extração e campos editáveis prontos imediatamente. O Miscellaneous\NavigationLab usa sua própria cópia local para um passeio pelas APIs de favoritos e destinos
O Attachment começa com dois arquivos incorporados reais. O PrintPreferences começa com quatro páginas e preferências do autor para duas cópias, intervalos de páginas selecionados, escala e duplex; o fluxo de impressão atual aplica cópias e intervalos de páginas, enquanto escala e duplex são inspecionados e relatados. O XfaLab começa com pacotes reais de template e datasets para inspeção de XFA estático; a renderização interativa de XFA requer um runtime apropriado e é uma capacidade separada
Cada projeto de visualização, formulário, extração e navegação contém seu próprio PDFiumDemoShowcase.pdf. Copie o diretório do projeto e mantenha essa entrada embutida ao lado do executável distribuído; os builds do Lazarus fazem seu staging automaticamente. O passeio funciona offline, e os visualizadores gerais e os exemplos de extração também fornecem conteúdo gerado como fallback quando o PDF local não está disponível
Cada demo nativo contém sua própria implementação de exemplo. Os pontos de entrada Delphi e Lazarus de AccessibilityLab, AccessibilityWorkbenchCli, IntakeWorkbenchCli e PreflightReportCli incluem o fluxo de trabalho completo no diretório do projeto, com a inicialização de framework específica do compilador e o writer de JPEG. Os exemplos de anexos, preferências de impressão e XFA também constroem localmente suas próprias entradas específicas de cada recurso. Fora do projeto copiado, apenas a biblioteca, o runtime nativo correspondente e as dependências normais do framework do compilador são necessários
Escolha a extração de objetos de imagem quando precisar de bitmaps incorporados, a renderização de página quando precisar da página visível e a extração de texto quando o PDF já tem camada de texto. Um relatório que lista essas categorias não exporta seus payloads completos. Esses limites mantêm os exemplos focados úteis sem transformar cada demo em mais um visualizador ou workbench de propósito geral
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;
Os projetos Demo\Delphi\Miscellaneous\FontProperties, Demo\CBuilder\Miscellaneous\FontProperties e Demo\Lazarus\Miscellaneous\FontProperties mostram os mesmos metadados tanto via TPdf quanto via TPdfView
Os projetos Demo\Delphi\ContentExtractionLab, Demo\CBuilder\ContentExtractionLab e Demo\Lazarus\ContentExtractionLab transformam a extração de conteúdo em um único fluxo de trabalho. Eles abrem ou criam um PDF, permitem que os usuários escolham metadados, texto de página, objetos de página, imagens, anexos, links, anotações, favoritos e métricas de fonte / caractere, e em seguida geram um resumo mais um relatório TXT ou JSON detalhado. O lab também inclui seleção de categoria todas / nenhuma, cópia de relatório para a área de transferência e ações de salvamento de PDF de origem, para que os usuários possam manter o PDF de exemplo gerado ao lado de seu relatório de extração. ExtractImages e Attachment fornecem fluxos de trabalho de exportação de payload, enquanto Miscellaneous\ExtractText e Miscellaneous\FontProperties mantêm exemplos focados de API; ExtractText suporta opções de intervalo de páginas e separador de páginas para produzir saída de texto por página em Delphi, C++Builder e Lazarus, enquanto ContentExtractionLab é o exemplo de inventário transversal
Os projetos Demo\Delphi\TableExtractionLab, Demo\CBuilder\TableExtractionLab e Demo\Lazarus\TableExtractionLab transformam a detecção de tabelas em um único fluxo de trabalho. O laboratório constrói um documento de exemplo contendo uma tabela com linhas e células de cabeçalho mescladas, uma tabela alinhada por espaços em branco sem linhas e uma tabela longa que se quebra em um limite de página, e então executa ExtractTables para a página atual ou ExtractDocumentTables para o documento inteiro e reporta linhas, colunas, valores de RowSpan e ColumnSpan, sinalizadores de cabeçalho, modo de detecção, confiança e grupos de continuação. As opções DetectRuledTables, DetectWhitespaceTables, DetectContinuations, DetectFilledRulings e MinConfidence podem ser editadas na interface, e a tabela selecionada é exportada por meio de TPdfTable.ToCsv e TPdfTable.ToJson. O laboratório também processa em lote uma pasta inteira: Batch folder executa ExtractDocumentTables em cada PDF, reporta as contagens de tabelas por documento, sinaliza varreduras sem camada de texto e repete documentos vazios com uma predefinição de colunas compactas; Export all CSV grava cada tabela detectada ao lado dos arquivos de origem. Cada documento abre em sua própria instância de TPdf, de modo que um arquivo ilegível não pode afetar o restante do 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;
// Sem achatamento, FormField[i] := value escreve apenas a entrada /V —
// a aparência visível vem do stream /AP e pode não ser atualizada.
// GenerateFormAppearances regenera /AP para cada widget, então
// FlattenAllPages grava as anotações e widgets de cada página
// em conteúdo permanente e não editável.
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);
// Cria um documento PDF compactado
Pdf1.CreateDocument;
Pdf1.Compressed := True; // garante que todos os streams sejam compactados com FlateDecode (padrão)
Pdf1.Active := True;
Pdf1.AddPage(0, 595, 842); // tamanho A4
Pdf1.AddText('Hello World!', 'Arial', 24, 100, 700, clBlack, $FF, 0.0);
Pdf1.SaveAs('C:\Compressed.pdf');
Pdf1.Active := False;
// Salvar com opções
Pdf1.SaveAs('C:\Output.pdf', saIncremental); // salvamento incremental
Pdf1.SaveAs('C:\NoSecurity.pdf', saRemoveSecurity); // remove a segurança
// Salvar em uma versão de PDF de destino específica. O validador de versão PDF rejeita
// qualquer recurso introduzido após a versão de destino escolhida (JBIG2Decode, MarkInfo,
// criptografia AES, anotações Polygon / Caret / Watermark / Redact, ...).
if not Pdf1.SaveAs('C:\Legacy15.pdf', saNone, pv15) then
ShowMessage('Salvamento rejeitado: o documento contém recursos mais novos que PDF 1.5');
// SaveAsPdfA pós-processa o salvamento base com uma atualização incremental que
// injeta um stream de metadados XMP, um OutputIntent ICC sRGB e um Catalog
// de documento atualizado, de modo que o resultado seja compatível com PDF/A-1b.
// O perfil sRGB IEC61966-2.1 incluso é usado automaticamente quando nenhum
// perfil personalizado é fornecido.
Pdf1.FileName := 'C:\Report.pdf';
Pdf1.Active := True;
if Pdf1.SaveAsPdfA('C:\Report.pdfa.pdf', pac1b) then
ShowMessage('Arquivo PDF/A-1b salvo');
// PDF/A com perfil ICC personalizado (pipelines de impressão CMYK, por exemplo)
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;
// Saída PDF/A em memória
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;
// Sondagem barata estilo cabeçalho — lê a conformidade sem iterar
// o validador completo. Resultado: pacNone, pac1a, pac1b, pac2b, pac3b ou
// pacUnknown.
case Pdf1.PdfAConformance of
pac1b: Status.Caption := 'PDF/A-1b';
pac2b: Status.Caption := 'PDF/A-2b';
pacNone: Status.Caption := 'Não é PDF/A';
else
Status.Caption := 'Conformidade desconhecida';
end;
// Validador completo com diagnósticos por problema
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;
Os projetos Demo\Delphi\StandardsLab, Demo\CBuilder\StandardsLab e Demo\Lazarus\StandardsLab carregam ou criam um PDF, executam ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR e ValidatePdfVT, e em seguida mostram cada nível de conformidade detectado e contagem de problemas em uma única grade. Seus botões de salvar chamam SaveAsPdfA, SaveAsPdfUa, SaveAsPdfE, SaveAsPdfX, SaveAsPdfR e SaveAsPdfVT, de modo que o fluxo de trabalho de saída com marcadores fique visível sem escrever uma harness personalizada
A unit FPdfPreflightReport encapsula ValidatePdfA, ValidatePdfUa, ValidatePdfE, ValidatePdfX, ValidatePdfR e ValidatePdfVT em um único objeto de relatório consultável com severidade Info / Warning / Error, agregação de status e problemas, busca, pesquisa, filtragem e impressões digitais SHA-256 estáveis. Os relatórios podem ser emitidos como texto, HTML, Markdown, JSON, CSV, SARIF 2.1.0, JUnit XML, NDJSON ou XML nativo. Demo\Delphi\PreflightReport, Demo\Lazarus\PreflightReport e Demo\CBuilder\PreflightReport fornecem fluxos de trabalho interativos de seleção e pré-visualização, enquanto Demo\Delphi\PreflightReportCli acrescenta argumentos de entrada / saída programáveis, filtragem de padrão, incorporação opcional de anexo de relatório, gating de código de saída para CI, processamento de lista e diretório em lote, roteamento seguro contra colisões, resumos agregados e manifestos CSV. O relatório gerado informa que os validadores integrados cobrem verificações em nível de marcador e seleções em nível de arquivo, de modo que o preflight completo em nível de conteúdo ainda possa ser delegado a um motor de validação dedicado
// LoadCustomDocument permite que o PDFium puxe blocos de qualquer TStream
// pesquisável sob demanda. O stream NÃO é copiado para a memória, de modo
// que PDFs de vários GB, streams de corpo HTTP remoto e fontes baseadas
// em banco de dados são viáveis sem um buffer antecipado.
var
FileStream: TFileStream;
begin
// Streaming de leitura de arquivo (sem cópia em memória)
FileStream := TFileStream.Create('C:\Huge.pdf',
fmOpenRead or fmShareDenyWrite);
Pdf1.LoadCustomDocument(FileStream, True{AOwnsStream});
// ^^ propriedade transferida — Pdf1 libera FileStream em UnloadDocument.
Pdf1.Active := True;
ShowMessage('Pages: ' + IntToStr(Pdf1.PageCount));
end;
// Stream de propriedade externa (chamador libera após 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 expõe IPdfCancellationToken /
// IPdfCancellationTokenSource para semântica de cancelar a partir da UI
// que funciona nos caminhos de exportação e renderização de longa duração.
uses FPdfAsync;
var
CancelSource: IPdfCancellationTokenSource;
CancelToken: IPdfCancellationToken;
begin
CancelSource := PdfCancellationTokenSource;
CancelToken := CancelSource.Token;
// ... usuário clica em Cancelar ...
CancelSource.Cancel;
// O worker verifica periodicamente CancelToken.IsCancelled, ou o caminho
// de renderização o consulta através do callback IFSDK_PAUSE do PDFium.
if CancelToken.IsCancelled then
Memo1.Lines.Add('Cancelled by user');
end;
// RenderPageProgressive permite que uma renderização longa em alto DPI seja
// abortada no meio da página quando o usuário clica em Cancelar, em vez de
// bloquear o chamador até a conclusão.
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('Renderização cancelada — resultado parcial disponível');
prsFailed: Memo1.Lines.Add('PDFium relatou FPDF_RENDER_FAILED');
end;
finally
Bitmap.Free;
end;
end;
// TPdfFuture<T> inicia um worker em uma thread de trabalho em segundo plano
// e envia um envelope TPdfFutureResult<T> de volta para a thread principal.
//
// Importante: TPdf serializa chamadas de renderização por instância, mas o worker
// ainda é proprietário do despacho e do ciclo de vida do documento. Não mute um TPdf
// enquanto uma renderização está em andamento; exportação em lote geralmente mantém
// um TPdf por arquivo.
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 encapsula a FS_MATRIX do PDFium para que os chamadores possam construir
// uma transformação declarativamente e entregá-la 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 1 pol à direita, ~2,8 pol acima
M.Scale(0.5, 0.5); // carimbo com metade do tamanho
M.Rotate(15); // rotação de 15 graus no sentido anti-horário
// M.HorizontalFlip;
// M.VerticalFlip;
// M.CentralFlip;
// M.Skew(10, 5);
// M.Multiply(Other); // pós-multiplica com outra matriz
// Aplicar a qualquer objeto de página PDFium (texto / caminho / imagem / Form XObject)
RawMatrix := M.Handle;
FPDFPageObj_SetMatrix(PageObj, RawMatrix);
finally
M.Free;
end;
end;
// ImportPagesByIndex copia um array explícito de índices baseado em zero de
// um PDF de origem para este documento. InsertAt = 0 insere antes da página 1;
// PageCount anexa.
var
Source: TPdf;
begin
Source := TPdf.Create(nil);
try
Source.FileName := 'C:\Report.pdf';
Source.Active := True;
// Importa as páginas 0, 2, 4 (baseado em um: páginas 1, 3, 5) de Source
// e as anexa ao final de Pdf1.
Pdf1.ImportPagesByIndex(Source, [0, 2, 4], Pdf1.PageCount);
// Array vazio importa todas as páginas de origem
// Pdf1.ImportPagesByIndex(Source, [], 0);
finally
Source.Free;
end;
end;
// ImportNPagesToOne retorna um novo TPdf cujas páginas são compostos NumX*NumY
// DESTE documento. OutputWidth/Height são unidades de usuário PDF
// (1 unidade = 1/72 pol).
var
Composite: TPdf;
begin
Pdf1.FileName := 'C:\Slides.pdf';
Pdf1.Active := True;
// A4 paisagem 4-up: 842 x 595 pt, 2 colunas x 2 linhas
Composite := Pdf1.ImportNPagesToOne(842, 595, 2, 2);
try
if Composite <> nil then
Composite.SaveAs('C:\Slides_4up.pdf');
finally
Composite.Free;
end;
end;
// MovePages recebe os índices baseados em zero das páginas a serem movidas mais
// o índice de destino para a primeira página movida após a conclusão do movimento.
// Outras páginas se deslocam em torno do bloco movido, de modo que o comprimento
// do documento permaneça o mesmo.
//
// Exemplo: em um documento de 5 páginas com páginas numeradas [0,1,2,3,4],
// MovePages([2, 3], 0) reordena para [2, 3, 0, 1, 4].
if not Pdf1.MovePages([2, 3], 0) then
ShowMessage('Índices inválidos passados para MovePages');
// CreateXObjectFromPage fabrica um handle de Form XObject reutilizável a partir
// de qualquer página de qualquer outro TPdf. Estampe esse handle em quantas
// páginas DESTE documento você quiser — cada carimbo é um único objeto de
// página PDFium que pode ser posicionado, escalonado e rotacionado através
// da API de matriz.
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;
// Encapsula a página 0 de WatermarkSource como um XObject reutilizável
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;
// Centraliza a marca d'água na 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; // fecha o handle FPDF_XOBJECT
end;
Pdf1.SaveAs('C:\Watermarked.pdf');
finally
WatermarkSource.Free;
end;
end;
Os projetos Demo\Delphi\WatermarkStamp, Demo\Lazarus\WatermarkStamp e Demo\CBuilder\WatermarkStamp transformam esse padrão em um fluxo de trabalho executável: criam um PDF de destino e um PDF de carimbo reutilizável, encapsulam a página de carimbo com CreateXObjectFromPage, inserem o mesmo Form XObject em cada página de destino, aplicam transformações TPdfMatrix para marcas d'água centralizadas e carimbos no canto superior direito, e adicionam rótulos opcionais de número de página antes de salvar o resultado
// AddImage(FileName) aceita qualquer formato registrado com as unidades de
// gráficos VCL ou LCL (BMP, PNG via PngImage, JPG, ...).
Pdf1.AddImage('C:\Photo.png', 100, 500, 200, 150);
// AddImage(TBitmap) pula o intermediário TPicture, ideal quando o
// bitmap já vem de trabalho de renderização ou geração em lote.
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;
Os projetos Demo\Delphi\ImageToPDF, Demo\CBuilder\ImageToPDF e Demo\Lazarus\ImageToPDF transformam isso em um fluxo de trabalho de lote completo: selecione vários arquivos de imagem, pré-visualize o item selecionado, crie uma página PDF por imagem, escale cada imagem em uma página A4 retrato ou paisagem, salve o resultado e abra o PDF gerado
var
MatchCount: Integer;
begin
// Pinta uma máscara clYellow sobre cada correspondência na página atual da visualização.
// Mudar para uma página diferente limpa o destaque automaticamente.
PdfView1.HighlightColor := clYellow;
MatchCount := PdfView1.HighlightSearchText('invoice', False{Case}, True{Word});
Status.Caption := Format('%d correspondência(s) nesta página', [MatchCount]);
// Remover programaticamente a sobreposição antes da mudança de página
PdfView1.ClearHighlight;
end;
// FitMode mantém documentos longos enquadrados durante Resize ou mudanças de página.
// Definir Zoom diretamente cancela FitMode (reverte para pfmNone).
PdfView1.FitMode := pfmFitPage; // página inteira na viewport
// PdfView1.FitMode := pfmFitWidth; // largura da página corresponde à largura da viewport
// PdfView1.FitMode := pfmActualSize; // 100%
// PageColor desacopla a página PDF renderizada da Color do controle hospedeiro
// — configuração típica de visualizador em modo escuro mantém a área de rolagem
// escura enquanto a página PDF permanece branco-papel.
PdfView1.Color := clBlack; // área de rolagem
PdfView1.PageColor := clWhite; // fundo da página PDF
// Sombra projetada e borda de página opcionais para destacar a página de um fundo escuro
PdfView1.PageShadowSize := 6;
PdfView1.PageShadowColor := $00404040;
PdfView1.PageBorderColor := clGray;
Os projetos Demo\Delphi\Miscellaneous\ViewerInteractionLab, Demo\CBuilder\Miscellaneous\ViewerInteractionLab e Demo\Lazarus\Miscellaneous\ViewerInteractionLab mantêm a superfície moderna de interação do TPdfView em um formulário compacto: abrir ou criar um PDF de exemplo, alternar DisplayMode, aplicar FitMode, alterar PageColor, rotacionar páginas, destacar correspondências de pesquisa da página atual com HighlightSearchText, habilitar ou desabilitar a seleção de texto pelo usuário, inspecionar SelectedText, chamar SelectAll, CopySelectionToClipboard e ClearSelection, e observar as coordenadas DeviceToPage atualizarem na barra de status enquanto o mouse se move sobre a página
Os projetos Demo\Delphi\SearchAndSelect, Demo\CBuilder\SearchAndSelect e Demo\Lazarus\SearchAndSelect transformam o fluxo de trabalho de pesquisa e seleção do visualizador em amostras autônomas. Eles abrem ou criam um PDF, listam resultados de pesquisa em todas as páginas com número de página, índice de caractere e texto de pré-visualização, suportam navegação Anterior / Próximo e salto de resultado por clique duplo, destacam correspondências da página atual com HighlightSearchText, expõem opções de correspondência de maiúsculas e palavra inteira, alternam AllowUserTextSelection, pré-visualizam SelectedText, controlam SelectAll, CopySelectionToClipboard e ClearSelection a partir de botões, e permitem que os usuários alternem entre modos de exibição único e layout
Os projetos Demo\Delphi\Miscellaneous\PrintPreferences, Demo\CBuilder\Miscellaneous\PrintPreferences e Demo\Lazarus\Miscellaneous\PrintPreferences leem as preferências de impressão do autor antes de imprimir. Eles exibem PrintCopies, PrintPageRanges, PrintScaling e PrintPaperHandling, podem copiar cópias e intervalos fornecidos pelo autor para as entradas de impressão, e mostram como SetPdfPrintPaperHandlingDevMode mapeia a intenção de duplex do PDF em um DEVMODE do Windows
Os projetos Demo\Delphi\PrintPDF, Demo\CBuilder\PrintPDF e Demo\Lazarus\PrintPDF mostram o fluxo de trabalho padrão de impressão: abrir um PDF, pré-visualizar páginas, escolher intervalos de páginas e cópias no diálogo de impressão da plataforma, honrar o modo de agrupamento, renderizar cada página através de TPdf.RenderPage e expor o progresso de impressão com cancelamento. A amostra Delphi também aceita arquivos PDF arrastados para carregamento rápido
Os projetos Demo\Delphi\MultiPageViewer, Demo\CBuilder\MultiPageViewer e Demo\Lazarus\MultiPageViewer exercitam visualização contínua, em layout e com capa, com fluxos de trabalho regulares de navegação entre páginas e zoom. Também são úteis para testar a velocidade de abertura na primeira página e a responsividade de renderização em PDFs muito grandes: em testes de arquivos grandes, documentos de 2,x GB que podem fazer o Acrobat ou o Foxit demorar 20-30 segundos antes da primeira visualização podem se tornar utilizáveis quase imediatamente através do caminho do visualizador PDFium Delphi Component
Os projetos Demo\Delphi\SplitView, Demo\CBuilder\SplitView e Demo\Lazarus\SplitView mostram revisão de PDF lado a lado. As amostras C++Builder e Lazarus focam em comparação de dois ou três painéis, seleção de visualização ativa, comandos opcionais de navegação sincronizada, presets de zoom compartilhados e rotação para a visualização selecionada ou todas as visualizações carregadas. Use essas amostras para comparar documentos grandes mantendo a primeira visualização utilizável e a renderização de páginas subsequentes responsivas; os mesmos arquivos PDF de 2,x GB que podem levar de 20 a 30 segundos para abrir no Acrobat ou Foxit podem se tornar utilizáveis quase imediatamente no caminho do visualizador PDFium Delphi Component
Os projetos Demo\Delphi\SecurityAudit, Demo\CBuilder\SecurityAudit e Demo\Lazarus\SecurityAudit abrem um PDF somente leitura e listam estado de permissão, anexos incorporados, ações JavaScript do documento, anotações de link URI e Launch, links da web, resumos de assinatura, estado XFA, disponibilidade de auxiliar V8 e callbacks de recurso não suportado. As mesmas linhas de resumo e descoberta podem ser salvas ou copiadas como um relatório de auditoria TXT ou salvas como JSON estruturado. Eles são destinados como painéis de risco da aplicação hospedeira, não como detecção de malware
// LinkOptions controla a manipulação automática dos quatro tipos de ação
// de link PDF. Os padrões habilitam apenas goto e URI; launch (executar
// um programa) e GotoR incorporado (saltar para outro arquivo) permanecem
// DESLIGADOS, de modo que um clique perdido não possa executar código
// arbitrário.
PdfView1.LinkOptions :=
[loAutoGoto, loAutoOpenURI]; // padrões seguros
// OnAnnotationLinkClick dispara para destinos dentro do documento (saltos
// de página, destinos nomeados, cadeias de ação). Marque Handled = True
// para impedir que a visualização siga automaticamente o link.
procedure TForm1.PdfView1AnnotationLinkClick(Sender: TObject;
LinkIndex: Integer; const Action: TPdfAction;
var Handled: Boolean);
begin
if Action.Kind = paUri then
begin
if MessageDlg('Abrir ' + Action.Uri + '?', mtConfirmation, [mbYes, mbNo], 0)
<> mrYes then
Handled := True; // suprime tratamento automático
end;
end;
// OnWebLinkClick dispara para strings URI descobertas pelo scanner de
// links da web do PDFium (URLs autodetectadas no stream de texto, mesmo
// sem uma anotação /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;
// No widget AcroForm em foco, seis novos métodos controlam o histórico
// de edição de formulário do PDFium. Todos os seis fazem curto-circuito
// de forma segura se nenhum widget estiver em foco ou o documento não
// possuir 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;
// Os três têm o padrão True, de modo que aplicações existentes atualizem
// sem alteração de comportamento. Defina como False para quiosques,
// painéis de visualização ou incorporações somente leitura sem fazer
// subclasse de TPdfView.
PdfView1.AllowUserPageChange := False; // PgUp/PgDn/Ctrl+Home/End
PdfView1.ChangePageOnMouseScrolling := False; // saltos de roda para cima/baixo
PdfView1.AllowUserTextSelection := False; // seleção de texto via mouse/teclado
// Ctrl+roda é reservado para zoom e é ignorado pelo manipulador de
// navegação independentemente de ChangePageOnMouseScrolling.
// TPdfThumbnailView (unit FPdfThumbnail) renderiza uma miniatura de página
// por linha em um painel lateral rolável.
uses FPdfThumbnail;
procedure TForm1.FormCreate(Sender: TObject);
begin
ThumbView.Pdf := Pdf1;
ThumbView.ThumbnailWidth := 120;
ThumbView.ThumbnailHeight := 160;
ThumbView.SelectionColor := $00CFA85F; // destaque quente
ThumbView.OnPageClick := ThumbViewPageClick;
end;
procedure TForm1.ThumbViewPageClick(Sender: TObject; PageIndex: Integer);
begin
PdfView1.PageNumber := PageIndex + 1; // PageIndex é baseado em zero
end;
procedure TForm1.PdfView1PageNumberChanged(Sender: TObject);
begin
ThumbView.CurrentPageIndex := PdfView1.PageNumber - 1;
end;
// Padrão usado por Demo\Delphi\BatchExport, Demo\CBuilder\BatchExport
// e Demo\Lazarus\BatchExport. Um TPdf por arquivo, IPdfCancellationToken
// para cancelar a partir da UI, TPdfStreamAdapter para carregamento de
// arquivo com buffer.
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 é uma sondagem barata no Catalog — True quando /StructTreeRoot existe.
// StructureElements materializa a árvore em um array plano de
// records TPdfStructureElement com tipo, título, texto alternativo, texto real,
// texto de expansão, idioma, nível, índice do pai e contagens de filhos /
// marked content / atributos.
var
Elements: TPdfStructureElements;
I: Integer;
begin
if not Pdf1.IsTagged then
begin
Log.Add('Documento NÃO está tagged — ferramentas de acessibilidade podem ter dificuldades.');
Exit;
end;
if Pdf1.Language = '' then
Log.Add('Tagged PDF sem /Lang — falha em 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 é uma função global que mapeia para o
// FPDF_SetPrintMode do PDFium. Use o valor TPdfPrintMode correspondente
// para o driver de impressora em uso.
SetPdfPrintMode(pmEmf); // GDI EMF (padrão)
// SetPdfPrintMode(pmTextOnly); // renderização somente texto
// SetPdfPrintMode(pmPostScript2); // PostScript Nível 2
// SetPdfPrintMode(pmPostScript3); // PostScript Nível 3
// SetPdfPrintMode(pmPostScript2PassThrough);
// SetPdfPrintMode(pmPostScript3PassThrough);
// SetPdfPrintMode(pmEmfImageMasks); // EMF + máscaras de imagem
// SetPdfPrintMode(pmPostScript3Type42); // PostScript 3 + fontes Type 42
// PrintCopies, PrintPageRanges, PrintScaling e PrintPaperHandling são
// as entradas do dicionário de preferências do visualizador — elas
// codificam o que o autor do documento queria que os leitores de PDF
// usassem como padrão.
var
Ranges: TPrintPageRanges;
Range: TPrintPageRange;
begin
ShowMessage('Cópias sugeridas: ' + IntToStr(Pdf1.PrintCopies));
ShowMessage('Escala de impressão: ' + GetEnumName(TypeInfo(TPrintScaling),
Ord(Pdf1.PrintScaling)));
Ranges := Pdf1.PrintPageRanges; // intervalos baseados em um
for Range in Ranges do
Log.Add(Format('Páginas %d..%d', [Range.First, Range.Last]));
if SetPdfPrintPaperHandlingDevMode(PrinterDevMode, Pdf1.PrintPaperHandling) then
ApplyPrinterDevMode(PrinterDevMode);
end;
// JavaScript no nível do documento é armazenado na árvore de nomes
// /Names /JavaScript. JavaScriptAction[i] retorna uma entrada;
// JavaScriptActions retorna o 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;
// Caminho de renderização zero-copy (padrão desde v1.21.0): RenderPage grava
// diretamente no buffer DIB do TBitmap de destino quando os chamadores passam um
// bitmap pré-alocado, evitando uma cópia de largura * 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;