Hiperlinks de PDF são anotações de URI: um retângulo cobrindo alguma área da página que, quando clicado, diz ao visualizador para abrir uma URL. A anotação e o texto sob ela são objetos completamente independentes. O PrintHyperlink do HotPDF agrupa ambos em uma chamada, desenhando o texto e calculando o retângulo de anotação a partir das métricas de texto renderizadas. Essa conveniência esconde um detalhe que vale a pena entender antes de escrever o código de produção. Também não é a história toda: o AddURILink coloca uma área clicável sobre o conteúdo que você mesmo desenhou, e o AddGoToLink lida com a navegação interna — ambos abordados abaixo
Como o PrintHyperlink funciona
O PrintHyperlink reside no THPDFPage e recebe quatro argumentos: as coordenadas X e Y (em pontos, origem inferior esquerda, Y aumentando para cima), a string de rótulo para desenhar e o destino da URL. Internamente ele chama TextOut na cor atual do hiperlink, e então calcula imediatamente o retângulo da anotação a partir de TextWidth e TextHeight nas métricas da fonte atuais. Isso significa que a fonte e o tamanho devem ser definidos antes da chamada, e eles não devem mudar entre o desenho do rótulo e a colocação da anotação, pois ambos são resolvidos na mesma chamada
A cor padrão é clBlue. O SetRGBHyperlinkColor a altera apenas para chamadas subsequentes; ele não atualiza retroativamente anotações já escritas. Se você precisar de cores diferentes para grupos de links diferentes na mesma página, chame o SetRGBHyperlinkColor antes de cada grupo e o redefina em seguida
Aqui está um documento mínimo que escreve três links com duas cores diferentes:
__CODE_BLOCK_A armadilha das coordenadas
O HotPDF usa uma origem no canto inferior esquerdo com o Y crescendo para cima, em pontos (1/72 polegadas). Uma página A4 tem 595 x 842 pt; uma página Carta tem 612 x 792 pt. O Y=750 fica próximo ao topo de uma página A4, e o Y=50 ficaria próximo à margem inferior. Qualquer pessoa que venha de gráficos de ecrã ou de HTML assume o oposto e coloca a primeira linha de link direto fora da área visível
O retângulo de anotação que o PrintHyperlink calcula usa o mesmo sistema de coordenadas. Se mais tarde você rotacionar a página, escalá-la ou alterar o tamanho da página sem recalcular seus valores de X/Y, o texto visível e o retângulo clicável se afastarão. O link "funciona" no sentido de que clicar em algum lugar perto do texto aciona a URL, mas a zona de acesso não corresponde mais ao que o leitor vê. Faça o teste com o tamanho da página e o nível de zoom reais que você entrega, não apenas na máquina de desenvolvimento a 100%
Um caso onde o desvio é garantido: se você chamar o PrintHyperlink com as coordenadas apropriadas para uma página A4 e então mudar para uma página de formato estreito personalizado sem ajustar os valores de X/Y, a anotação pode acabar totalmente fora da página. O objeto da anotação ainda é escrito no PDF; a maioria dos visualizadores o recorta silenciosamente, portanto o link simplesmente desaparece sem nenhum erro
Texto do rótulo versus destino da URL
Os argumentos Text e Link são independentes. Você pode desenhar "Baixar o PDF da fatura" enquanto o destino é uma URL HTTPS totalmente qualificada com parâmetros de consulta. Essa separação é intencional; o rótulo visível deve ser legível por humanos e a URL pode ser longa ou gerada dinamicamente
O que gera problemas é quando o rótulo é a própria URL original, especialmente uma longa. Se a URL quebrar visualmente em duas linhas, mas o retângulo de anotação tiver sido calculado para uma string de uma única linha, apenas a primeira linha será clicável. O PrintHyperlink não trata o fluxo de múltiplas linhas; mantenha o rótulo curto o suficiente para caber em uma linha com o tamanho de fonte e a largura da página atuais, use um rótulo curto e descritivo com a URL completa como o destino, ou aplique a solução alternativa por linha mostrada na próxima seção
Para os documentos que serão arquivados ou distribuídos sem uma ligação de internet ativa, considere também se a própria URL deve aparecer de forma impressa em algum lugar no corpo do documento, não apenas como um metadado de anotação. Um leitor que imprime o PDF em papel não obtém nada de uma anotação de URI
Contornando a limitação de várias linhas
Quando um rótulo de link genuinamente tem que se estender por mais de uma linha — uma URL longa impressa textualmente, ou uma frase com quebra que deva ser clicável de ponta a ponta — a solução é parar de tratá-lo como um link e tratá-lo como um link por linha. Cada chamada de PrintHyperlink calcula o seu retângulo a partir do texto que ele desenha, então várias chamadas que compartilham o mesmo destino de Link produzem várias anotações dimensionadas corretamente onde todas abrem a mesma URL. O leitor não consegue perceber a diferença; cada linha responde a um clique
A divisão da string é responsabilidade sua: quebre-a nas mesmas posições onde ela faria a quebra visual na fonte e na largura da coluna atuais, usando TextWidth para testar cada linha candidata. A alternativa é você mesmo desenhar o texto com quebra por meio de chamadas puras de TextOut e então colocar um retângulo AddURILink sobre cada linha — que é a melhor rota quando o texto já é produzido por sua própria lógica de quebra de palavra, o que nos leva a essa função
AddURILink: áreas clicáveis sobre qualquer coisa que você tenha desenhado
O PrintHyperlink é um invólucro de conveniência: ele desenha seu próprio rótulo e deriva o retângulo a partir das métricas desse rótulo. O AddURILink é a metade de nível mais baixo exposta diretamente:
Ele escreve apenas a anotação — nenhum texto é desenhado e as cores não mudam. O Rectangle é interpretado no mesmo espaço de coordenadas que as suas chamadas de desenho, portanto você pode reutilizar os exatos valores X/Y que você passou para o TextOut ou uma chamada de imagem. Isso faz com que essa seja a ferramenta certa sempre que o conteúdo visível já existir: um hotspot de imagem, uma célula de tabela, um bloco de texto desenhado anteriormente, ou uma linha de um parágrafo quebrado como na solução alternativa acima. A anotação carrega uma borda de largura zero, portanto nada que seja visível muda; a região clicável é exatamente o retângulo que você especificar
A função retorna o dicionário de anotação como um THPDFDictionaryObject. A maioria dos chamadores descarta o resultado, mas mantê-lo permite que você ajuste as entradas da anotação antes que o documento seja escrito
Dois detalhes de conformidade são incorporados. Nos modos PDF/A, o sinalizador de impressão da anotação é definido como esses padrões exigem. Sob PDFUACompliance, o parâmetro Description deve ser uma string que não esteja vazia — ele se torna a entrada /Contents da anotação, que é o que a tecnologia assistiva anuncia para o link — e a chamada lança uma exceção em vez de emitir silenciosamente um ficheiro não conforme. O PrintHyperlink é anterior a essa regra e não anexa nenhuma descrição; portanto, para saídas PDF/UA, desenhe o rótulo com TextOut e coloque a anotação com AddURILink mais uma descrição que tenha significado
A regra de decisão é simples: use PrintHyperlink quando o link for um texto curto que você ainda não desenhou; use AddURILink quando a região clicável for definida pelo conteúdo que você mesmo desenha ou mede
Navegação interna com o AddGoToLink
As URLs externas são apenas a metade do que as anotações de link fazem. A outra metade é a navegação dentro do documento — um índice que salta para capítulos, referências cruzadas entre as seções. O HotPDF expõe isso por meio de AddGoToLink:
Vale a pena declarar três semânticas com precisão, uma vez que nenhuma é adivinhável a partir da assinatura. O TargetPageIndex é baseado em zero: a primeira página do documento é a página 0, correspondendo ao CurrentPageNumber. A página de destino já deve existir quando você faz a chamada; se o índice estiver fora do intervalo, o procedimento retorna sem adicionar uma anotação — nenhuma exceção, nenhum link, nenhum aviso. Para um índice que aponte para a frente, crie todas as páginas primeiro, depois retorne e adicione os links
O YPos seleciona a posição vertical na página de destino, no mesmo espaço de coordenadas que as suas chamadas de desenho. O padrão de -1 (qualquer valor negativo) grava uma coordenada de destino nula, dizendo ao visualizador para manter a sua posição vertical atual quando ele pousar na página de destino. Passe um valor não negativo e a visualização rola para que a posição fique no topo da janela — use a coordenada Y do cabeçalho ao qual você está se vinculando. O zoom sempre é mantido inalterado. Assim como com o AddURILink, o Description não deve estar vazio sob o PDFUACompliance e se torna o texto alternativo do link
Cada entrada obtém um retângulo mais largo do que o texto para que a linha inteira responda ao ponteiro, e todos os links chegam com o cabeçalho do capítulo (desenhado em Y=780) no topo da janela. Se mais tarde você inserir uma página antes dos capítulos, cada TargetPageIndex muda em um; calcule os índices a partir do seu loop de criação de páginas, em vez de codificá-los manualmente
Um exemplo completo de geração de documento
O padrão abaixo mostra um cenário mais realista: gerar um relatório curto com uma seção de cabeçalho, corpo de texto e uma linha de rodapé com links, tudo a partir do código, em vez de um formulário com campos TEdit:
Observe que o SetFont é chamado antes de cada grupo de chamadas de texto. A fonte não persiste no AddPage, e se você esquecer de configurá-la antes do PrintHyperlink em uma nova página, o retângulo de anotação será calculado em relação às métricas padrão da página, o que pode diferir do que você espera
Onde o tratamento de anotações varia entre os visualizadores
As anotações de URI de PDF estão definidas na ISO 32000-1 §12.6.4.7, e todo visualizador em conformidade deve segui-las. Na prática, alguns comportamentos diferem de acordo com o visualizador. O Adobe Acrobat exibe um prompt de segurança no primeiro clique para URLs que não constam da lista de domínios confiáveis; muitos navegadores e leitores leves não fazem isso. Alguns visualizadores de PDF corporativos em ambientes bloqueados desabilitam as anotações de URI inteiramente por política; portanto, um clique não faz nada, sem erro visível. Os aplicações de PDF em dispositivos móveis variam em abrir links na visualização da web do aplicação ou em transferi-los para o navegador do sistema
Nenhum desses são bugs que você pode corrigir do lado da geração; são decisões de políticas do visualizador. O que você pode fazer é escrever rótulos de link que tornem a URL visível também no corpo do documento; assim, um leitor num ambiente restrito ainda poderá copiar o endereço manualmente. A anotação é a conveniência; o texto é a contingência
Um detalhe a mais que vale a pena conhecer: as anotações URI de PDF não carregam nenhum sublinhado visual por padrão. O sublinhado que você vê na maioria dos visualizadores é desenhado pelo próprio visualizador com base no tipo de anotação, não por um glifo no fluxo de conteúdo. Se você precisa de um sublinhado físico que sobreviva à impressão para um renderizador não interativo ou para uma conversão de PDF para imagem, desenhe-o explicitamente com LineTo e Stroke no deslocamento Y apropriado, abaixo da linha de base do texto. Trata-se de uma operação de desenho separada, não de algo que o PrintHyperlink controla por você
A API de hiperlinks mostrada aqui faz parte do Componente HotPDF para Delphi e C++Builder