---
title: "Versão para impressão"
description: "Geração da versão para impressão de um PDF assinado com o PKI SDK: o PdfMarker marca cada página com os signatários e um código de verificação e acrescenta uma página de resumo."
canonical: "https://docs.lacunasoftware.com/articles/pki-sdk/printer-friendly-version"
locale: "pt-BR"
product: "PKI SDK"
last_updated: "2026-10-12"
---

# Versão para impressão

A cópia impressa de um documento assinado não leva as assinaturas digitais. A versão para impressão compensa isso: cada
página mostra quem assinou o documento e um código de verificação, para que quem receber o papel possa visitar o seu
site, informar o código e obter de volta o arquivo assinado digitalmente. 

No PKI SDK, a classe `AlphaCode` gera o código de verificação e o `PdfMarker` (namespace `Lacuna.Pki.Pdf`) grava marcas,
compostas de textos e imagens, nas páginas de um PDF. 

## Como funciona

1. Na primeira vez em que um documento for solicitado, gere o código de verificação dele com `AlphaCode.Generate()` e
   guarde-o junto com o documento. O código é gerado sem formatação: mostre-o aos usuários com `AlphaCode.Format`, por
   exemplo como `XXXX-XXXX-XXXX-XXXX`. Veja [Gerando códigos alfanuméricos](https://docs.lacunasoftware.com/articles/pki-sdk/alpha-codes).
1. Abra o PDF assinado com `PadesSignature.Open` e leia os signatários em `Signers`, por exemplo o nome no certificado de
   cada um e a data e hora da assinatura.
1. Crie um `PdfMarker` e adicione um `PdfMark` por marca com `AddMark`.
1. Defina `ThrowIfSignedPdf` como `false`. O padrão é `true`, e com ele o `PdfMarker` lança `SignedPdfToMarkException`
   (namespace `Lacuna.Pki.Exceptions`) se o PDF tiver qualquer assinatura.
1. Chame `WriteMarks(pdfContent)`, que retorna o PDF com as marcas. Todas as assinaturas são removidas do arquivo antes de
   as marcas serem aplicadas, então a versão para impressão não é um arquivo assinado.
1. Na sua página de verificação, converta o código digitado pelo usuário para a forma guardada com `AlphaCode.Parse`,
   localize o documento e valide as assinaturas como de costume, com `PadesSignature.Open` e `ValidateSignature`. O
   exemplo espera dois segundos antes de responder a um código desconhecido, para dificultar ataques de força bruta.

## Exemplo

Adaptado do exemplo: um resumo na margem inferior de todas as páginas e uma nova página no fim do documento com o código
de verificação.

```cs
var formattedCode = AlphaCode.Format(verificationCode);

// Names of the signers, for the summary
var signature = PadesSignature.Open(pdfContent);
var signerNames = string.Join(", ", signature.Signers.Select(s => s.Signer.SigningCertificate.SubjectName.CommonName));
var summary = $"This document was digitally signed by {signerNames}.\nTo verify the signatures go to {verificationSite} and inform the code {formattedCode}";

var pdfMarker = new PdfMarker();

// Summary on the bottom margin of every page
pdfMarker.AddMark(new PdfMark() {
    PageOption = PdfMarkPageOptions.AllPages,
    Container = new PadesVisualRectangle() { Height = 2, Bottom = 0, Left = 1.5, Right = 3.5 },
    Elements = new List<PdfMarkElement>() {
        new PdfMarkText() {
            Texts = new List<PdfTextSection>() {
                new PdfTextSection() { Style = PdfTextStyle.Normal, Text = summary }
            }
        }
    }
});

// New page at the end of the document, with 1-inch margins
var summaryPage = new PdfMark() {
    PageOption = PdfMarkPageOptions.NewPage,
    Container = new PadesVisualRectangle() { Top = 2.54, Bottom = 2.54, Left = 2.54, Right = 2.54 }
};
summaryPage.Elements.Add(new PdfMarkText() {
    RelativeContainer = new PadesVisualRectangle() { Top = 0, Height = 2, Left = 0, Right = 0 },
    Align = PadesHorizontalAlign.Center,
    Texts = new List<PdfTextSection>() {
        new PdfTextSection() { Style = PdfTextStyle.Normal, FontSize = 14, Text = $"Verification code: {formattedCode}" }
    }
});
pdfMarker.AddMark(summaryPage);

pdfMarker.ThrowIfSignedPdf = false;   // the PDF is signed: don't throw SignedPdfToMarkException
var pfvContent = pdfMarker.WriteMarks(pdfContent);
```

A página de resumo do exemplo traz também o logotipo da ICP-Brasil, um QR code com o link de verificação (uma imagem PNG
gerada com a biblioteca QRCoder) e uma linha por signatário, com um ícone verde ou vermelho conforme o resultado de
`ValidateSignature`. O exemplo também põe o resumo na margem direita de todas as páginas, girado com
`PdfMarkRotation.D90` para que o texto fique na vertical, de baixo para cima. 

## Marcas

Um `PdfMark` é uma marca aplicada nas páginas do PDF:

| Propriedade | O que define |
| --- | --- |
| `PageOption` | As páginas que recebem a marca, um `PdfMarkPageOptions`: `AllPages`; `NewPage`, uma nova página acrescentada no fim do documento; ou `SinglePage` e `SinglePageFromEnd`, junto com a propriedade `PageOptionNumber`. |
| `Container` | A posição da marca na página, um `PadesVisualRectangle`: a classe que posiciona a representação visual das assinaturas, explicada em [Definindo um container](https://docs.lacunasoftware.com/articles/pki-sdk/signatures/pades/visual-rep/containers). |
| `MeasurementUnits` | `PadesMeasurementUnits.Centimeters` ou `PadesMeasurementUnits.PdfPoints`. O exemplo não a define, e as medidas dele estão em centímetros (2,54 para margens de 1 polegada). |
| `Elements` | Os textos e as imagens da marca: uma lista de `PdfMarkText` e `PdfMarkImage`. |
| `BorderWidth`, `BorderColor`, `BackgroundColor` | A borda e o fundo da marca. |

Todo elemento tem um `RelativeContainer`, a posição dele dentro do `Container` da marca; uma `Rotation`, `D0`, `D90`,
`D180` ou `D270` (em graus); e uma `Opacity`, 100 (opaco) por padrão. Além disso:

- O `PdfMarkText` tem `Texts`, uma lista de `PdfTextSection`, cada um com seu `Text`, `Style` (`Normal`, `Bold`, `Italic`
  ou `Underline`, que podem ser combinados), `FontSize` e `Color` (preto por padrão); e `Align`, `VerticalAlign` e
  `LineSpacing`, um multiplicador do tamanho da fonte.
- O `PdfMarkImage` tem `ImageContent`, os bytes da imagem; o exemplo usa imagens PNG.

## Outras opções

- `PreserveSignaturesVisualRepresentation`: mantém no PDF as imagens da representação visual das assinaturas, se houver.
- `NewPagesTemplate`: um `PdfPageTemplate` com o tamanho e a orientação das páginas criadas pelas marcas `NewPage`. Se não
  for definido, é usado o tamanho de papel mais comum entre as páginas do PDF, em retrato.
- `CreateContext` e `ComputeRequiredArea`: calculam a área de que um texto precisa antes de você posicioná-lo; depois,
  chame `WriteMarks(context)`.
- `WriteMarks(Stream, Stream)` lê o PDF de um stream e grava o resultado em outro.

## Assinaturas CAdES

Um arquivo CMS/CAdES não é um PDF, então o exemplo de CAdES monta a versão para impressão como um documento novo: ele lê
os signatários com `CadesSignature.Open` e grava a marca de resumo num PDF em branco que acompanha o exemplo. 

## Veja também

* [Gerando códigos alfanuméricos](https://docs.lacunasoftware.com/articles/pki-sdk/alpha-codes)
* [Assinaturas padrão PAdES](https://docs.lacunasoftware.com/articles/pki-sdk/signatures/pades)
* [`PdfMarker` na referência da API](https://docs.lacunasoftware.com/api/Lacuna.Pki.Pdf/PdfMarker)
* [Lacuna PKI SDK](https://docs.lacunasoftware.com/articles/pki-sdk)

**Demonstrações e exemplos**

- Demonstração: [Make a printer-friendly version](https://try.lacunasoftware.com/pt/pki-suite/printer-friendly-version)
- Make a printer-friendly version of a signed PDF using PKI SDK: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/PrinterFriendlyPadesSdkController.cs)
- Make a printer-friendly version of a CMS/CAdES signature using PKI SDK: [.NET](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/dotnet/mvc/PkiSuiteAspNetMvcSample/Controllers/PrinterFriendlyCadesSdkController.cs)
