Technical Article

PDF anotacije u Delphi-ju sa HotPDF-om: Tipovi i pravougaonici

Anotacija nije deo sadržaja stranice. Kada pozovete TextOut ili nacrtate pravougaonik, te oznake postaju deo toka sadržaja stranice i ugrađuju se u bajtove koje renderer iscrtava. Anotacija je zaseban rečnik koji je povezan sa stranicom preko njenog niza /Annots, sa sopstvenim pravougaonikom, sopstvenim izgledom i sopstvenim životnim ciklusom. Čitač je može otvoriti, pomeriti, sakriti ili ukloniti bez uticaja na ijedan karakter osnovne stranice. To razdvajanje je glavni razlog zašto anotacije postoje, a takođe je i izvor dve stvari koje najčešće iznenađuju programere na početku: mesto gde anotacija završava na stranici i kako izgleda kada je određeni čitač prikaže.

HotPDF izlaže podtipove anotacija prema standardu ISO 32000 kroz grupu poziva AddXxxAnnotation na objektu stranice. Svi oni dele istu strukturu: pravougaonik koji pozicionira anotaciju na stranici u PDF korisničkom prostoru, sadržaj (tekst, naziv pečata, par tačaka) i boju. Kada ispravno podesite pravougaonik, veći deo posla je završen. Ostatak se svodi na poznavanje toga koji podtipovi nose sopstveni izgled, a koji se oslanjaju na čitač da ih iscrta.

A PDF page produced by HotPDF showing text note icons, free text boxes, square and line markups, and approval stamps placed across the page
Jedna stranica koja istovremeno sadrži nekoliko podtipova anotacija: tekstualne beleške, slobodan tekst, geometrijske oznake i pečate

Pravougaonik je anotacija, a ne tekst

Svaki poziv anotacije zahteva TRect, a taj pravougaonik označava nešto sasvim drugo u odnosu na koordinate koje prosleđujete u TextOut. Za tekstualnu belešku (text note), to je aktivna zona (hotspot) na koju se može kliknuti, odnosno mali prostor gde se nalazi ikona beleške i gde klik otvara komentar. Za pravougaonik ili okvir sa slobodnim tekstom, to je vidljivi opseg oznake. Za pečat, to je okvir u koji se slika pečata skalira. Brojevi predstavljaju tačke u PDF korisničkom prostoru, merene od donjeg levog ugla stranice sa Y osom koja raste nagore, što je ista konvencija koju koristi i ostatak HotPDF-a.

Tekstualna beleška je najjednostavniji podtip. Dajete joj tekst poruke, pravougaonik za ikonu, zastavicu koja određuje da li je otvorena po default-u, naziv ikone i boju.

Pdf.CurrentPage.AddTextAnnotation(
  'Reviewer: confirm the totals on this line before sign-off.',
  Rect(120, 700, 140, 720),   // icon hotspot, ~20pt square
  False,                      // closed until the reader clicks it
  taComment,                  // bubble icon
  clBlue);

Pravougaonik je ovde namerno mali, oko dvadeset tačaka po stranici, jer je tekstualna beleška samo ikona sve dok neko ne klikne na nju. Ako napravite veliki pravougaonik, nećete dobiti veliku belešku, već samo preveliku zonu za klik sa ikonom zakačenom za jedan ugao. Zastavica Open kontroliše da li se popup prozor prikazuje prilikom učitavanja dokumenta. Ako postavite više beležaka na True, one će se slagati jedna preko druge i preko sadržaja, pa to sačuvajte samo za onu belešku koju čitalac zaista treba odmah da vidi.

Naziv ikone dolazi iz THPDFTextAnnotationType, koji se mapira na standardne ikone beležaka: taComment, taKey, taNote, taHelp, taParagraph, taNewParagraph i taInsert. Ikona je jedina stvar koju tip menja. Ona ne utiče na ponašanje, a korisno je znati da svaki čitač ne iscrtava svih sedam; najsigurnije ikone u starim i novim čitačima su taComment, taNote i taHelp.

Slobodan tekst se ispisuje na stranici, ali ostaje anotacija

