Articolo tecnico

Collegamenti ipertestuali in HotPDF Delphi: consigli per le annotazioni PrintHyperlink

I collegamenti ipertestuali PDF sono annotazioni URI: un rettangolo che copre un'area della pagina e che, se cliccato, indica al visualizzatore di aprire un URL. L'annotazione e il testo sottostante sono oggetti completamente indipendenti. Il metodo PrintHyperlink di HotPDF racchiude entrambi in un'unica chiamata, disegnando il testo e calcolando il rettangolo dell'annotazione in base alle metriche del testo renderizzato. Questa comodità nasconde un dettaglio che vale la pena comprendere prima di scrivere codice di produzione.

Come funziona PrintHyperlink

PrintHyperlink appartiene a THPDFPage e accetta quattro argomenti: le coordinate X e Y (in punti, con origine in basso a sinistra e Y crescente verso l'alto), la stringa dell'etichetta da disegnare e l'URL di destinazione. Internamente chiama TextOut con il colore corrente del collegamento ipertestuale, quindi calcola immediatamente il rettangolo dell'annotazione da TextWidth e TextHeight in base alle metriche del font corrente. Ciò significa che il font e la dimensione devono essere impostati prima della chiamata e non devono cambiare tra il disegno dell'etichetta e il posizionamento dell'annotazione, poiché entrambi vengono risolti nella stessa chiamata.

Il colore predefinito è clBlue. SetRGBHyperlinkColor lo modifica solo per le chiamate successive; non aggiorna retroattivamente le annotazioni già scritte. Se hai bisogno di colori diversi per gruppi di collegamenti diversi sulla stessa pagina, chiama SetRGBHyperlinkColor prima di ogni gruppo e ripristinalo successivamente.

Ecco un documento minimo che scrive tre collegamenti con due colori diversi:

procedure CreateLinkedReport(const FileName: string);
var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := FileName;
    Pdf.BeginDoc;

    Pdf.CurrentPage.SetFont('Arial', [], 11);

    // Default blue for informational links
    Pdf.CurrentPage.TextOut(50, 750, 0, 'Reference links:');
    Pdf.CurrentPage.PrintHyperlink(50, 720, 'Product page', 'https://www.loslab.com/en-us/pdf-library/delphi-pdf-component.html');
    Pdf.CurrentPage.PrintHyperlink(50, 695, 'Online manual', 'https://www.loslab.com/en-us/pdf-library/documentation.html');

    // Red for the action link
    Pdf.CurrentPage.SetRGBHyperlinkColor(clRed);
    Pdf.CurrentPage.PrintHyperlink(50, 660, 'Purchase license', 'https://www.loslab.com/en-us/order/');
    Pdf.CurrentPage.SetRGBHyperlinkColor(clBlue);  // restore default

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

La trappola delle coordinate

HotPDF utilizza un'origine in basso a sinistra con Y che cresce verso l'alto, espressa in punti (1/72 di pollice). Una pagina A4 misura 595 x 842 pt; una pagina US Letter misura 612 x 792 pt. Y=750 si trova vicino alla parte superiore di una pagina A4, mentre Y=50 si trova vicino al margine inferiore. Chiunque provenga dalla grafica su schermo o dall'HTML tende a ipotizzare il contrario, posizionando la prima riga di collegamento direttamente al di fuori dell'area visibile.

Il rettangolo dell'annotazione calcolato da PrintHyperlink utilizza lo stesso sistema di coordinate. Se successivamente si ruota la pagina, la si scala o si modifica la dimensione della pagina senza ricalcolare i valori X/Y, il testo visibile e il rettangolo cliccabile si allontaneranno. Il collegamento "funziona" nel senso che cliccando in un punto vicino al testo si attiva l'URL, ma la zona attiva non corrisponde più a ciò che il lettore vede. Effettua i test sulle dimensioni reali della pagina e sul livello di zoom effettivo di distribuzione, non solo sulla macchina di sviluppo al 100%.

Un caso in cui lo scostamento è garantito: se si chiama PrintHyperlink con coordinate adeguate per una pagina A4 e poi si passa a una pagina con formato personalizzato stretto senza regolare i valori X/Y, l'annotazione può finire completamente fuori dalla pagina. L'oggetto annotazione viene comunque scritto nel PDF; la maggior parte dei visualizzatori lo ritaglia silenziosamente, quindi il collegamento semplicemente scompare senza generare alcun errore.

Testo dell'etichetta rispetto all'URL di destinazione

Gli argomenti Text e Link sono indipendenti. È possibile visualizzare "Download invoice PDF" mentre la destinazione è un URL HTTPS completo di parametri di query. Questa separazione è intenzionale; l'etichetta visibile dovrebbe essere facilmente leggibile per l'utente, mentre l'URL può essere lungo o generato dinamicamente.

Ciò che crea problemi è quando l'etichetta coincide con l'URL non formattato, specialmente se lungo. Se l'URL va a capo visivamente su due righe ma il rettangolo dell'annotazione è stato calcolato per una stringa a riga singola, solo la prima riga sarà cliccabile. PrintHyperlink non gestisce il flusso multilinea; mantieni l'etichetta abbastanza corta da adattarsi a una sola riga con la dimensione del font e la larghezza della pagina correnti, oppure usa un'etichetta descrittiva breve con l'URL completo come destinazione.

Per i documenti che verranno archiviati o distribuiti senza una connessione Internet attiva, valuta anche se l'URL stesso debba apparire in forma stampata in qualche parte del corpo del documento, e non solo come metadato dell'annotazione. Un lettore che stampa il PDF su carta non trarrà alcun vantaggio da un'annotazione URI.

Un esempio completo di generazione del documento

Il pattern seguente mostra uno scenario più realistico: la generazione di un breve report con una sezione di intestazione, il corpo del testo e una riga a piè di pagina con i collegamenti, il tutto generato da codice anziché da un modulo con campi TEdit:

procedure GenerateProductSheet(
  const FileName, ProductName, ProductURL, SupportURL: string);
var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := FileName;
    Pdf.Compression := cmFlateDecode;
    Pdf.BeginDoc;

    // Header
    Pdf.CurrentPage.SetFont('Arial', [fsBold], 16);
    Pdf.CurrentPage.TextOut(50, 750, 0, WideString(ProductName));

    // Body paragraph placeholder
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 710, 0, 'See the links below for full documentation.');

    // Footer links
    Pdf.CurrentPage.SetFont('Arial', [], 10);
    Pdf.CurrentPage.TextOut(50, 80, 0, 'Links:');
    Pdf.CurrentPage.PrintHyperlink(50, 60, 'Product page', ProductURL);
    Pdf.CurrentPage.PrintHyperlink(200, 60, 'Support', SupportURL);

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Nota che SetFont viene chiamato prima di ogni gruppo di chiamate di testo. Il font non persiste dopo la chiamata a AddPage e, se dimentichi di impostarlo prima di PrintHyperlink su una nuova pagina, il rettangolo dell'annotazione verrà calcolato in base alle metriche predefinite della pagina, che potrebbero differire da quelle previste.

