PDF čitač (viewer) u Delphi-ju svodi se na dve komponente i njihovo međusobno povezivanje. TPdf poseduje dokument: otvara datoteku, dešifruje je i odgovara na pitanja o broju stranica i metapodacima. TPdfView je vizuelna kontrola koja iscrtava stranice na ekranu i upravlja skrolovanjem, zumiranjem i stranicom koju korisnik trenutno gleda. PDFium Component obavija isti mehanizam za renderovanje koji se isporučuje unutar Chrome-a, tako da se glifovi, anti-aliasing i boje koje dobijete na platnu poklapaju sa onim što vaši korisnici već vide u svom veb-pregledaču. Posao nije u renderovanju. On je u povezivanju objekta dokumenta sa prikazom, učitavanju bez rušenja programa na oštećenoj ili lozinkom zaštićenoj datoteci i pružanju korisniku nekoliko kontrola koje čine da čitač izgleda kompletno: okretanje stranice, promena zumiranja, uklapanje stranice u prozor
Ovaj članak vas vodi kroz to sklapanje redosledom kojim ga stvarno gradite. Sve ovde renderuje po jednu stranicu u isto vreme, što je ono što većina tokova rada sa dokumentima zahteva. Ako su vam potrebne stranice naslagane u jednoj koloni koja se neprekidno skroluje, to je drugačija odluka o rasporedu i nije put koji je ovde prikazan
Povezivanje TPdf sa TPdfView
Prevucite TPdf i TPdfView na formu, a zatim recite prikazu koji dokument da prikaže. Ta jedna dodela vrednosti je cela veza između nevizuelnog dokumenta i kontrole koja ga iscrtava
procedure TFormMain.FormCreate(Sender: TObject);
begin
// Pdf and PdfView were dropped at design time.
PdfView.Pdf := Pdf; // the view paints whatever this document holds
PdfView.FitMode := pfmFitWidth; // start the user at a sensible zoom
end;
Pre nego što bilo šta od ovoga proradi, PDFium izvorna biblioteka mora biti na računaru. PDFium Component poziva pdfium32.dll or pdfium64.dll u zavisnosti od vaše ciljne platforme, i dokument jednostavno odbija da se otvori ako se DLL ne može pronaći. Isporučite odgovarajući DLL pored vaše izvršne datoteke ili ga postavite tamo gde će ga sistemski učitavač pronaći. Verzije sa omogućenim V8 motorom postoje samo za PDF-ove koji nose JavaScript koji želite da izvršite, što običan čitač ne radi, pa se opredelite za standardni DLL osim ako nemate konkretan razlog za suprotno
Učitavanje dokumenta bez poverenja u ulazne podatke
Instinkt je da se učitavanje obavije u try/except blok i da se bačeni izuzetak tretira kao neuspeh. Taj instinkt je ovde pogrešan, a njegovo pogrešno korišćenje proizvodi čitač koji izgleda u redu sve dok mu neko ne prosledi oštećenu datoteku. Postavljanje Active := True ne podiže izuzetak u slučaju neuspeha učitavanja. PDFium Component hvata internu grešku i ostavlja Active na False, tako da je jedini iskren način da saznate da li je dokument otvoren čitanje tog svojstva nakon što ga postavite
procedure TFormMain.OpenDocument(const FileName: string);
begin
Pdf.FileName := FileName;
Pdf.Active := True; // never raises; failure leaves Active = False
if not Pdf.Active then
begin
ShowMessage('Could not open ' + FileName);
Exit;
end;
PdfView.PageNumber := 1; // the view tracks its own current page
UpdatePageLabel;
end;
Dve stvari zaslužuju pažnju. Prva je da PageNumber postoji na oba objekta i da su oni nezavisni. Pdf.PageNumber je pojam dokumenta o trenutnoj stranici; PdfView.PageNumber je stranica koju kontrola zapravo prikazuje, i to je ona koju podešavate da biste pomerali korisnika kroz datoteku. Postavljanje jednog ne pomera drugo, tako da čitač uvek pokreće svojstvo prikaza. Druga stvar je indeksiranje koje počinje od 1: stranice idu od 1 do Pdf.PageCount, a ne od 0, što može iznenaditi svakoga ko je navikao na nizove čiji indeks počinje od nule
Rukovanje šifrovanom datotekom
Šifrovani dokumenti se uklapaju u istu putanju učitavanja. Ako se lozinka za otvaranje postavi pre aktivacije, dokument se dešifruje prilikom otvaranja; ako je pogrešna ili nedostaje, Active ostaje na False baš kao što se dešava sa oštećenom datotekom. Zato je rešenje da se zatraži lozinka i pokuša ponovna aktivacija
procedure TFormMain.OpenWithPassword(const FileName: string);
var
Password: string;
begin
Pdf.FileName := FileName;
Pdf.Active := True;
if not Pdf.Active then
begin
if InputQuery('Password required', 'Password:', Password) then
begin
Pdf.Password := Password; // must be set before Active := True
Pdf.Active := True;
end;
if not Pdf.Active then
begin
ShowMessage('Unable to open the document.');
Exit;
end;
end;
PdfView.PageNumber := 1;
end;
Budući da je neuspeh tih i za pogrešnu lozinku i za oštećenu datoteku, ne možete ih razlikovati samo na osnovu svojstva Active. U praksi je to prihvatljivo za čitač: korisnik ili unese ispravnu lozinku ili sazna da se datoteka ne može otvoriti, a poruka glasi isto u oba slučaja
Kretanje kroz dokument po stranicama
Sa otvorenim dokumentom, navigacija je aritmetika na PdfView.PageNumber ograničena sa Pdf.PageCount. Jedini stvarni posao je ograničavanje (clamping), tako da dugmad nikada ne gurnu stranicu van opsega, a prva i poslednja dugmad ostaju onemogućena na krajevima datoteke
procedure TFormMain.GoToPage(NewPage: Integer);
begin
if not Pdf.Active then
Exit;
if NewPage < 1 then
NewPage := 1
else if NewPage > Pdf.PageCount then
NewPage := Pdf.PageCount;
PdfView.PageNumber := NewPage;
UpdatePageLabel;
end;
// the four navigation buttons reduce to one call each
procedure TFormMain.FirstClick(Sender: TObject); begin GoToPage(1); end;
procedure TFormMain.PrevClick(Sender: TObject); begin GoToPage(PdfView.PageNumber - 1); end;
procedure TFormMain.NextClick(Sender: TObject); begin GoToPage(PdfView.PageNumber + 1); end;
procedure TFormMain.LastClick(Sender: TObject); begin GoToPage(Pdf.PageCount); end;
Polje za unos teksta "idi na stranicu N" je isti poziv GoToPage koji se hrani iz parsiranog celog broja, a ograničenje pokriva slučaj kada korisnik ukuca 9999 u datoteci od deset stranica. Držite UpdatePageLabel kao jedino mesto koje ispisuje "Stranica 3 od 12" tako da očitavanje nikada ne ispadne iz sinhronizacije sa onim što prikazuje kontrola
Zumiranje: eksplicitni procenti i režimi uklapanja
Zumiranje na TPdfView dolazi u dva oblika koji međusobno komuniciraju, a razumevanje te interakcije predstavlja razliku između kontrole zumiranja koja se ponaša kako treba i one koja se bori protiv korisnika. Direktan put je svojstvo Zoom, procenat gde 100 označava stvarnu veličinu. Drugi put je FitMode, koji govori prikazu da sam izračuna zum za vas i da ga ponovo izračunava kako se prozor menja
// fixed magnifications
PdfView.Zoom := 100; // actual size
PdfView.Zoom := 50; // half
PdfView.Zoom := 200; // double
// let the view size the page to the window, and keep it sized on resize
PdfView.FitMode := pfmFitWidth; // page width fills the control
PdfView.FitMode := pfmFitPage; // whole page visible
PdfView.FitMode := pfmActualSize; // 1:1 with the document's points
Evo dela gde se ljudi često sapliću. Direktan upis u Zoom poništava FitMode na pfmNone. To je ispravno ponašanje, a ne greška: onog trenutka kada korisnik izabere tačno 150%, prikaz više ne može da poštuje "uklapanje po širini", jer su ta dva zahteva u konfliktu. Posledica za vaš korisnički interfejs je da su dugme za zumiranje i dugme za uklapanje stranice međusobno isključiva stanja, a traka sa alatkama bi trebalo da učini aktivan režim vidljivim. Kada korisnik klikne na uklapanje stranice, postavite FitMode; kada klikne na numerički zum, postavite Zoom i pustite da on sam obriše režim uklapanja
Ako radije želite sami da izračunate vrednost uklapanja, možda da biste napunili klizač zumiranja trenutnim procentom uklapanja, pomoćne funkcije po stranici vam daju te brojeve bez promene režima. PageWidthZoom[N], PageZoom[N] i ActualSizeZoom[N] vraćaju procenat koji bi uklopio stranicu N po širini, uklopio je celu ili je renderovao u stvarnoj veličini
// seed a zoom readout from the fit-to-width value of the current page
var
FitPercent: Double;
begin
FitPercent := PdfView.PageWidthZoom[PdfView.PageNumber];
ZoomEdit.Text := Format('%.0f%%', [FitPercent]);
end;
Šta je zapravo potrebno za gotov čitač
Originalni naslov preuveličava posao. Gore opisani čitač ima nekoliko desetina linija, a već radi posao koji je potreban toku rada sa dokumentima: otvara datoteku, preživljava neispravnu datoteku, prikazuje stranicu, kreće se među stranicama i menja uvećanje ručno ili uklapanjem. PDFium obavlja teške delove nečujno. Ugrađeni fontovi se razrešavaju, beleške (annotations) i polja obrazaca se iscrtavaju tamo gde ih dokument postavlja, a stranica koju vidite se poklapa sa onom koju bi korisnik Chrome-a video, jer ih iscrtava isti mehanizam
Od ove osnove, dodaci su inkrementalni, a ne strukturalni. Selekcija teksta i pretraga čitaju iz istog tekstualnog sloja koji PDFium već gradi; metapodaci kao što su Pdf.Title i Pdf.Author su na udaljenosti od jednog čitanja svojstva; rotacija i sivi tonovi (grayscale) su opcije renderovanja koje prosleđujete kada iscrtavate stranicu na bitmapu. Ništa od toga ne menja kičmu koju ovde imate, a to su objekat dokumenta, prikaz i tok učitavanja-pa-navigacije koji ih povezuje. Uradite tu kičmu kako treba i ostatak je samo dekoracija
TPdf i TPdfView komponente koje se koriste u celom tekstu deo su PDFium Component za Delphi i C++Builder, koji nosi kompletnu referencu čitača na svojoj stranici proizvoda