Ugradnja panela za čitanje PDF-a u Delphi poslovnu aplikaciju ne zahteva pisanje petlje za renderovanje, mehanizma za skrolovanje niti modela zumiranja. losLab PDF biblioteka isporučuje komponentu TPDFlibViewer, VCL kontrolu koja otvara dokument jednim pozivom i donosi selekciju teksta, pomeranje (panning), zumiranje prevlačenjem (marquee zoom), snimke ekrana (snapshots), isticanje regija, isticanje rezultata pretrage celog teksta, interakciju sa anotacijama i štampanje kao ugrađeno ponašanje. Ovaj članak vodi kroz pet koraka koji praznu formu pretvaraju u funkcionalan pregledač: postavljanje kontrole, povezivanje gotovih akcija, dodavanje isticanja pretrage, rukovanje klikovima na anotacije i štampanje
Zašto koristiti kontrolu pregledača umesto pisanja sopstvene petlje za renderovanje?
Argument o slojevima dolazi prvi, jer objašnjava šta zapravo dobijate. Renderovanje stranice u bitmapu je lakših 20 procenata; ostalih 80 procenata je sve što je obavijeno oko toga: keš memorija za bitmape stranica sa budžetom za izbacivanje, raspored skrolovanja kroz stranice različitih veličina, režimi zumiranja koji se preračunavaju pri promeni veličine, testiranje pogotka (hit-testing) koje mapira piksel miša nazad u koordinate stranice pri bilo kom zumiranju i rotaciji, kao i raspoređivanje ponovnog iscrtavanja koje ne treperi. TPDFlibViewer poseduje sve to i delegira rasterski rad istom mehanizmu opisanom u članku o renderovanju sa više mehanizama, tako da kontrolni sloj i sloj renderovanja ostaju odvojeno zamenljivi. Kod vaše forme komunicira sa Windows kontrolom koja podržava skrolovanje, a ne sa rendererom
Kako ugraditi PDF pregledač u Delphi aplikaciju?
Metoda TPDFlibViewer.LoadFromFile otvara dokument preko sopstvene interne instance TPDFlib i vraća 1 u slučaju uspeha, tako da se minimalni pregledač sastoji od poziva konstruktora, dodele svojstva Parent i jednog učitavanja. Ako već držite instancu TPDFlib na drugom mestu u aplikaciji, AttachLibrary umesto toga prikazuje njen izabrani dokument, pri čemu vlasništvo ostaje na vašoj strani
uses PDFlibViewer;
procedure TMainForm.FormCreate(Sender: TObject);
begin
FViewer := TPDFlibViewer.Create(Self);
FViewer.Parent := Self;
FViewer.Align := alClient;
if FViewer.LoadFromFile('quarterly-report.pdf', '') = 1 then
FViewer.ViewerMode := vmHand; // pan by dragging; a plain click still follows links
end;
Svojstvo ViewerMode bira šta miš radi, između pet vrednosti: vmSelect je podrazumevani alat za izbor teksta, vmHand pomera prikaz prevlačenjem pomoću kursora za hvatanje dok običan klik i dalje prati veze (linkove), vmZoom vrši zumiranje prevlačenjem okvira (marquee zoom) koje uveličava prevučenu traku da popuni prozor, vmSnapshot snima prevučenu regiju u privremenu memoriju (clipboard) (uz događaj OnSnapshot i prekidač SnapshotToClipboard), a vmHighlight iscrtava trajna polutransparentna isticanja regija. Alat za isticanje je vredan pažnje kada su u pitanju koordinate: regije se čuvaju u korisničkom prostoru stranice, a ne u pikselima klijenta, tako da oznake kreirane metodom AddHighlightRegion preživljavaju zumiranje, rotaciju prikaza i navigaciju kroz stranice bez ikakve potrebe za praćenjem sa vaše strane. U rotiranom prikazu, smer prevlačenja može čak ići i nasuprot osama stranice, što daje negativnu širinu ili visinu nakon mapiranja inverzne rotacije — kontrola normalizuje pravougaonik za vas
Kako povezati PDF traku sa alatkama u Delphi-ju bez veznog koda (glue code)?
Unit PDFlibViewerActions u potpunosti uklanja vezni kod za traku sa alatkama. On pruža dvadeset gotovih potomaka klase TAction koji pokrivaju navigaciju kroz stranice (TPDFlibViewerFirstPage, TPDFlibViewerPriorPage, TPDFlibViewerNextPage, TPDFlibViewerLastPage), zumiranje (TPDFlibViewerZoomIn, TPDFlibViewerZoomOut, TPDFlibViewerFitWidth, TPDFlibViewerFitPage, TPDFlibViewerActualSize), rotaciju prikaza (TPDFlibViewerRotateClockwise, TPDFlibViewerRotateAntiClockwise), štampanje, dijaloge za otvaranje i čuvanje datoteka, kopiranje izabranog teksta i po jednu akciju prebacivanja po alatu miša (TPDFlibViewerSelectMode, TPDFlibViewerHandMode, TPDFlibViewerMarqueeZoomMode, TPDFlibViewerSnapshotMode, TPDFlibViewerHighlightMode). Svaka akcija pokazuje na kontrolu preko svog objavljenog (published) svojstva Viewer i održava sopstveno stanje: svaka akcija se onemogućava kada dokument nije otvoren, navigacione akcije prate poziciju stranice, kopiranje prati da li selekcija postoji, a akcije režima i uklapanja drže svoje čekirano stanje sinhronizovanim sa aktivnim alatom i režimom zumiranja. U vreme dizajna sve se registruju u kategoriji losLab PDF u Action List editoru, a u vreme izvršavanja iste klase zauzimaju po tri linije koda
uses System.Actions, Vcl.ActnList, PDFlibViewer, PDFlibViewerActions;
procedure TMainForm.BuildToolbar;
var
NextPage: TPDFlibViewerNextPage;
FitWidth: TPDFlibViewerFitWidth;
HandMode: TPDFlibViewerHandMode;
begin
NextPage := TPDFlibViewerNextPage.Create(Self);
NextPage.ActionList := ActionList1;
NextPage.Viewer := FViewer;
btnNext.Action := NextPage;
FitWidth := TPDFlibViewerFitWidth.Create(Self);
FitWidth.ActionList := ActionList1;
FitWidth.Viewer := FViewer;
btnFitWidth.Action := FitWidth;
HandMode := TPDFlibViewerHandMode.Create(Self);
HandMode.ActionList := ActionList1;
HandMode.Viewer := FViewer;
btnHand.Action := HandMode;
end;
Jednu zamku u opsegu unita vredi znati ako gradite sopstvenu registraciju akcija na osnovu ovog obrasca. Procedura RegisterActions je deklarisana u System.Actions, a ne u Vcl.ActnList, a greška kompajlera koju dobijate kada je samo Vcl.ActnList u klauzuli uses je aktivno obmanjujuća: literal klase-niza [TAction1, TAction2, ...] se interpretira kao skup, stvarajući lanac grešaka E2010 Incompatible types: 'Integer' and 'class of ...' koje izgledaju kao nepodudaranje tipova u vašim klasama akcija. Rešenje je jedan unos u uses klauzuli, ali dijagnostika pokazuje svuda osim na njega. Za trake zumiranja, TPDFlibViewer.EffectiveZoomPercent prijavljuje zumiranje koje je zapravo na snazi — uključujući izračunati faktor u režimima uklapanja po širini i po stranici — tako da korak zumiranja može da se gradi na stvarnom trenutnom uvećanju, a ne na poslednjoj vrednosti koju ste dodelili
Isticanje pogodaka pretrage i obrtanje koordinata iza njega
Metoda HighlightSearchHits pretražuje ceo dokument za upit i crta polutransparentnu traku preko svakog pogotka, vraćajući broj pogodaka. Svojstva ClearSearchHighlights, SearchHighlightCount and SearchHighlightColor upotpunjuju ovaj interfejs. Pošto se pravougaonici pogodaka čuvaju u prostoru stranice i ponovo projektuju pri svakom iscrtavanju, trake ostaju zalepljene za svoj tekst dok korisnik skroluje, zumira i rotira prikaz. Ako koristite prateći panel TPDFlibSearchPanel, njegova metoda RunSearch automatski iscrtava iste trake u povezanom pregledaču preko svojstva HighlightInView, koje je podrazumevano uključeno
procedure TMainForm.btnSearchClick(Sender: TObject);
var
Hits: Integer;
begin
FViewer.SearchHighlightColor := clYellow;
Hits := FViewer.HighlightSearchHits(edtQuery.Text, False); // case-insensitive
StatusBar1.SimpleText := Format('%d matches', [Hits]);
end;
Suptilan deo, i razlog zašto treba preferirati ugrađenu putanju umesto pravljenja sopstvene od sirovih rezultata pretrage, jeste konverzija koordinatnog sistema. Tekstualni mehanizam prijavljuje pravougaonike podudaranja u koordinatama koje zavise od podešavanja Origin (početak koordinata) biblioteke: sa Origin 0 ili 3, Y osa ide odozdo nagore kao u izvornom PDF korisničkom prostoru, a sa Origin 2 ili 3, X osa se meri od desne ivice. Preklapanje pregledača radi u prostoru stranice odozgo nadole i sleva nadesno, tako da se svaki pravougaonik pogotka mora obrnuti (Y = PageHeight - Bottom, i gde je primenjivo X = PageWidth - Right) pre nego što se sačuva — uzimanje prijavljene gornje ivice zdravo za gotovo pod podrazumevanim početkom koordinata iscrtava isticanje na vertikalno ogledalnoj poziciji na stranici. TPDFlibViewer vrši ovu konverziju prema aktivnom početku koordinata kada zabeleži svaki pogodak, a zatim primenjuje mapiranje direktne rotacije u vreme iscrtavanja, zbog čega trake sleću ispravno pod svakim uglom. Sama transparentnost koristi Windows API AlphaBlend sa konstantnom alfe izvora, pošto VCL platno (canvas) nema učitavanje alfa kanala (alpha compositing). Osnovni API-ji za pretragu teksta i geometriju detaljno su pokriveni u članku o pretrazi teksta i enumeraciji elemenata stranice
Klikovi na anotacije, saveti (hints) i izvoz priloga (attachments)
Komponenta TPDFlibViewer tretira anotacije kao interaktivne objekte prve klase. Klik na anotaciju koja nije veza pokreće događaj OnAnnotClick sa brojem stranice, indeksom anotacije u bazi od 1 i stringom podtipa. Metoda AnnotAtPagePoint izlaže isti test pogotka programski i preskače prateće Popup anotacije, tako da uvek dobijate anotaciju koju korisnik zapravo vidi. Prelazak mišem preko anotacije prikazuje njen Contents tekst kao savet (hint) kontrole preko prekidača AnnotHints, koji je podrazumevano uključen i sarađuje sa standardnim VCL svojstvom ShowHint. Za anotacije tipa FileAttachment, metoda SaveAnnotAttachmentToFile upisuje ugrađenu datoteku na disk i vraća 1 u slučaju uspeha, što kompletira radni tok klikni-i-sačuvaj u samo nekoliko linija koda
procedure TMainForm.ViewerAnnotClick(Sender: TObject; APage, AnnotIndex: Integer;
const Subtype: WideString);
begin
if Subtype = 'FileAttachment' then
if FViewer.SaveAnnotAttachmentToFile(APage, AnnotIndex,
'C:\Temp\attached-invoice.xml') = 1 then
StatusBar1.SimpleText := 'Attachment saved';
end;
Štampanje i granice koje bi trebalo da planirate
Štampanje ne zahteva posebnu integraciju. Metoda PrintDoc prikazuje standardni Windows dijalog za štampanje — izbor štampača, opseg stranica, broj kopija, slaganje (collation) — i predaje posao mehanizmu za štampanje biblioteke, dok PrintDoc(False) šalje ceo dokument na podrazumevani štampač bez ikakvog korisničkog interfejsa. PrintDocRange pruža potpuno programski pristup sa eksplicitnim nazivom štampača, početnom i krajnjom stranicom, brojem kopija i zastavicom slaganja, što je prava ulazna tačka za grupne poslove ili poslove štampanja pokrenute sa servera koji se pokreću iz iste instance pregledača
Dve granice zaslužuju iskreno pominjanje. Prvo, TPDFlibViewer je Windows VCL kontrola; sloj pregledača je isključen iz NOVCL build-ova, tako da bi konzolne usluge i ciljevi van VCL-a trebali direktno da koriste osnovni API za renderovanje TPDFlib. Drugo, upotreba bez grafičkog okruženja (headless use) je namerno podržana, ali ograničena: metoda CaptureRegion renderuje bilo koju klijentsku regiju — stranice plus isticanja — u bitmapu u vlasništvu pozivaoca i radi na kontroli bez roditelja (unparented control) bez rukovanja prozorom (window handle), jer putanja iscrtavanja izbegava VCL pozive koji bi iznudili kreiranje rukovaoca. To čini proveru na nivou piksela u automatizovanim testovima praktičnom, ali svemu što zaista zahteva petlju poruka (message loop), kao što su interaktivni alati za miša, i dalje je mesto u stvarnoj korisničkoj sesiji. Sa strane performansi, kontrola drži keš stranica u memoriji sa podesivim budžetom preko SetCacheLimit i može da perzistira renderovane stranice kroz sesije; članak o kešu stranica pregledača na disku detaljno pokriva taj sloj i njegovo ponašanje po monitoru kod DPI skale
Pet koraka, dakle: postavite kontrolu i pozovite LoadFromFile, povežite gotove akcije iz unita PDFlibViewerActions, pozovite HighlightSearchHits za pretragu unutar stranice, rukujte događajem OnAnnotClick za radne tokove sa anotacijama i izložite metodu PrintDoc. Svaki prikazani deo se isporučuje u standardnoj losLab PDF biblioteci za Delphi, gde se kontrola pregledača, klase akcija i mehanizam za renderovanje instaliraju zajedno