Delphi'de bir PDF görüntüleyici (viewer) iki bileşene (component) ve aralarındaki bağlantıya indirgenir. TPdf belgeye sahiptir: dosyayı açar, şifresini çözer, sayfa sayısı ve meta veri (metadata) ile ilgili soruları yanıtlar. TPdfView, sayfaları ekranda boyayan ve kaydırma (scrolling), yakınlaştırma (zoom) ve kullanıcının şu anda baktığı sayfayı işleyen görsel denetimdir (visual control). PDFium Component, Chrome'un içinde gönderilen aynı oluşturma (rendering) motorunu sarar, böylece tuval (canvas) üzerinde elde ettiğiniz glifler, kenar yumuşatma (anti-aliasing) ve renk, kullanıcılarınızın tarayıcılarında zaten gördükleriyle eşleşir. İş oluşturmada değildir. Belge nesnesini görünüme (view) bağlamak, hasarlı veya parola korumalı bir dosyada çökmeden (crashing) yükleme yapmak ve kullanıcıya bir görüntüleyiciyi tamamlanmış hissettiren bir avuç denetimi vermektedir: sayfayı çevir, yakınlaştırmayı değiştir, sayfayı pencereye sığdır
Bu, aslında onu oluşturduğunuz sırayla bu birleştirmeyi (assembly) adım adım anlatır. Buradaki her şey aynı anda tek bir sayfayı oluşturur ki çoğu belge iş akışının (workflow) istediği şey budur. Sayfaların sürekli kayan tek bir sütunda yığılmasına ihtiyacınız varsa, bu farklı bir düzen (layout) kararıdır ve buradaki yol değildir
TPdf'yi TPdfView'a Bağlama
Forma bir TPdf ve bir TPdfView bırakın, ardından görünüme hangi belgeyi görüntüleyeceğini söyleyin. Bu tek atama, görsel olmayan belge ile onu boyayan denetim arasındaki bağlantının tamamıdır
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;
Bunların hiçbiri çalışmadan önce, PDFium yerel kütüphanesinin (native library) makinede olması gerekir. PDFium Component, hedef platformunuza bağlı olarak pdfium32.dll veya pdfium64.dll dosyasını çağırır ve DLL bulunamazsa belge basitçe açılmayı reddeder. Eşleşen DLL'yi çalıştırılabilir (executable) dosyanızın yanında gönderin veya sistem yükleyicisinin bulabileceği bir yere yerleştirin. V8 özellikli derlemeler (builds) yalnızca yürütmek istediğiniz JavaScript'i taşıyan PDF'ler için vardır, ki sade bir görüntüleyici bunu yapmaz, bu yüzden yapmamak için somut bir nedeniniz yoksa standart DLL'ye ulaşın
Girişe güvenmeden bir belgeyi yükleme
İçgüdü (instinct), yüklemeyi (load) bir try/except içine sarmak ve atılan (thrown) bir istisnayı başarısızlık olarak ele almaktır. Bu içgüdü burada yanlıştır ve bunu yanlış yapmak, birisi ona bozuk bir dosya verene kadar iyi görünen bir görüntüleyici üretir. Active := True ayarı, bir yükleme hatasında artış (raise) göstermez. PDFium Component dahili (internal) hatayı yakalar ve Active durumunu False'da bırakır, bu nedenle belgenin açılıp açılmadığını bilmenin tek dürüst yolu, ayarladıktan sonra özelliği geri okumaktır
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;
İki şey dikkati hak ediyor. Birincisi, PageNumber'ın her iki nesnede de var olması ve ikisinin birbirinden bağımsız olmasıdır. Pdf.PageNumber belgenin geçerli bir sayfa kavramıdır; PdfView.PageNumber denetimin gerçekte görüntülediği sayfadır ve kullanıcıyı dosya içinde taşımak için ayarladığınız sayfadır. Birini ayarlamak diğerini taşımaz, bu nedenle bir görüntüleyici (viewer) her zaman görünümün (view) özelliğini yönlendirir. İkincisi, 1 tabanlı indekslemedir: sayfalar 0'dan değil, 1'den Pdf.PageCount'a kadar uzanır, bu da sıfır tabanlı dizilere (arrays) alışkın olan herkesi yakalar
Şifrelenmiş bir dosyayı işleme
Şifrelenmiş belgeler aynı yükleme yoluna katlanır (fold). Açık (open) parola etkinleştirmeden önce ayarlanırsa, belge açılırken şifresi çözülür; eğer yanlışsa veya eksikse, tıpkı bozuk bir dosya için olduğu gibi Active tam olarak False kalır. Bu nedenle kurtarma, bir parola sormak ve etkinleştirmeyi tekrar denemektir
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;
Başarısızlık hem kötü bir parola hem de hasarlı bir dosya için sessiz olduğundan, ikisini yalnızca Active'den ayıramazsınız. Pratikte bu bir görüntüleyici için kabul edilebilirdir: kullanıcı ya doğru parolayı sağlar ya da dosyanın açılmayacağını öğrenir ve mesaj her iki durumda da aynı şekilde okunur
Belge boyunca sayfalama
Belge açıkken gezinme (navigation), Pdf.PageCount ile sınırlanan PdfView.PageNumber üzerinde aritmetiktir. Tek gerçek iş kenetlemedir (clamping), böylece düğmeler (buttons) sayfayı asla menzilin dışına itmez ve ilk ve son düğmeler dosyanın sonlarında devre dışı (disabled) kalır
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;
Bir "sayfa N'ye git" metin kutusu, ayrıştırılmış (parsed) bir tamsayıdan (integer) beslenen aynı GoToPage çağrısıdır ve kelepçe (clamp), kullanıcının on sayfalık bir dosyaya 9999 yazdığı durumu kapsar. Göstergenin görünümün (view) gösterdiğiyle hiçbir zaman senkronizasyon dışına kaymaması için UpdatePageLabel'ı "Sayfa 3 / 12" yazan tek yer olarak tutun
Yakınlaştırma (Zoom): açık yüzdeler ve sığdırma modları
TPdfView üzerindeki yakınlaştırma, etkileşime giren iki çeşitte gelir ve etkileşimi anlamak, uslu duran bir yakınlaştırma denetimi ile kullanıcıyla savaşan biri arasındaki farktır. Doğrudan yol, 100'ün gerçek boyut (actual size) anlamına geldiği bir yüzde olan Zoom özelliğidir. Diğer yol, görünüme yakınlaştırmayı sizin için hesaplamasını ve pencere yeniden boyutlandırıldıkça (resizes) hesaplamaya devam etmesini söyleyen FitMode'dur
// 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
İşte insanları çelmeleyen kısım burası. Zoom ataması, FitMode'u doğrudan pfmNone'a sıfırlar (resets). Bu doğru bir davranıştır, bir hata değildir: kullanıcının tam bir %150 seçtiği an, görünüm artık "genişliğe sığdır" (fit to width) seçeneğini de onurlandıramaz, çünkü iki istek çatışır. Kullanıcı arayüzünüz (UI) için bunun sonucu, bir yakınlaştırma (zoom-in) düğmesi ve bir sayfaya sığdır (fit-to-page) düğmesinin birbirini dışlayan durumlar olmasıdır ve araç çubuğu (toolbar) etkin modu görünür kılmalıdır. Kullanıcı sayfaya sığdır'ı tıkladığında FitMode'u ayarlayın; sayısal bir yakınlaştırmaya tıkladıklarında Zoom'u ayarlayın ve sığdırma modunu kendi başına temizlemesine izin verin
Belki de mevcut sığdırma yüzdesiyle bir yakınlaştırma kaydırıcısını (zoom slider) tohumlamak için (seed), sığdırma (fit) değerini kendiniz hesaplamayı tercih ederseniz, sayfa başına yardımcılar (helpers) modu değiştirmeden size sayıları verir. PageWidthZoom[N], PageZoom[N] ve ActualSizeZoom[N] N sayfasını genişliğe sığdıracak, bütünüyle sığdıracak veya gerçek boyutta oluşturacak (render) yüzdeyi döndürür
// 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;
Tamamlanmış bir görüntüleyici aslında neye ihtiyaç duyar?
Yukarıdaki görüntüleyici (viewer) birkaç düzine satırdır ve bir belge iş akışının (workflow) ihtiyaç duyduğu işi zaten yapar: bir dosya açmak, kötü bir tanesinden kurtulmak, bir sayfa göstermek, sayfalar arasında gezinmek ve büyütmeyi (magnification) elle veya sığdırarak değiştirmek. PDFium zor kısımları sessizce yapar. Gömülü (embedded) yazı tipleri çözülür, ek açıklamalar (annotations) ve form alanları (fields) belgenin onları yerleştirdiği yere boyanır ve gördüğünüz sayfa bir Chrome kullanıcısının göreceği sayfayla eşleşir, çünkü her ikisini de çizen aynı motordur
Bu temelden (base) itibaren eklemeler yapısal olmaktan ziyade artımlıdır (incremental). Metin seçimi ve arama, PDFium'un zaten oluşturduğu aynı metin katmanından okur; Pdf.Title ve Pdf.Author gibi meta veriler (metadata) bir özellik okuma uzağındadır; döndürme ve gri tonlamalı (grayscale), bir sayfayı bir bit eşleme (bitmap) çizerken aktardığınız oluşturma (render) seçenekleridir. Bunların hiçbiri, belge nesnesi, görünüm (view) ve bunları birbirine bağlayan "yükle, ardından gezin" (load-then-navigate) akışı olan buradaki omurgayı (spine) değiştirmez. O omurgayı doğru yapın ve geri kalanı dekorasyondur
Baştan sona kullanılan TPdf ve TPdfView bileşenleri, ürün sayfasında tam görüntüleyici referansını (reference) taşıyan Delphi ve C++Builder için PDFium Component'in bir parçasıdır