Teknik Makale

Delphi'de TPDFlibViewer ile İnteraktif PDF Görüntüleyici Oluşturun

Bir Delphi iş uygulamasına bir PDF okuma paneli yerleştirmek; bir oluşturma (rendering) döngüsü, bir kaydırma motoru veya bir yakınlaştırma modeli yazmayı gerektirmez. losLab PDF Library, tek bir çağrıyla bir belgeyi açan ve metin seçimi, kaydırma, çerçeve yakınlaştırma, anlık görüntüler (snapshots), bölge vurgulama, tam metin araması vurgulama, açıklama (annotation) etkileşimi ve yazdırmayı yerleşik davranış olarak sunan bir VCL denetimi olan TPDFlibViewer'ı barındırır. Bu makale, boş bir formu çalışan bir görüntüleyiciye dönüştüren rehabilitation beş adımı açıklamaktadır: denetimi yerleştirin, hazır eylemleri bağlayın, arama vurgulama ekleyin, açıklama tıklamalarını işleyin ve yazdırın

Bir oluşturma döngüsü yazmak yerine neden bir görüntüleyici denetimi kullanılmalı?

Öncelikle katmanlama argümanı gelir çünkü gerçekte ne elde ettiğinizi açıklar. Bir sayfayı bir biteşlemleme (bitmap) oluşturmak işin kolay olan yüzde 20'lik kısmıdır; diğer yüzde 80 ise onun etrafındaki her şeydir: tahliye bütçesine sahip bir sayfa biteşlem belleği (cache), farklı boyutlardaki sayfalar arasında kaydırma düzeni, yeniden boyutlandırmada yeniden hesaplanan yakınlaştırma modları, herhangi bir yakınlaştırma ve döndürmede bir fare pikselini sayfa koordinatlarına geri eşleyen isabet testi (hit-testing) ve titremeyen yeniden çizim planlaması. TPDFlibViewer tüm bunlara sahiptir ve rasterleştirme işini çoklu motorla oluşturma makalesinde açıklanan motorla aynı motora devreder, böylece denetim katmanı ve oluşturma (rendering) katmanı ayrı ayrı değiştirilebilir kalır. Form kodunuz bir oluşturucu (renderer) ile değil, kaydırılabilir bir Windows denetimi ile konuşur

Bir Delphi uygulamasına bir PDF görüntüleyici nasıl yerleştirilir?

TPDFlibViewer.LoadFromFile, denetimin kendi dahili TPDFlib örneği (instance) aracılığıyla bir belge açar ve başarı durumunda 1 değerini döndürür; bu nedenle minimum görüntüleyici bir yapıcı (constructor) çağrısı, bir Parent ataması ve bir yüklemeden ibarettir. Uygulamanın başka bir yerinde zaten bir TPDFlib örneği tutuyorsanız, AttachLibrary bunun yerine seçilen belgeyi görüntüler ve sahiplik sizin tarafınızda kalır

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 özelliği fare eylemini beş değer arasından seçer: vmSelect varsayılan metin seçme aracıdır, vmHand sürükleyerek kaydırma yapar ve düz bir tıklama hala bağlantıları takip eder, vmZoom sürüklenen alanı görünüm penceresini dolduracak şekilde büyüten bir çerçeve yakınlaştırmadır, vmSnapshot sürüklenen bir bölgeyi panoya kopyalar (bir OnSnapshot olayı ve bir SnapshotToClipboard anahtarı ile birlikte) ve vmHighlight kalıcı yarı saydam bölge vurgulamaları çizer. Vurgulama aracının koordinatları hakkında bir not düşmekte fayda var: bölgeler istemci piksellerinde değil, sayfa kullanıcı alanında saklanır, bu nedenle AddHighlightRegion işaretleri, sizin tarafınızdan herhangi bir ek kayıt tutulmasına gerek kalmadan yakınlaştırma, görünüm döndürme ve sayfa geçişlerinde kalıcı olur. Döndürülmüş bir görünümde, sürükleme yönü sayfa eksenlerine karşı bile çalışabilir, bu da ters döndürme eşlemesinden sonra negatif bir genişlik veya yükseklik üretir — denetim dikdörtgeni sizin için normalleştirir

Delphi'de yapıştırıcı kod olmadan bir PDF araç çubuğu nasıl bağlanır?