Anotacija sa slobodnim tekstom (free text annotation) izgleda kao stvarni sadržaj jer je tekst vidljiv bez klika, smešten u svoj pravougaonik poput natpisa. Ipak, to je i dalje anotacija sa svim osobinama razdvajanja, što je upravo ono što želite za revizorski pečat ili oznaku nacrta koju neko treba da ukloni kasnije. Potpis funkcije zamenjuje ikonu i zastavicu otvorenosti vrednošću poravnanja.

Pdf.CurrentPage.AddFreeTextAnnotation(
  'DRAFT - not for distribution',
  Rect(200, 210, 400, 235),   // the box the text is laid into
  ftCenter,                   // ftLeftJust / ftCenter / ftRightJust
  clRed);

Ovde je pravougaonik važniji nego kod tekstualne beleške, jer se tekst prelama i poravnava unutar njega. Ako napravite prekratak okvir, tekst će biti opsečen na donjoj ivici; ako je preuzak, prelamaće se na mestima gde to niste želeli. Poravnanje dolazi iz THPDFFreeTextAnnotationJust i ima samo tri vrednosti. Pošto je slobodan tekst anotacija za označavanje, korisnik koji otvori fajl u editoru može da je selektuje, pomeri ili obriše kao celinu, što je razlika koja određuje da li ćete upotrebiti slobodan tekst ili jednostavno ispisati reči pomoću TextOut. Ako oznaka mora da bude trajna, nacrtajte je. Ako je urednička i predviđena za uklanjanje, napravite je kao anotaciju.

Geometrijske i linijske oznake za ukazivanje na detalje

Pravougaonici, krugovi i linije su oznake koje koristite da biste ukazali na određenu oblast umesto da je opisujete rečima. Funkcija AddCircleSquareAnnotation pokriva ova dva oblika kroz THPDFCSAnnotationType sa vrednostima csCircle ili csSquare, gde pravougaonik definiše granice oblika.

// A box drawn around a figure that needs attention
Pdf.CurrentPage.AddCircleSquareAnnotation(
  'Check this region against the source data',
  Rect(50, 300, 120, 360),
  csSquare,
  clGreen);

// A line, given two points rather than a rectangle
var
  StartPt, EndPt: THPDFCurrPoint;
begin
  StartPt.X := 130; StartPt.Y := 360;
  EndPt.X   := 250; EndPt.Y   := 320;
  Pdf.CurrentPage.AddLineAnnotation(
    'Points from the note to the figure',
    StartPt, EndPt,
    clBlue);
end;

Primetite da linijska anotacija odstupa od šablona pravougaonika: ona uzima dva THPDFCurrPoint zapisa, početak i kraj, jer je linija definisana svojim krajnjim tačkama, a ne okvirom. Boja definiše liniju. Ako su vam potrebni vrhovi strelica, HotPDF ima preopterećene verzije funkcije AddLineAnnotation koje prihvataju stilove završetka linije, ali obična forma sa tri argumenta crta čistu liniju, što je najčešće i potrebno.

Podtipovi za označavanje teksta rade na oblasti koju ste već definisali. Funkcija AddHighlightAnnotation uzima pravougaonik, opcionalni sadržaj i boju koja je podrazumevano žuta, i boji oblast kao marker. Namenjena je da stoji preko stvarnog teksta, pa pravougaonik treba da odgovara granicama reči koje ste nacrtali, što znači da ga obično računate iz istih koordinata koje ste prosledili u TextOut, umesto da nagađate.

Pečati zavise od čitača koji ih iscrtava

Anotacija pečata (stamp annotation) je ona koja će najverovatnije izgledati drugačije od jednog do drugog čitača, a razlog za to je važno razumeti. Funkcija AddStampAnnotation navodi standardni pečat kroz THPDFStampAnnotationType, sa vrednostima kao što su satApproved, satConfidential, satFinal, satDraft i satForComment.

Pdf.CurrentPage.AddStampAnnotation(
  'Approved for release on review',
  Rect(50, 400, 200, 440),
  satApproved,
  clGreen);

