ShieldSign PKIDocumentação

Assinatura visível

Carimbo no PDF com texto, imagem e posição definidos por você.

Por padrão a assinatura é invisível: está no arquivo e aparece no painel de assinaturas do leitor de PDF. Com a assinatura visível, o PDF ganha um carimbo na página, com o texto, a imagem e a posição que o seu sistema definir. A API só desenha o que for pedido, dentro do campo da assinatura (não é possível acrescentar o carimbo depois de assinar).

O pedido vai no prepare, porque o certificado já é conhecido e permite preencher o nome e o CPF do signatário:

// pontos = 1/72 de polegada; a origem é o canto INFERIOR esquerdo da página (A4 em pé = 595 x 842)
$visual = ShieldSign\Client::visualRepresentation(
    page: 'last',                      // 1, 2, ... ou 'last'
    x: 40, y: 40, width: 260, height: 80,
    text: "Assinado digitalmente por {{signer}}\nCPF {{cpf}}\nData: {{date}}",
    imagePath: '/var/app/assets/logo-carimbo.png',   // PNG ou JPEG, até 2 MB; vai ao fundo do retângulo
    fontSize: 9, imageOpacity: 0.35, border: true,
);

$p = $api->prepare($token, $certificadoDerBase64, visual: $visual);                     // o mesmo carimbo em todos os documentos
$p = $api->prepare($token, $certificadoDerBase64, visualPerDocument: [$v0, null, $v2]); // lote: um por documento; null = invisível
const resultado = await client.signPades({
  pdf, signer, signaturePolicyId: "pades-icpbrasil-ad-rb", securityContextId: "icp-brasil",
  visualRepresentation: {
    page: "last",
    rect: { x: 40, y: 40, width: 260, height: 80 },
    text: "Assinado digitalmente por {{signer}}\nCPF {{cpf}}\nData: {{date}}",
    image: bytesDoPng,   // opcional: PNG ou JPEG, até 2 MB
    fontSize: 9, border: true,
  },
});

Campos#

Campo Regra
page 1, 2… ou "last". Página inexistente: 400.
retângulo (x, y, width, height; em JavaScript, dentro de rect) Mínimo de 20 x 10. Precisa caber na página: a mensagem de erro informa o tamanho da página e o que foi pedido.
text Até 2000 caracteres. Aceita os marcadores abaixo. Quebra de linha automática; se não couber na altura, 400 dizendo quantas linhas faltam. null usa o texto padrão; "" mostra só a imagem.
image PNG ou JPEG, até 2 MB e 12 megapixels. Validada de verdade (arquivo corrompido: 400). No cliente PHP: imagePath ou imageBytes; em JavaScript: image. Aceita data URL.
fontSize De 5 a 48 (padrão 9). A fonte é embutida (DejaVu Sans): acentos e símbolos latinos funcionam.
fontColor #RRGGBB ou #RGB (padrão preto).
textAlign, textVerticalAlign left/center/right (padrão left) e top/middle/bottom (padrão middle).
includeSigningTime false omite a linha "Data: …" do texto padrão. Com text próprio, simplesmente não escreva {{date}}.
autoFontSize true: o texto que não cabe reduz o corpo (até 5 pt) em vez de dar 400.
imageOpacity, border Opacidade da imagem de fundo e borda do retângulo.
imagePlacement Onde a imagem fica (veja abaixo).

Marcadores do texto#

Marcador Valor
{{signer}} Nome do titular (sem o :CPF do nome do certificado).
{{date}} Data e hora em UTC, do momento do preparo.
{{issuer}} AC emissora.
{{cpf}}, {{cnpj}} Do certificado; vazios se ele não tiver.
{{company}} Razão social do e-CNPJ; vazio nos demais certificados.

Qualquer outro {{...}} é recusado.

Imagem alinhada em um canto, com o texto ao lado#

$visual = Client::visualRepresentation(1, 40, 700, 300, 90,
    "Assinado digitalmente por\n{{signer}}\nCPF {{cpf}}\nData: {{date}}", imageBytes: $seloPng, fontSize: 9,
    extra: ['imagePlacement' => ['horizontal' => 'right', 'vertical' => 'top', 'width' => 48, 'height' => 48, 'margin' => 3, 'textFlow' => 'beside']]);
imagePlacement Efeito
horizontal (left/center/right) e vertical (top/middle/bottom) Canto ou centro. Padrão: centro.
width e height (pontos) ou scale (0 a 1) Tamanho máximo, mantendo a proporção. width e height mandam sobre scale.
margin Pontos entre a imagem e a borda do retângulo.
textFlow overlay (padrão): o texto fica por cima da imagem. beside: o texto usa só o espaço que sobra ao lado (exige left ou right).

Sem imagePlacement, a imagem fica centralizada, no tamanho máximo, atrás do texto.

Por que o texto "não cabe" e como evitar#

A fonte é a DejaVu Sans, mais larga que a Helvetica ou a Arial. A largura média de um caractere, em múltiplos do corpo, é de cerca de 0,52 para minúsculas, 0,58 para dígitos e 0,64 para MAIÚSCULAS (os nomes nos certificados ICP-Brasil vêm em maiúsculas). A entrelinha é 1,25 vezes o corpo.

Caracteres por linha ≈ (largura − 6) / (corpo × fator). Com corpo 9 e 243 pt de largura, cabem cerca de 49 minúsculas ou 40 MAIÚSCULAS por linha. Para resolver: aumente o retângulo, reduza o fontSize, encurte o texto, ou use autoFontSize: true (o servidor reduz o corpo até caber; se nem 5 pt couber, responde 400 com a conta).

Lotes e páginas de tamanhos diferentes#

Calcule a posição por documento (o seu servidor sabe o tamanho de cada PDF) e use visualPerDocument. Em JavaScript, é documents[i].visualRepresentation. Com páginas rotacionadas (/Rotate), o retângulo continua sendo dado no espaço do PDF sem rotação, e o carimbo sai de pé.

Erros#

Todas as validações do carimbo respondem 400 invalid_visual_representation, e a sessão continua aberta: corrija e chame o prepare de novo. Em lote, a mensagem começa com documento N:, em que N é o índice do documento a partir de 0.

Com vários signatários, cada um envia o seu prepare com a sua posição: veja Vários signatários.

ShieldSign PKI · Shield Certificadora · contato@shieldcertificadora.com.br · Privacidade