Uma anotação não é conteúdo da página. Quando você chama TextOut ou desenha um retângulo, as marcas tornam-se parte do fluxo de conteúdo da página, integradas aos bytes que um renderizador pinta. Uma anotação é um dicionário separado anexado à página por meio de seu array /Annots, com seu próprio retângulo, sua própria aparência e seu próprio ciclo de vida. Um leitor pode abri-la, movê-la, ocultá-la ou removê-la sem tocar em um único glifo da página subjacente. Essa separação é o único motivo pelo qual as anotações existem, e também é a origem de duas coisas que surpreendem as pessoas a princípio: onde uma anotação vai parar, e como ela se parece assim que um visualizador específico a obtém
O HotPDF expõe os subtipos de anotação da norma ISO 32000 por meio de uma família de chamadas AddXxxAnnotation no objeto da página. Todos eles compartilham a mesma forma: um retângulo que fixa a anotação na página no espaço do usuário do PDF, algum payload (texto, nome de carimbo, um par de pontos) e uma cor. Se você acertar o retângulo, a maior parte do trabalho estará concluída. O restante é saber quais subtipos carregam sua própria aparência e quais dependem do visualizador para desenhá-los

O retângulo é a anotação, não o texto
Toda chamada de anotação requer um TRect, e esse retângulo significa algo diferente das coordenadas que você passa para TextOut. Para uma nota de texto, é a área clicável (hotspot), a pequena região onde fica o ícone da nota e onde um clique abre o comentário. Para um quadrado ou caixa de texto livre, é a extensão visível da marcação. Para um carimbo, é a caixa para a qual a arte do carimbo é redimensionada. Os números são pontos no espaço de usuário do PDF, medidos a partir do canto inferior esquerdo da página com o Y aumentando para cima, a mesma convenção que o restante do HotPDF utiliza
Uma nota de texto é o subtipo mais leve. Você informa o texto do corpo, um retângulo para o ícone, uma flag (sinalizador) indicando se ele abre por padrão, um nome de ícone e uma cor
Pdf.CurrentPage.AddTextAnnotation(
'Reviewer: confirm the totals on this line before sign-off.',
Rect(120, 700, 140, 720), // icon hotspot, ~20pt square
False, // closed until the reader clicks it
taComment, // bubble icon
clBlue);
O retângulo aqui é deliberadamente pequeno, com cerca de vinte pontos de cada lado, porque uma nota de texto é apenas um ícone até que alguém clique nela. Faça o retângulo grande e você não obterá uma nota grande; você obterá um alvo de clique gigantesco com o ícone preso a um canto. A flag Open controla se o pop-up está aparecendo quando o documento carrega. Defina um punhado de notas como True e elas ficarão empilhadas umas sobre as outras e sobre o conteúdo, portanto, reserve isso para aquela única nota que você realmente deseja que o leitor veja imediatamente
O nome do ícone vem de THPDFTextAnnotationType, que mapeia para os ícones de nota padrão: taComment, taKey, taNote, taHelp, taParagraph, taNewParagraph e taInsert. O ícone é a única coisa que o tipo altera. Ele não altera o comportamento e é importante saber que nem todo visualizador desenha todos os sete; os mais seguros entre os leitores antigos e novos são taComment, taNote e taHelp
O texto livre escreve na página, mas permanece como uma anotação
Uma anotação de texto livre parece conteúdo porque o texto é visível sem um clique, posicionado em seu retângulo como uma legenda. Ainda é uma anotação, com toda a capacidade de separação que isso implica, o que é exatamente o que você deseja para um carimbo de revisão ou um rótulo de rascunho que alguém deva poder remover posteriormente. A assinatura substitui o ícone e a flag 'open' por um valor de justificação
Pdf.CurrentPage.AddFreeTextAnnotation(
'DRAFT - not for distribution',
Rect(200, 210, 400, 235), // the box the text is laid into
ftCenter, // ftLeftJust / ftCenter / ftRightJust
clRed);
Aqui, o retângulo importa mais do que para uma nota de texto, porque o texto sofre quebra e se alinha dentro dele. Defina a caixa muito curta e o texto será cortado na borda inferior; muito estreita e ele fará quebras onde você não pretendia. A justificação vem de THPDFFreeTextAnnotationJust e possui apenas três valores. Como o texto livre é uma anotação de marcação, um leitor que abrir o arquivo em um editor pode selecioná-lo, movê-lo ou excluí-lo como uma unidade, e é essa diferença que decide se você usará o texto livre ou apenas desenhará as palavras com TextOut. Se o rótulo tiver que ser permanente, desenhe-o. Se for redatorial e destinado a ser removido, transforme-o em uma anotação
Marcações geométricas e de linhas para apontar coisas
Quadrados, círculos e linhas são a marcação que você utiliza para apontar para uma região em vez de descrevê-la com palavras. O AddCircleSquareAnnotation abrange os dois formatos de caixa por meio de um THPDFCSAnnotationType sendo csCircle ou csSquare, com o retângulo fornecendo os limites da forma
// A box drawn around a figure that needs attention
Pdf.CurrentPage.AddCircleSquareAnnotation(
'Check this region against the source data',
Rect(50, 300, 120, 360),
csSquare,
clGreen);
// A line, given two points rather than a rectangle
var
StartPt, EndPt: THPDFCurrPoint;
begin
StartPt.X := 130; StartPt.Y := 360;
EndPt.X := 250; EndPt.Y := 320;
Pdf.CurrentPage.AddLineAnnotation(
'Points from the note to the figure',
StartPt, EndPt,
clBlue);
end;
Observe que a anotação de linha quebra o padrão do retângulo: ela recebe dois registros THPDFCurrPoint, um começo e um fim, porque uma linha é definida pelos seus pontos finais, e não por uma caixa delimitadora. A cor define o traçado. Se você quiser pontas de setas, o HotPDF tem sobrecargas do AddLineAnnotation que aceitam estilos de fim de linha, mas a forma simples com três argumentos desenha uma linha reta, que costuma ser o que uma chamada (callout) precisa
Os subtipos de marcação de texto atuam numa região que você já dispôs. AddHighlightAnnotation recebe um retângulo, conteúdo opcional e uma cor com padrão amarelo, e tinge a área da mesma forma que um marca-texto faria. O intuito é que ele fique sobre um texto real, portanto o retângulo deve corresponder aos limites das palavras que você desenhou, o que significa que geralmente você deve calculá-lo a partir das mesmas coordenadas que passou para TextOut, em vez de adivinhar
Carimbos dependem do visualizador para renderizá-los
A anotação de carimbo é a que tem maior probabilidade de parecer diferente de um leitor para outro, e vale a pena entender o motivo. AddStampAnnotation nomeia um carimbo padrão por meio de THPDFStampAnnotationType, com valores como satApproved, satConfidential, satFinal, satDraft e satForComment
Pdf.CurrentPage.AddStampAnnotation(
'Approved for release on review',
Rect(50, 400, 200, 440),
satApproved,
clGreen);
O nome do carimbo é um pedido. O PDF define o conjunto de nomes de carimbos padrão, mas não a arte por trás deles; assim, cada visualizador traz sua própria renderização de "APPROVED" ou "CONFIDENTIAL", e alguns não renderizam nada para nomes que não reconhecem. O retângulo controla a caixa em que a arte é redimensionada, e a cor é uma dica que o visualizador pode honrar ou não. Se um carimbo precisar ser idêntico em todos os lugares, o caminho confiável não é, de forma alguma, um carimbo padrão: desenhe a marca você mesmo com TextOut e as chamadas de desenho, ou posicione-o como uma anotação de texto livre cuja aparência você controla. Recorra ao carimbo padrão quando desejar a aparência familiar do visualizador e puder tolerar a variação
Os anexos de arquivos seguem a mesma forma de retângulo-mais-payload. AddFileAttachmentAnnotation recebe a descrição, o caminho do arquivo para incorporar, um retângulo para o ícone de clipe de papel e uma cor. O arquivo viaja dentro do PDF e o ícone é o puxador (alça) que o leitor usa para extraí-lo
Como as anotações diferem dos campos AcroForm
A confusão que custa mais tempo é tratar uma anotação como se fosse um campo de formulário. Ambos são anexados à página por meio de /Annots, e um campo de formulário é, de fato, um subtipo de anotação especial (um widget), razão pela qual eles parecem estar relacionados. Eles não são intercambiáveis. Um campo de formulário contém um valor, tem um nome, participa da ordem de tabulação (tab order) e pode ser enviado, redefinido ou receber scripts; você os cria com as chamadas AddTextField, AddCheckBox e AddPushButton, não com as chamadas de anotações desta página. Uma anotação de marcação contém um comentário ou uma forma geométrica, não possui valor a ser enviado e é a ferramenta incorreta quando se trata de coletar entrada de dados
O teste prático é simples. Se a intenção é que um usuário digite, escolha ou clique e que o documento se lembre disso, você precisa de um campo AcroForm. Se você for deixar uma nota, marcar uma região ou carimbar um status que acompanha o arquivo, mas que não é um dado, você quer uma anotação. Misturá-los produz documentos que parecem corretos e se comportam de maneira errada: um "campo" que ninguém pode preencher, ou um comentário que desaparece quando um formulário é redefinido. O lado interativo, com os tipos de campos, a validação e as ações de envio, é um assunto à parte, abordado no guia passo a passo de campos e ações de AcroForm
Montando uma página
As partes compõem da mesma forma que o resto do HotPDF. Defina as propriedades do documento, chame BeginDoc, desenhe o conteúdo da página que precisar com as chamadas de texto e gráficos, adicione anotações por cima e encerre com EndDoc. As anotações são anexadas a CurrentPage, portanto, após um AddPage, elas caem na nova página, e uma anotação que você pretendia que ficasse na página um, silenciosamente aparecerá na página dois se for adicionada após a quebra de página
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'annotated.pdf';
Pdf.Compression := cmFlateDecode;
Pdf.FontEmbedding := True;
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 740, 0, 'Quarterly figures, draft for review');
Pdf.CurrentPage.AddTextAnnotation(
'Confirm the totals before sign-off.',
Rect(50, 720, 70, 740), False, taComment, clBlue);
Pdf.CurrentPage.AddFreeTextAnnotation(
'DRAFT', Rect(450, 720, 540, 745), ftCenter, clRed);
Pdf.CurrentPage.AddStampAnnotation(
'For comment', Rect(50, 660, 180, 695), satForComment, clGreen);
Pdf.EndDoc;
finally
Pdf.Free;
end;
Um último reflexo que vale a pena desenvolver quando o resultado parecer errado: abra o arquivo em mais de um visualizador antes de decidir que o código está quebrado. Carimbos e os ícones de notas mais raros são os suspeitos comuns, e como a anotação é um pedido ao leitor e não pixels pintados, uma diferença entre o Acrobat e um visualizador leve muitas vezes é a especificação funcionando conforme foi projetada, não um bug em sua chamada
As chamadas de anotação mostradas aqui são parte do Componente HotPDF para Delphi e C++Builder