Naziv pečata je zapravo zahtev čitaču. PDF definiše skup standardnih naziva pečata, ali ne i grafiku iza njih, pa svaki čitač isporučuje sopstveni prikaz za oznake „APPROVED” ili „CONFIDENTIAL”, dok neki ne iscrtavaju ništa za nazive koje ne prepoznaju. Pravougaonik kontroliše okvir u koji se grafika skalira, a boja je smernica koju čitač može, ali ne mora da ispoštuje. Ako pečat mora da izgleda identično svuda, najsigurniji put uopšte nije standardni pečat: sami nacrtajte oznaku pomoću TextOut i drugih poziva za crtanje, ili je postavite kao anotaciju slobodnog teksta čiji izgled kontrolišete. Standardni pečat koristite kada želite prepoznatljiv izgled čitača i možete tolerisati razlike u prikazu.

Prilozi datoteka prate istu strukturu pravougaonika i sadržaja. Funkcija AddFileAttachmentAnnotation uzima opis, putanju fajla koji se ugrađuje, pravougaonik za ikonu spajalice i boju. Datoteka se nalazi unutar PDF-a, a ikona je objekat koji čitalac koristi za njeno preuzimanje.

Kako se anotacije razlikuju od AcroForm polja

Zabuna koja oduzima najviše vremena jeste tretiranje anotacije kao da je polje forme. Obe se povezuju sa stranicom preko niza /Annots, a polje forme je zapravo poseban podtip anotacije (widget), zbog čega izgledaju slično. Međutim, one nisu međusobno zamenljive. Polje forme čuva vrednost, ima naziv, učestvuje u redosledu tabulatora i može se poslati, resetovati ili skriptovati; njih kreirate pozivima AddTextField, AddCheckBox i AddPushButton, a ne pozivima anotacija na ovoj stranici. Oznaka anotacije čuva komentar ili oblik, nema vrednost za slanje i predstavlja pogrešan alat ako želite da prikupite unos od korisnika.

Praktičan test je jednostavan. Ako korisnik treba da kuca, bira ili klikne, a dokument treba to da zapamti, potreban vam je AcroForm polje. Ako ostavljate belešku, označavate oblast ili utiskujete status koji putuje sa fajlom ali nije podatak, potrebna vam je anotacija. Njihovo mešanje proizvodi dokumente koji izgledaju ispravno, ali se ponašaju pogrešno: dobijate „polje” koje niko ne može da popuni ili komentar koji nestaje kada se forma resetuje. Interaktivna strana, sa tipovima polja, validacijom i akcijama slanja, posebna je tema pokrivena u vodiču za AcroForm polja i akcije.

Sastavljanje stranice

Delovi se sastavljaju na isti način kao i u ostatku HotPDF-a. Podesite svojstva dokumenta, pozovite BeginDoc, nacrtajte sadržaj stranice pomoću poziva za tekst i grafiku, dodajte anotacije na vrh i završite sa EndDoc. Anotacije se povezuju sa CurrentPage, pa nakon poziva AddPage one završavaju na novoj stranici, a beleška namenjena prvoj stranici će se tiho pojaviti na drugoj ako je dodate nakon preloma stranice.

Pdf := THotPDF.Create(nil);
try
  Pdf.FileName := 'annotated.pdf';
  Pdf.Compression := cmFlateDecode;
  Pdf.FontEmbedding := True;
  Pdf.BeginDoc;

  Pdf.CurrentPage.SetFont('Arial', [], 11);
  Pdf.CurrentPage.TextOut(50, 740, 0, 'Quarterly figures, draft for review');

  Pdf.CurrentPage.AddTextAnnotation(
    'Confirm the totals before sign-off.',
    Rect(50, 720, 70, 740), False, taComment, clBlue);
  Pdf.CurrentPage.AddFreeTextAnnotation(
    'DRAFT', Rect(450, 720, 540, 745), ftCenter, clRed);
  Pdf.CurrentPage.AddStampAnnotation(
    'For comment', Rect(50, 660, 180, 695), satForComment, clGreen);

  Pdf.EndDoc;
finally
  Pdf.Free;
end;

Još jedno pravilo koje vredi usvojiti kada izlaz izgleda pogrešno: otvorite fajl u više čitača pre nego što zaključite da kod ne radi. Pečati i ređe ikone beležaka su najčešći uzroci problema, i pošto je anotacija zahtev čitaču a ne naslikani pikseli, razlika između Acrobat-a i nekog lakšeg pregledača je često posledica dizajna samog standarda, a ne greška u vašem pozivu.

Pozivi anotacija prikazani ovde su deo HotPDF komponente za Delphi i C++Builder.