SignatureKit
Receitas

Posicionamento por âncora

Encontre âncoras de texto como assinatura, CPF ou CNPJ e transforme-as em retângulos de assinatura PDF.

Use findPdfTextAnchors quando o documento de negócio já nomeia a área de assinatura. Ele substitui scans com pdfjs-dist e matemática manual de transform por um matcher do pacote sobre text boxes do SignatureKit.

anchor-placement.ts
import { findPdfTextAnchors } from "@signature-kit/pdf/anchors"
import { type PdfSignaturePage, type PdfTextBox } from "@signature-kit/pdf/config"
import {
  liteParseWorkerBrowserLayer,
  parsePdfTextBoxesBrowser,
} from "@signature-kit/pdf/liteparse-browser"
import { prepareAndSignPdf } from "@signature-kit/pdf/workflow"
import { Effect, Layer } from "effect"

const pages: Array<PdfSignaturePage> = template.documents[0]?.pages ?? []
const extractedTextBoxes = await Effect.runPromise(
  parsePdfTextBoxesBrowser(pdf, pages.length).pipe(Effect.provide(liteParseWorkerBrowserLayer)),
)
const pageTextBoxes: Array<Array<PdfTextBox>> = extractedTextBoxes.map((page) =>
  Array.from(page),
)

const stampRects = await Effect.runPromise(
  findPdfTextAnchors({
    pages,
    textBoxes: pageTextBoxes,
    matchers: [
      { text: "assinatura:" },
      { digits: "12345678901" },      // CPF/CNPJ: compara só números
    ],
    stampSize: { width: 180, height: 54 },
    placement: "below",
    offset: 6,
  }),
)

const signedPdf = await Effect.runPromise(
  prepareAndSignPdf({
    pdf,
    pages,
    pageTextBoxes,
    stampRects,
    badge: {
      header: { text: "ASSINADO DIGITALMENTE" },
      rows: [[{ label: "Signatário", value: "Maria Souza" }]],
      footer: [{ text: "ICP-Brasil" }],
    },
    rubric: { initials: "MS" },
    signing: { policy: "pades-icp-brasil", name: "Maria Souza" },
  }).pipe(Effect.provide(Layer.merge(layer, liteParseWorkerBrowserLayer))),
)

digits normaliza o matcher e o texto do PDF para strings numéricas, então 123.456.789-01 e 12345678901 casam. Os retângulos retornados são limitados aos bounds da página.

A extração de texto no navegador vem de parsePdfTextBoxesBrowser e LiteParse WASM. Se seu runtime não carrega esse WASM, passe pages e textBoxes da sua própria extração e mantenha o posicionamento em findPdfTextAnchors.

Como está este guia?