PDFlibViewerActions ünitesi araç çubuğu yapıştırıcı kodunu tamamen ortadan kaldırır. Sayfa gezintisi (TPDFlibViewerFirstPage, TPDFlibViewerPriorPage, TPDFlibViewerNextPage, TPDFlibViewerLastPage), yakınlaştırma (TPDFlibViewerZoomIn, TPDFlibViewerZoomOut, TPDFlibViewerFitWidth, TPDFlibViewerFitPage, TPDFlibViewerActualSize), görünüm döndürme (TPDFlibViewerRotateClockwise, TPDFlibViewerRotateAntiClockwise), yazdırma, dosya açma ve farklı kaydetme iletişim kutuları, seçilen metni kopyalama ve fare aracı başına bir anahtar eylemi (TPDFlibViewerSelectMode, TPDFlibViewerHandMode, TPDFlibViewerMarqueeZoomMode, TPDFlibViewerSnapshotMode, TPDFlibViewerHighlightMode) içeren yirmi adet hazır TAction alt sınıfı sağlar. Her eylem, yayınlanan (published) Viewer özelliği aracılığıyla bir denetimi işaret eder ve kendi durumunu korur: hiçbir belge açık değilken her eylem kendini devre dışı bırakır, gezinti eylemleri sayfa konumunu izler, kopyalama bir seçimin var olup olmadığını izler ve mod ile sığdırma eylemleri işaretli durumlarını aktif araç ve yakınlaştırma modu ile senkronize tutar. Tasarım zamanında hepsi Action List düzenleyicisinin losLab PDF kategorisinde kaydedilir; çalışma zamanında aynı sınıflar üçer satırdan oluşur

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;

Bu desen üzerine kendi eylem kaydınızı oluşturursanız, ünite kapsamındaki bir tuzağı bilmeye değer. RegisterActions, Vcl.ActnList içinde değil, System.Actions içinde bildirilir ve uses kısmında yalnızca Vcl.ActnList bulunduğunda aldığınız derleyici hatası etkin bir şekilde yanıltıcıdır: [TAction1, TAction2, ...] sınıf-dizi sabiti bir küme (set) olarak ayrıştırılmaya geri döner ve eylem sınıflarınızda bir tip uyuşmazlığı gibi görünen bir dizi E2010 Incompatible types: 'Integer' and 'class of ...' hatası üretir. Çözüm tek bir uses girdisidir, ancak tanı koyucu onun dışındaki her yeri gösterir. Yakınlaştırma araç çubukları için TPDFlibViewer.EffectiveZoomPercent reports the zoom actually in effect — including the computed factor in fit-width and fit-page modes — so a zoom-in step can build on the real current magnification rather than on the last value you assigned

Arama sonucu vurgulama ve arkasındaki koordinat ters çevrilmesi

HighlightSearchHits, tüm belgede bir sorguyu arar ve her eşleşmenin üzerine yarı saydam bir çubuk çizerek eşleşme sayısını döndürür; ClearSearchHighlights, SearchHighlightCount and the SearchHighlightColor özelliği arayüzü tamamlar. Eşleşen dikdörtgenler sayfa alanında saklandığından ve her çizimde yeniden yansıtıldığından, kullanıcı görünümü kaydırırken, yakınlaştırırken ve döndürürken çubuklar metinlerine yapışık kalır. Yardımcı TPDFlibSearchPanel bileşenini kullanıyorsanız, bunun RunSearch işlevi, varsayılan olarak açık olan HighlightInView özelliği aracılığıyla bağlı görüntüleyicide aynı çubukları otomatik olarak çizer

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;

İşin ince kısmı ve ham arama sonuçlarından kendinizinkini oluşturmak yerine yerleşik yolu tercih etme nedeni, koordinat sistemi dönüşümüdür. Metin motoru, eşleşme dikdörtgenlerini kütüphanenin Origin ayarına bağlı koordinatlarda bildirir: Origin 0 veya 3 ile Y ekseni yerel PDF kullanıcı alanında olduğu gibi aşağıdan yukarıya doğru çalışır ve Origin 2 veya 3 ile X ekseni sağ kenardan ölçülür. Görüntüleyicinin katmanı yukarıdan aşağıya, sola dayalı sayfa alanında çalışır, bu nedenle her eşleşen dikdörtgen kaydedilmeden önce ters çevrilmelidir (Y = PageHeight - Bottom ve uygun olan yerlerde X = PageWidth - Right) — bildirilen üst kenarı varsayılan orijin altında olduğu gibi kabul etmek, vurguyu sayfada dikey olarak aynalanmış konumda çizer. TPDFlibViewer, her eşleşmeyi kaydettiğinde aktif orijine göre bu dönüşümü gerçekleştirir, ardından çizim zamanında ileri döndürme eşlemesini uygular, bu nedenle çubuklar her açıda doğru şekilde yerleşir. VCL tuvalinin (canvas) yerel alfa birleştirme özelliği olmadığından, yarı saydamlığın kendisi sabit bir kaynak alfa ile Windows AlphaBlend API'sini kullanır. Temel metin arama ve geometri API'leri metin arama ve sayfa öğesi numaralandırma makalesinde ayrıntılı olarak ele alınmıştır