Differenze nella gestione delle annotazioni tra i visualizzatori

Le annotazioni URI PDF sono definite nello standard ISO 32000-1 §12.6.4.7 e ogni visualizzatore conforme dovrebbe seguirle. Nella pratica, alcuni comportamenti variano a seconda del programma utilizzato. Adobe Acrobat mostra un avviso di sicurezza al primo clic per gli URL non inclusi nell'elenco dei domini attendibili; molti browser e lettori leggeri non lo fanno. Alcuni visualizzatori PDF aziendali in ambienti controllati disabilitano completamente le annotazioni URI per criteri di sicurezza, quindi il clic non produce alcun effetto, senza mostrare errori visibili. Le applicazioni PDF per dispositivi mobili variano a seconda che aprano i collegamenti all'interno di una web view integrata o li passino al browser di sistema.

Nessuno di questi è un bug che si può correggere in fase di generazione; si tratta di scelte legate ai criteri dei singoli visualizzatori. Ciò che puoi fare è scrivere etichette di collegamento che rendano l'URL visibile anche nel corpo del documento, in modo che un lettore in un ambiente con restrizioni possa comunque copiare l'indirizzo manualmente. L'annotazione rappresenta la comodità; il testo è il meccanismo di fallback.

Un ulteriore dettaglio utile da sapere: le annotazioni URI PDF non includono alcuna sottolineatura visiva per impostazione predefinita. La sottolineatura mostrata nella maggior parte dei visualizzatori viene disegnata dal lettore stesso in base al tipo di annotazione, e non da un glifo nel flusso di contenuto. Se hai bisogno di una sottolineatura fisica che rimanga visibile in caso di stampa su un visualizzatore non interattivo o di conversione da PDF a immagine, disegnala esplicitamente con LineTo e Stroke all'offset Y appropriato al di sotto della linea di base del testo. Si tratta di un'operazione di disegno separata, non gestita automaticamente da PrintHyperlink.

L'API per i collegamenti ipertestuali mostrata in questo articolo fa parte di HotPDF Component per Delphi e C++Builder.