Los hipervínculos en PDF son anotaciones URI: un rectángulo que cubre un área de la página y que, al hacer clic, indica al visor que abra una URL. La anotación y el texto bajo ella son objetos completamente independientes. PrintHyperlink de HotPDF agrupa ambos en una única llamada, dibujando el texto y calculando el rectángulo de anotación a partir de las métricas del texto renderizado. Esa comodidad oculta un detalle que conviene entender antes de escribir código de producción.
Cómo funciona PrintHyperlink
PrintHyperlink reside en THPDFPage y acepta cuatro argumentos: coordenadas X e Y (en puntos, origen en la esquina inferior izquierda, Y creciendo hacia arriba), la cadena de etiqueta a dibujar y la URL de destino. Internamente llama a TextOut con el color de hipervínculo actual y, a continuación, calcula inmediatamente el rectángulo de anotación a partir de TextWidth y TextHeight con las métricas de la fuente actual. Eso significa que la fuente y el tamaño deben establecerse antes de la llamada, y no deben cambiar entre el dibujo de la etiqueta y la colocación de la anotación, porque ambos se resuelven en la misma llamada.
El color predeterminado es clBlue. SetRGBHyperlinkColor solo lo cambia para las llamadas posteriores; no actualiza retroactivamente las anotaciones ya escritas. Si necesitas colores diferentes para distintos grupos de enlaces en la misma página, llama a SetRGBHyperlinkColor antes de cada grupo y restablécelo después.
A continuación se muestra un documento mínimo que escribe tres enlaces con dos colores distintos:
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 trampa de las coordenadas
HotPDF usa un origen en la esquina inferior izquierda con Y creciendo hacia arriba, en puntos (1/72 de pulgada). Una página A4 es 595 x 842 pt; una US Letter es 612 x 792 pt. Y=750 se sitúa cerca de la parte superior de una página A4, y Y=50 quedaría cerca del margen inferior. Cualquiera que venga de gráficos de pantalla o HTML asume lo contrario y coloca la primera línea de enlace directamente fuera del área visible.
El rectángulo de anotación que calcula PrintHyperlink usa el mismo sistema de coordenadas. Si luego rotas la página, la escalas o cambias el tamaño sin recalcular los valores X/Y, el texto visible y el rectángulo clicable se separarán. El enlace «funciona» en el sentido de que hacer clic en algún lugar cerca del texto activa la URL, pero la zona activa ya no coincide con lo que ve el lector. Prueba con el tamaño de página y el nivel de zoom reales que vayas a distribuir, no solo en la máquina de desarrollo al 100%.
Hay un caso en que la separación está garantizada: si llamas a PrintHyperlink con coordenadas apropiadas para una página A4 y luego cambias a una página de formato estrecho personalizado sin ajustar los valores X/Y, la anotación puede quedar completamente fuera de la página. El objeto de anotación sigue escribiéndose en el PDF; la mayoría de los visores lo recortan en silencio, de modo que el enlace simplemente desaparece sin ningún error.
Texto de etiqueta frente a URL de destino
Los argumentos Text y Link son independientes. Puedes dibujar «Descargar factura PDF» mientras el destino es una URL HTTPS completa con parámetros de consulta. Esa separación es deliberada; la etiqueta visible debe ser legible por personas y la URL puede ser larga o generarse dinámicamente.
Lo que crea problemas es cuando la etiqueta es la propia URL en bruto, especialmente si es larga. Si la URL se ajusta visualmente a dos líneas pero el rectángulo de anotación se calculó para una cadena de una sola línea, solo la primera línea es clicable. PrintHyperlink no gestiona el flujo multilínea; mantén la etiqueta lo suficientemente corta para que quepa en una línea con el tamaño de fuente y el ancho de página actuales, o usa una etiqueta descriptiva breve con la URL completa como destino.
Para documentos que se vayan a archivar o distribuir sin conexión a internet activa, considera también si la propia URL debería aparecer impresa en algún lugar del cuerpo del documento, no solo como metadatos de anotación. Un lector que imprima el PDF en papel no obtiene nada de una anotación URI.
Un ejemplo completo de generación de documentos
El patrón siguiente muestra un escenario más realista: generar un informe breve con una sección de encabezado, texto de cuerpo y una fila de pie de página con enlaces, todo desde código en lugar de desde un formulario con campos 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;
Observa que SetFont se llama antes de cada grupo de llamadas de texto. La fuente no persiste tras AddPage, y si olvidas establecerla antes de PrintHyperlink en una nueva página, el rectángulo de anotación se calculará contra las métricas predeterminadas de la página, que pueden diferir de lo esperado.
Variaciones en el tratamiento de anotaciones según el visor
Las anotaciones URI de PDF están definidas en ISO 32000-1 §12.6.4.7, y todo visor conforme debería seguirlas. En la práctica, algunos comportamientos varían según el visor. Adobe Acrobat muestra un aviso de seguridad en el primer clic para URLs que no están en la lista de dominios de confianza; muchos navegadores y lectores ligeros no lo hacen. Algunos visores de PDF empresariales en entornos bloqueados deshabilitan las anotaciones URI completamente por política, de modo que un clic no hace nada, sin ningún error visible. Las aplicaciones de PDF para móviles varían en si abren los enlaces dentro de la vista web de la aplicación o los transfieren al navegador del sistema.
Ninguno de estos es un error que puedas corregir desde el lado de la generación; son decisiones de política del visor. Lo que puedes hacer es escribir etiquetas de enlace que hagan visible la URL también en el cuerpo del documento, para que un lector en un entorno restringido pueda copiar la dirección manualmente. La anotación es la comodidad; el texto es la alternativa.
Un detalle más que merece conocerse: las anotaciones URI de PDF no llevan ningún subrayado visual por defecto. El subrayado que se ve en la mayoría de los visores lo dibuja el propio visor basándose en el tipo de anotación, no un glifo en el flujo de contenido. Si necesitas un subrayado físico que sobreviva a la impresión en un renderizador no interactivo o a la conversión de PDF a imagen, dibújalo explícitamente con LineTo y Stroke al desplazamiento Y adecuado por debajo de la línea base del texto. Es una operación de dibujo separada, no algo que PrintHyperlink gestione por ti.
La API de hipervínculos mostrada aquí forma parte del HotPDF Component para Delphi y C++Builder.