Açıklama tıklamaları, ipuçları ve ek dışa aktarma

TPDFlibViewer açıklamaları birinci sınıf etkileşimli nesneler olarak ele alır. Bağlantı olmayan bir açıklamaya tıklamak, sayfa numarası, 1 tabanlı açıklama dizini ve alt tür dizesi ile birlikte OnAnnotClick olayını tetikler; AnnotAtPagePoint aynı isabet testini programlı olarak sunar ve Popup yardımcı açıklamalarını atlar, böylece her zaman kullanıcının gerçekte gördüğü açıklamayı alırsınız. Bir açıklamanın üzerine gelindiğinde, varsayılan olarak açık olan ve standart VCL ShowHint özelliği ile birlikte çalışan AnnotHints anahtarı aracılığıyla Contents metni denetimin ipucu olarak gösterilir. FileAttachment açıklamaları için, SaveAnnotAttachmentToFile gömülü dosyayı diske yazar ve başarı durumunda 1 değerini döndürür; bu da birkaç satırda bir tıkla-kaydet iş akışını tamamlar

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;

Yazdırma ve planlamanız gereken sınırlar

Yazdırma için ayrı bir entegrasyona gerek yoktur. PrintDoc standart Windows yazdırma iletişim kutusunu (yazıcı seçimi, sayfa aralığı, kopyalar, harmanlama) gösterir ve işi kütüphanenin yazdırma motoruna devreder; PrintDoc(False) ise hiçbir arayüz olmadan tüm belgeyi varsayılan yazıcıya gönderir. PrintDocRange belirgin bir yazıcı adı, başlangıç ve bitiş sayfası, kopya sayısı ve harmanlama bayrağı ile tamamen programlı olarak çalışır; bu da aynı görüntüleyici örneğinden yönlendirilen toplu veya sunucu tarafından tetiklenen yazdırma işleri için doğru giriş noktasıdır

Dürüstçe belirtilmesi gereken iki sınır vardır. İlk olarak, TPDFlibViewer bir Windows VCL denetimidir; görüntüleyici katmanı NOVCL derlemelerinin dışındadır, bu nedenle konsol servisleri ve VCL dışı hedefler doğrudan temel TPDFlib oluşturma API'sini kullanmalıdır. İkinci olarak, arayüzsüz (headless) kullanım kasıtlı olarak desteklenir ancak sınırlandırılmıştır: CaptureRegion herhangi bir istemci bölgesini (sayfalar artı vurgulamalar) çağıranın sahip olduğu bir bit eşleme (bitmap) haline getirir ve pencere tanıtıcısı (handle) olmayan bir üst bağımsız denetimde çalışır, çünkü çizim yolu tanıtıcı oluşturulmasını zorlayacak VCL çağrılarından kaçınır. Bu, otomatik testlerde piksel düzeyinde doğrulamayı pratik hale getirir, ancak etkileşimli fare araçları gibi gerçekten bir mesaj döngüsüne ihtiyaç duyan her şey yine de gerçek bir kullanıcı arayüzü oturumuna aittir. Performans tarafında, denetim SetCacheLimit aracılığıyla yapılandırılabilir bir bütçeye sahip bir bellek sayfa önbelleği tutar ve oluşturulan sayfaları oturumlar arasında kalıcı hale getirebilir; görüntüleyici disk sayfası önbelleği makalesi bu katmanı ve monitör başına DPI (per-monitor DPI) davranışını ayrıntılı olarak ele almaktadır

Öyleyse beş adım: denetimi yerleştirin ve LoadFromFile'ı çağırın, PDFlibViewerActions'tan hazır eylemleri bağlayın, sayfa içi arama için HighlightSearchHits'i çağırın, açıklama iş akışları için OnAnnotClick'i işleyin ve PrintDoc'u sunun. Burada gösterilen her parça, görüntüleyici denetimi, eylem sınıfları ve oluşturma motorunun birlikte kurulduğu Delphi için standart losLab PDF Kütüphanesi içinde gelir