Technisch artikel

HotPDF Delphi Hyperlinks: Tips voor PrintHyperlink-annotaties

PDF-hyperlinks zijn URI-annotaties: een rechthoek die een gedeelte van de pagina bestrijkt en, wanneer aangeklikt, de viewer instrueert een URL te openen. De annotatie en de onderliggende tekst zijn volledig onafhankelijke objecten. De PrintHyperlink-methode van HotPDF bundelt beide in één aanroep: hij tekent de tekst en berekent de annotatierechtoek op basis van de weergegeven tekstmetrieken. Dit gemak verbergt een detail dat het waard is te begrijpen voordat u productiecode schrijft.

Hoe PrintHyperlink werkt

PrintHyperlink behoort tot THPDFPage en accepteert vier argumenten: X- en Y-coördinaten (in punten, linksonder als oorsprong, Y stijgt omhoog), de labeltekst om te tekenen, en de URL als bestemming. Intern roept het TextOut aan in de huidige hyperlinkkleur en berekent vervolgens onmiddellijk de annotatierechtoek op basis van TextWidth en TextHeight bij de huidige lettertypemetrieken. Dat betekent dat lettertype en grootte vóór de aanroep moeten zijn ingesteld en niet mogen veranderen tussen het tekenen van het label en het plaatsen van de annotatie, omdat beide in dezelfde aanroep worden verwerkt.

De standaardkleur is clBlue. SetRGBHyperlinkColor wijzigt de kleur alleen voor volgende aanroepen; het werkt reeds geschreven annotaties niet achteraf bij. Als u op dezelfde pagina verschillende kleuren voor verschillende koppelingsgroepen nodig hebt, roept u SetRGBHyperlinkColor vóór elke groep aan en stelt u de kleur daarna terug in.

Hieronder staat een minimaal document dat drie koppelingen met twee verschillende kleuren schrijft:

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;

De coördinaatval

HotPDF gebruikt een linksonder-oorsprong waarbij Y omhoog groeit, in punten (1/72 inch). Een A4-pagina is 595 x 842 pt; een US Letter-pagina is 612 x 792 pt. Y=750 bevindt zich nabij de bovenkant van een A4-pagina, en Y=50 zou zich nabij de ondermarge bevinden. Wie gewend is aan schermgraphics of HTML gaat uit van het tegenovergestelde en plaatst de eerste koppelingsregel direct buiten het zichtbare gebied.

De annotatierechtoek die PrintHyperlink berekent, gebruikt hetzelfde coördinatensysteem. Als u de pagina achteraf roteert, schaalt of de paginagrootte wijzigt zonder de X/Y-waarden opnieuw te berekenen, zullen de zichtbare tekst en het klikbare rechthoek uit elkaar drijven. De koppeling "werkt" in de zin dat ergens in de buurt van de tekst klikken de URL activeert, maar de klikzone komt niet meer overeen met wat de lezer ziet. Test op de werkelijke paginagrootte en het zoomniveau dat u levert, niet alleen op de ontwikkelingsmachine op 100%.

Een geval waarbij de verschuiving gegarandeerd optreedt: als u PrintHyperlink aanroept met coördinaten die geschikt zijn voor een A4-pagina en vervolgens overschakelt naar een aangepaste smalformaatpagina zonder de X/Y-waarden aan te passen, kan de annotatie volledig buiten de pagina terechtkomen. Het annotatieobject wordt nog steeds in de PDF geschreven; de meeste viewers knippen het stilletjes af, zodat de koppeling eenvoudig verdwijnt zonder foutmelding.

Labeltekst versus URL-bestemming

De argumenten Text en Link zijn onafhankelijk van elkaar. U kunt "Download factuur PDF" weergeven terwijl de bestemming een volledig gekwalificeerde HTTPS-URL met queryparameters is. Die scheiding is opzettelijk: het zichtbare label moet leesbaar zijn voor mensen en de URL kan lang zijn of dynamisch worden gegenereerd.

Problemen ontstaan wanneer het label de onbewerkte URL zelf is, met name een lange. Als de URL visueel over twee regels loopt maar de annotatierechtoek is berekend voor een tekenreeks op één regel, is alleen de eerste regel klikbaar. PrintHyperlink verwerkt geen meervoudige regelafbreking; houd het label kort genoeg om op één regel te passen bij de huidige lettergrootte en paginabreedte, of gebruik een kort beschrijvend label met de volledige URL als bestemming.

Voor documenten die worden gearchiveerd of gedistribueerd zonder actieve internetverbinding, overweeg ook of de URL zelf ergens in de documenttekst in gedrukte vorm moet verschijnen, niet alleen als annotatiemetadata. Een lezer die de PDF op papier afdrukt, heeft niets aan een URI-annotatie.

Een volledig voorbeeld van documentgeneratie

Het patroon hieronder toont een realistischer scenario: het genereren van een kort rapport met een koptekstgedeelte, bodytekst en een voettekstrij met koppelingen, alles vanuit code in plaats van vanuit een formulier met TEdit-velden:

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;

Let op dat SetFont vóór elke groep tekstoproepen wordt aangeroepen. Het lettertype blijft niet behouden na AddPage, en als u vergeet het in te stellen vóór PrintHyperlink op een nieuwe pagina, wordt de annotatierechtoek berekend op basis van de standaardmetrieken van die pagina, die kunnen afwijken van wat u verwacht.

Waar annotatieverwerking verschilt per viewer

PDF URI-annotaties zijn gedefinieerd in ISO 32000-1 §12.6.4.7, en elke conforme viewer zou deze moeten volgen. In de praktijk verschillen sommige gedragingen per viewer. Adobe Acrobat toont bij de eerste klik een beveiligingsprompt voor URL's die niet in de lijst met vertrouwde domeinen staan; veel browsers en lichtgewicht lezers doen dat niet. Sommige zakelijke PDF-viewers in afgeschermde omgevingen schakelen URI-annotaties volledig uit als beleidsmaatregel, zodat een klik niets doet, zonder zichtbare fout. Mobiele PDF-apps variëren in de vraag of ze koppelingen openen in de ingebouwde webweergave of doorgeven aan de systeembrowser.

Geen van deze gevallen zijn fouten die u aan de generatiezijde kunt oplossen; het zijn viewerbeleidsbesluiten. Wat u wel kunt doen, is koppelingslabels schrijven die de URL ook zichtbaar maken in de documenttekst, zodat een lezer in een beperkte omgeving het adres nog steeds handmatig kan kopiëren. De annotatie is het gemak; de tekst is de terugvaloptie.

Nog een detail dat het waard is te kennen: PDF URI-annotaties dragen standaard geen visuele onderstreping. De onderstreping die u in de meeste viewers ziet, wordt door de viewer zelf getekend op basis van het annotatietype, niet door een glyph in de inhoudsstream. Als u een fysieke onderstreping nodig hebt die overleeft bij het afdrukken naar een niet-interactieve renderer of bij PDF-naar-afbeelding-conversie, teken deze dan expliciet met LineTo en Stroke op de juiste Y-afstand onder de tekstbasislijn. Dat is een afzonderlijke tekenhandeling en niet iets dat PrintHyperlink voor u afhandelt.

De hier getoonde hyperlink-API maakt deel uit van de HotPDF Component voor Delphi en C++Builder.