Technical Article

HotPDF Delphi hiperlinkovi: Saveti za PrintHyperlink anotacije

PDF hiperlinkovi su URI anotacije: pravougaonik koji pokriva određenu oblast stranice i koji, kada se na njega klikne, govori programu za pregled da otvori URL. Anotacija i tekst ispod nje su potpuno nezavisni objekti. HotPDF-ova metoda PrintHyperlink objedinjuje oba u jedan poziv, ispisujući tekst i izračunavajući pravougaonik anotacije na osnovu dimenzija renderovanog teksta. Ta praktičnost krije detalj koji vredi razumeti pre nego što napišete produkcijski kod.

Kako funkioniše PrintHyperlink

Metoda PrintHyperlink se nalazi u klasi THPDFPage i prima četiri argumenta: koordinate X i Y (u tačkama/points, sa početkom u donjem levom uglu i Y koordinatom koja raste nagore), string oznake (label) koji se ispisuje i odredišni URL. Interno, ona poziva TextOut koristeći trenutnu boju hiperlinka, a zatim odmah izračunava pravougaonik anotacije pomoću funkcija TextWidth i TextHeight na osnovu trenutnih parametara fonta. To znači da font i njegova veličina moraju biti podešeni pre poziva i ne smeju se menjati između iscrtavanja oznake i postavljanja anotacije, jer se oba rešavaju u istom pozivu.

Podrazumevana boja je clBlue. Metoda SetRGBHyperlinkColor je menja samo za naredne pozive; ona ne ažurira retroaktivno anotacije koje su već upisane. Ako su vam potrebne različite boje za različite grupe linkova na istoj stranici, pozovite SetRGBHyperlinkColor pre svake grupe i vratite je na podrazumevanu vrednost nakon toga.

Evo minimalnog dokumenta koji upisuje tri linka koristeći dve različite boje:

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;

Zamka sa koordinatama

HotPDF koristi početak u donjem levom uglu pri čemu Y raste nagore, u tačkama/points (1/72 inča). A4 stranica ima dimenzije 595 x 842 pt; US Letter stranica ima 612 x 792 pt. Koordinata Y=750 se nalazi blizu vrha A4 stranice, dok bi Y=50 bilo blizu donje margine. Svako ko dolazi iz sveta računarske grafike na ekranu ili HTML-a pretpostavlja suprotno i postavlja prvu liniju linka direktno van vidljive oblasti.

Pravougaonik anotacije koji izračunava PrintHyperlink koristi isti koordinatni sistem. Ako kasnije rotirate stranicu, skalirate je ili promenite veličinu stranice bez ponovnog računanja X/Y vrednosti, vidljivi tekst i klikabilni pravougaonik će se razdvojiti. Link će raditi u smislu da klik negde blizu teksta aktivira URL, ali aktivna zona (hot zone) više ne odgovara onome što čitalac vidi. Testirajte na stvarnoj veličini stranice i nivou zumiranja koji isporučujete korisnicima, a ne samo na računaru za razvoj pri 100% zumu.

Jedan od slučajeva gde je odstupanje garantovano: ako pozovete PrintHyperlink sa koordinatama prilagođenim za A4 stranicu, a zatim pređete na prilagođenu stranicu užeg formata bez prilagođavanja X/Y vrednosti, anotacija može završiti potpuno van stranice. Objekat anotacije se i dalje upisuje u PDF; većina programa za pregled ga tiho odbacuje (clip), pa link jednostavno nestaje bez ikakve greške.

Tekst oznake naspram odredišnog URL-a

Argumenti Text i Link su nezavisni. Možete ispisati „Preuzmi PDF fakture” dok je odredište potpuno kvalifikovani HTTPS URL sa parametrima upita. To razdvajanje je namerno; vidljiva oznaka treba da bude čitljiva ljudima, dok URL može biti dugačak ili dinamički generisan.

Problemi nastaju kada je sama oznaka sirovi URL, posebno ako je dugačak. Ako se URL vizuelno prelomi u dva reda, a pravougaonik anotacije je izračunat za jednoredni string, samo će prvi red biti klikabilan. Metoda PrintHyperlink ne podržava višeredni prelom; neka oznaka bude dovoljno kratka da stane u jedan red pri trenutnoj veličini fonta i širini stranice, ili koristite kratku opisnu oznaku sa punim URL-om kao odredištem.

Za dokumente koji će se arhivirati ili distribuirati bez aktivne internet veze, takođe razmotrite da li bi sam URL trebalo da se pojavi u štampanom obliku negde u telu dokumenta, a ne samo kao metapodatak anotacije. Čitalac koji štampa PDF na papiru nema nikakvu korist od URI anotacije.

Kompletan primer generisanja dokumenta

Šablon u nastavku prikazuje realniji scenario: generisanje kratkog izveštaja sa zaglavljem, telom teksta i podnožjem sa linkovima, i to direktno iz koda, a ne preko forme sa TEdit poljima:

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;

Primetite da se SetFont poziva pre svake grupe tekstualnih poziva. Font se ne zadržava nakon poziva AddPage, i ako zaboravite da ga podesite pre poziva PrintHyperlink na novoj stranici, pravougaonik anotacije će biti izračunat na osnovu podrazumevanih parametara stranice, što se može razlikovati od onoga što očekujete.

Gde se rukovanje anotacijama razlikuje među programima za pregled

PDF URI anotacije su definisane u standardu ISO 32000-1 §12.6.4.7, i svaki usaglašeni program za pregled bi trebalo da ih podržava. U praksi se nekoliko ponašanja razlikuje u zavisnosti od programa. Adobe Acrobat prikazuje bezbednosno upozorenje pri prvom kliku za URL-ove koji nisu na listi pouzdanih domena; mnogi veb pregledači i jednostavni čitači to ne rade. Neki korporativni PDF čitači u strogo kontrolisanim okruženjima potpuno onemogućavaju URI anotacije kroz polise, pa klik ne radi ništa bez ikakve vidljive greške. Mobilne PDF aplikacije se razlikuju po tome da li otvaraju linkove unutar ugrađenog veb prikaza ili ih prosleđuju sistemskom pregledaču.

Ništa od ovoga nisu bagovi koje možete ispraviti sa strane generisanja; to su odluke o polisama samog programa za pregled. Ono što možete učiniti jeste da napišete oznake linkova tako da URL bude vidljiv i u samom telu dokumenta, kako bi čitalac u ograničenom okruženju i dalje mogao ručno da kopira adresu. Anotacija je tu radi praktičnosti, dok je tekst rezervna varijanta (fallback).

Još jedan detalj koji vredi znati: PDF URI anotacije po defaultu nemaju vizuelno podvlačenje. Podvlačenje koje vidite u većini programa za pregled iscrtava sam čitač na osnovu tipa anotacije, a ne preko karaktera (glyph) u samom toku sadržaja. Ako vam je potrebno fizičko podvlačenje koje ostaje vidljivo pri štampanju na neinteraktivnom štampaču ili konverziji PDF-a u sliku, nacrtajte ga eksplicitno pomoću LineTo i Stroke na odgovarajućem Y ofsetu ispod osnovne linije teksta. To je zasebna operacija crtanja, a ne nešto što PrintHyperlink radi automatski.

API za hiperlinkove koji je ovde prikazan deo je HotPDF komponente za Delphi i C++Builder.