PDF-lukuikkunan upottaminen Delphi-yrityssovellukseen ei vaadi piirtosilmukan, vieritysmoottorin tai zoomausmallin toteuttamista. losLab PDF Library sisältää TPDFlibViewer-VCL-komponentin, joka avaa asiakirjan yhdellä kutsulla ja tarjoaa valmiina ominaisuuksina tekstin valinnan, panoroinnin, kehyszoomauksen, tilannevedokset, alueiden korostuksen, kokotekstihaun tulosten korostuksen, annotaatioiden käsittelyn ja tulostuksen. Tässä artikkelissa käydään läpi ne viisi vaihetta, joilla tyhjä lomake muutetaan toimivaksi katseluohjelmaksi: komponentin lisääminen, valmiiden toimintojen kytkeminen, haun korostuksen lisääminen, annotaatioklikkausten käsittely ja tulostaminen
Miksi käyttää katselukomponenttia piirtosilmukan kirjoittamisen sijaan?
Kerrosarkkitehtuuri on tärkein peruste, sillä se selittää, mitä todella saat. Sivun piirtäminen bittikartaksi on vain se helppo 20 prosenttia; loput 80 prosenttia koostuu kaikesta muusta sen ympärillä: sivun bittikarttavälimuistista poistobudjetteineen, vieritysasettelusta erikokoisille sivuille, zoomaustiloista, jotka lasketaan uudelleen koon muuttuessa, osumatestauksesta, joka muuntaa hiiren pikselin takaisin sivukoordinaateiksi missä tahansa zoomauksessa ja kierrossa, sekä välkkymättömästä uudelleenpiirron ajoituksesta. TPDFlibViewer hoitaa tämän kaiken ja delegoi rasterointityön samalle moottorille, jota kuvaillaan monimoottorista piirtoa käsittelevässä artikkelissa, joten ohjauskerros ja piirtokerros pysyvät erillisinä ja toisistaan riippumattomina. Lomakekoodisi kommunikoi vieritettävän Windows-komponentin kanssa, ei suoraan piirtomoottorin
Miten PDF-katseluohjelma upotetaan Delphi-sovellukseen?
TPDFlibViewer.LoadFromFile avaa asiakirjan komponentin sisäisen TPDFlib-instanssin kautta ja palauttaa arvon 1 onnistuessaan. Näin ollen minimaalinen katseluohjelma vaatii vain konstruktorikutsun, Parent-määrityksen ja yhden latauskutsun. Jos sinulla on jo TPDFlib-instanssi käytössä muualla sovelluksessa, AttachLibrary näyttää sen valitun asiakirjan sen sijaan, jolloin omistajuus säilyy sinulla
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;
ViewerMode-ominaisuus valitsee hiiren toiminnan viidestä eri vaihtoehdosta: vmSelect on oletusarvoinen tekstinvalintatyökalu, vmHand panoroi vetämällä kourankuvakkeella samalla kun tavallinen klikkaus seuraa edelleen linkkejä, vmZoom on kehyszoomaus, joka suurentaa vedetyn alueen täyttämään näkymän, vmSnapshot kaappaa vedetyn alueen leikepöydälle (OnSnapshot-tapahtuman and SnapshotToClipboard-kytkimen avulla), ja vmHighlight piirtää pysyviä läpinäkyviä aluekorostuksia. Korostustyökalun kohdalla koordinaatit ansaitsevat huomion: alueet tallennetaan sivun käyttäjäavaruudessa, ei asiakasalueen pikseleinä, joten AddHighlightRegion-merkinnät säilyvät zoomauksesta, näkymän kierrosta ja sivunvaihdosta riippumatta ilman erillistä kirjanpitoa. Kierretyssä näkymässä vetosuunta voi jopa olla vastakkainen sivun akseleihin nähden, mikä johtaa negatiiviseen leveyteen tai korkeuteen käänteisen kiertokuvauksen jälkeen — komponentti kuitenkin normalisoi suorakulmion puolestasi
Miten PDF-työkalurivi kytketään Delphissä ilman liitoskoodia?
PDFlibViewerActions-yksikkö poistaa työkalurivin liitoskoodin tarpeen kokonaan. Se tarjoaa kaksikymmentä valmista TAction-johdannaista, jotka kattavat sivunavigoinnin (TPDFlibViewerFirstPage, TPDFlibViewerPriorPage, TPDFlibViewerNextPage, TPDFlibViewerLastPage), zoomauksen (TPDFlibViewerZoomIn, TPDFlibViewerZoomOut, TPDFlibViewerFitWidth, TPDFlibViewerFitPage, TPDFlibViewerActualSize), näkymän kierron (TPDFlibViewerRotateClockwise, TPDFlibViewerRotateAntiClockwise), tulostuksen, tiedoston avaamis- ja tallennusikkunat, valitun tekstin kopioinnin sekä yhden kytkentätoiminnon kullekin hiirityökalulle (TPDFlibViewerSelectMode, TPDFlibViewerHandMode, TPDFlibViewerMarqueeZoomMode, TPDFlibViewerSnapshotMode, TPDFlibViewerHighlightMode). Jokainen toiminto viittaa komponenttiin sen julkaistun (published) Viewer-ominaisuuden kautta ja ylläpitää omaa tilaansa: kaikki toiminnot poistetaan käytöstä, kun asiakirjaa ei ole auki, navigointitoiminnot seuraavat sivun sijaintia, kopiointi seuraa onko tekstiä valittuna, ja tila- sekä sovitustoiminnot pitävät valintatilansa synkronoituna aktiivisen työkalun ja zoomaustilan kanssa. Suunnitteluaikana ne kaikki rekisteröityvät Action List -editorin losLab PDF -luokkaan; ajoaikana samat luokat vievät kukin vain kolme riviä
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;
Yksi yksikkötason sudenkuoppa on syytä tietää, jos rakennat oman toimintojen rekisteröinnin tämän mallin päälle. RegisterActions on esitelty yksikössä System.Actions, ei yksikössä Vcl.ActnList. Kääntäjän virheilmoitus, jonka saat jos uses-lauseessa on vain Vcl.ActnList, on erittäin harhaanjohtava: luokkataulukon literaali [TAction1, TAction2, ...] tulkitaan joukoksi (set), mikä aiheuttaa virheiden ketjun E2010 Incompatible types: 'Integer' and 'class of ...', jotka näyttävät tyyppiristiriidalta toimintoluokissasi. Korjaus on yhden yksikön lisääminen uses-lauseeseen, mutta diagnostiikka viittaa kaikkialle muualle paitsi siihen. Zoomaustyökalurivejä varten TPDFlibViewer.EffectiveZoomPercent raportoi todellisen käytössä olevan zoomaustason — mukaan lukien lasketun kertoimen sovita-leveyteen- ja sovita-sivuun-tiloissa — jotta zoomausvaihe voi perustua todelliseen nykyiseen suurennukseen eikä viimeisimpään määrittämääsi arvoon
Hakutulosten korostus ja sen taustalla oleva koordinaattien kääntäminen
HighlightSearchHits etsii hakusanaa koko asiakirjasta ja piirtää puoliläpinäkyvän palkin jokaisen osuman päälle palauttaen osumien määrän; ClearSearchHighlights, SearchHighlightCount ja SearchHighlightColor -ominaisuus täydentävät kokonaisuuden. Koska osumasuorakulmiot tallennetaan sivun avaruudessa ja projisoidaan uudelleen jokaisella piirtokerralla, palkit pysyvät liimattuina tekstiinsä käyttäjän vierittäessä, zoomatessa ja kiertäessä näkymää. Jos käytät siihen liittyvää TPDFlibSearchPanel-paneelia, sen RunSearch piirtää samat palkit liitettyyn katseluohjelmaan automaattisesti HighlightInView-ominaisuuden kautta, joka on oletusarvoisesti käytössä
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;
Hienovaraisin osuus, ja syy suosia sisäänrakennettua menetelmää oman hakutuloksiin perustuvan toteutuksen sijaan, on koordinaattijärjestelmän muunnos. Tekstimoottori raportoi osumasuorakulmiot koordinaatteina, jotka riippuvat kirjaston Origin-asetuksesta: kun Origin on 0 tai 3, Y-akseli kulkee alhaalta ylös kuten natiivissa PDF-käyttäjäavaruudessa, ja kun Origin on 2 tai 3, X-akseli mitataan oikeasta reunasta. Katseluohjelman peitekerros (overlay) toimii ylhäältä alas ja vasemmalta alkavassa sivunavaruudessa, joten jokainen osumasuorakulmio on käännettävä (Y = PageHeight - Bottom ja soveltuvin osin X = PageWidth - Right) ennen sen tallentamista — jos ilmoitettu yläreuna otetaan sellaisenaan oletusalkupisteessä, korostus piirtyy sivulla pystysuunnassa peilattuun kohtaan. TPDFlibViewer suorittaa tämän muunnoksen aktiivisen alkupisteen mukaan tallentaessaan jokaisen osuman ja soveltaa sitten suoraa kiertokuvausta piirtohetkellä, minkä vuoksi palkit asettuvat oikein kaikissa kulmissa. Läpinäkyvyys itsessään hyödyntää Windowsin AlphaBlend-rajapintaa vakiolla lähdealhalla (source alpha), koska VCL-kankaalla (canvas) ei ole natiivia alfavärien sekoitusta. Taustalla olevia tekstihaku- ja geometriarajapintoja käsitellään tarkemmin tekstihakua ja sivuelementtien luettelointia käsittelevässä artikkelissa
Annotaatioiden klikkaukset, vihjeet ja liitetiedostojen vienti
TPDFlibViewer käsittelee annotaatioita ensiluokkaisina interaktiivisina objekteina. Ei-linkkiä sisältävän annotaation napsauttaminen laukaisee OnAnnotClick-tapahtuman, joka välittää sivunumeron, 1-perustaisen annotaatioindeksin ja alityypin merkkijonon; AnnotAtPagePoint tarjoaa saman osumatestin ohjelmallisesti ja ohittaa Popup-apulaitteet, joten saat aina sen annotaation, jonka käyttäjä todella näkee. Annotaation päällä leijuttaminen näyttää sen Contents-tekstin komponentin vihjeenä AnnotHints-kytkimen kautta, joka on oletusarvoisesti käytössä ja toimii yhdessä VCL:n standardin ShowHint-ominaisuuden kanssa. FileAttachment-annotaatioille SaveAnnotAttachmentToFile kirjoittaa upotetun tiedoston levylle ja palauttaa arvon 1 onnistuessaan, mikä mahdollistaa klikkaa-ja-tallenna-työnkulun toteuttamisen muutamalla koodirivillä
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;
Tulostus ja huomioon otettavat rajoitukset
Tulostaminen ei vaadi erillistä integrointia. PrintDoc näyttää Windowsin tavallisen tulostusikkunan — tulostimen valinnan, sivualueen, kopiot ja lajittelun — ja antaa työn kirjaston tulostusmoottorille, kun taas PrintDoc(False) lähettää koko asiakirjan oletustulostimelle ilman käyttöliittymää. PrintDocRange toimii täysin ohjelmallisesti määrittämällä tulostimen nimen, aloitus- ja lopetussivun, kopiomäärän sekä lajittelulipun, mikä on oikea aloituspiste saman katseluohjelma-instanssin ohjaamille erä- tai palvelinohjatuille tulostustöille
Kaksi rajoitusta ansaitsee rehellisen maininnan. Ensinnäkin, TPDFlibViewer on Windows VCL -komponentti; katseluohjelmakerros on jätetty pois NOVCL-versioista, joten konsolipalveluiden ja ei-VCL-kohteiden tulisi käyttää suoraan taustalla olevaa TPDFlib-piirtorajapintaa. Toiseksi, palvelinkäyttö (headless) on tuettu tarkoituksella, mutta se on rajoitettua: CaptureRegion piirtää minkä tahansa asiakasalueen — sivut sekä korostukset — kutsujan omistamaan bittikarttaan ja toimii ilman isäntäikkunaa ja ikkunakahvaa (window handle), koska piirtopolku välttää VCL-kutsuja, jotka pakottaisivat kahvan luomiseen. Tämä tekee pikselitason tarkistuksista käytännöllisiä automaattisissa testeissä, mutta kaikki mikä todella vaatii viestisilmukkaa (message loop), kuten interaktiiviset hiirityökalut, kuuluu edelleen todelliseen käyttöliittymäistuntoon. Suorituskyvyn osalta komponentti ylläpitää sivujen välimuistia muistissa säädettävällä budjetilla SetCacheLimit-metodin kautta ja voi säilyttää piirretyt sivut istuntojen välillä; katseluohjelman levyn sivuvälimuistia käsittelevä artikkeli kattaa tämän kerroksen ja sen näyttökohtaisen DPI-toiminnan yksityiskohtaisesti
Viisi vaihetta siis: aseta komponentti ja kutsu LoadFromFile, liitä valmiit toiminnot yksiköstä PDFlibViewerActions, kutsu HighlightSearchHits sivun sisäistä hakua varten, käsittele OnAnnotClick annotaatiotyönkulkuja varten ja tarjoa PrintDoc. Jokainen tässä esitelty osa toimitetaan standardissa losLab PDF Library -kirjastossa Delphille, jossa katselukomponentti, toimintoluokat ja piirtomoottori asennetaan yhdessä