Artikel Teknis

Membangun Viewer PDF Interaktif di Delphi dengan TPDFlibViewer

Menyematkan panel pembaca PDF dalam aplikasi bisnis Delphi tidak memerlukan penulisan loop rendering, mesin gulir, atau model zoom. losLab PDF Library menyediakan TPDFlibViewer, sebuah kontrol VCL yang membuka dokumen dengan satu panggilan dan menghadirkan pilihan teks, panning, marquee zoom, snapshot, penyorotan wilayah, penyorotan pencarian teks lengkap, interaksi anotasi, dan pencetakan sebagai perilaku bawaan. Artikel ini membahas lima langkah untuk mengubah formulir kosong menjadi viewer yang berfungsi: menempatkan kontrol, menghubungkan aksi siap pakai, menambahkan penyorotan pencarian, menangani klik anotasi, dan mencetak

Mengapa menggunakan kontrol viewer daripada menulis loop rendering?

Argumen pelapisan (layering) adalah yang utama, karena menjelaskan apa yang sebenarnya Anda peroleh. Merender halaman ke bitmap hanyalah 20 persen yang mudah; 80 persen sisanya adalah semua hal di sekitarnya: cache halaman bitmap dengan anggaran penghapusan, tata letak gulir di berbagai halaman dengan ukuran berbeda, mode zoom yang menghitung ulang saat ukuran diubah, hit-testing yang memetakan piksel mouse kembali ke koordinat halaman pada zoom dan rotasi apa pun, serta penjadwalan cat ulang tanpa kedipan. TPDFlibViewer memiliki semua itu dan mendelegasikan pekerjaan raster ke mesin yang sama yang dijelaskan dalam artikel rendering multi-mesin, sehingga lapisan kontrol dan lapisan rendering tetap dapat diganti secara terpisah. Kode formulir Anda berinteraksi dengan kontrol Windows yang dapat digulir, bukan dengan perender

Bagaimana cara menyematkan viewer PDF dalam aplikasi Delphi?

TPDFlibViewer.LoadFromFile membuka dokumen melalui instans internal TPDFlib milik kontrol itu sendiri dan mengembalikan nilai 1 jika berhasil, sehingga viewer minimal hanyalah panggilan konstruktor, penetapan Parent, dan satu pemuatan. Jika Anda sudah memiliki instans TPDFlib di tempat lain dalam aplikasi, AttachLibrary akan menampilkan dokumen yang dipilih sebagai gantinya, dengan kepemilikan tetap berada di sisi Anda

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;  // geser dengan menyeret; klik biasa tetap mengikuti tautan
end;

Properti ViewerMode memilih apa yang dilakukan mouse, dari lima nilai: vmSelect adalah alat pilihan teks default, vmHand menggeser dengan menyeret menggunakan kursor genggam sementara klik biasa tetap mengikuti tautan, vmZoom adalah marquee zoom yang memperbesar area yang diseret untuk memenuhi viewport, vmSnapshot mengambil wilayah yang diseret ke papan klip (dengan kejadian OnSnapshot dan sakelar SnapshotToClipboard), dan vmHighlight melukis penyorotan wilayah transparan yang persisten. Alat penyorotan ini perlu diperhatikan koordinatnya: wilayah disimpan dalam ruang pengguna halaman, bukan piksel klien, sehingga tanda AddHighlightRegion tetap bertahan saat zoom, rotasi tampilan, dan navigasi halaman tanpa pembukuan apa pun di sisi Anda. Dalam tampilan yang diputar, arah seretan bahkan bisa berlawanan dengan sumbu halaman, yang menghasilkan lebar atau tinggi negatif setelah pemetaan rotasi terbalik — kontrol akan menormalkan persegi panjang tersebut untuk Anda

Bagaimana cara menghubungkan bilah alat PDF di Delphi tanpa kode perekat?

Unit PDFlibViewerActions menghapus kode perekat bilah alat sepenuhnya. Unit ini menyediakan dua puluh turunan TAction siap pakai yang mencakup navigasi halaman (TPDFlibViewerFirstPage, TPDFlibViewerPriorPage, TPDFlibViewerNextPage, TPDFlibViewerLastPage), zoom (TPDFlibViewerZoomIn, TPDFlibViewerZoomOut, TPDFlibViewerFitWidth, TPDFlibViewerFitPage, TPDFlibViewerActualSize), rotasi tampilan (TPDFlibViewerRotateClockwise, TPDFlibViewerRotateAntiClockwise), pencetakan, dialog buka dan simpan berkas, salin teks terpilih, dan satu tindakan sakelar per alat mouse (TPDFlibViewerSelectMode, TPDFlibViewerHandMode, TPDFlibViewerMarqueeZoomMode, TPDFlibViewerSnapshotMode, TPDFlibViewerHighlightMode). Setiap tindakan menunjuk ke kontrol melalui properti Viewer yang diterbitkan dan mempertahankan keadaannya sendiri: setiap tindakan menonaktifkan dirinya sendiri saat tidak ada dokumen yang terbuka, tindakan navigasi melacak posisi halaman, tindakan salin melacak apakah ada pilihan teks, serta tindakan mode dan kesesuaian menjaga keadaan tercentangnya tetap sinkron dengan alat aktif dan mode zoom. Pada waktu desain, semuanya terdaftar dalam kategori losLab PDF dari editor Daftar Tindakan (Action List); pada waktu runtime, kelas yang sama masing-masing hanya membutuhkan tiga baris kode

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;

Satu jebakan cakupan unit perlu diketahui jika Anda membangun registrasi tindakan sendiri di atas pola ini. RegisterActions dideklarasikan di System.Actions, bukan di Vcl.ActnList, dan kesalahan kompiler yang Anda dapatkan jika hanya menyertakan Vcl.ActnList dalam klausa uses sangatlah menyesatkan: literal array-kelas [TAction1, TAction2, ...] ditafsirkan sebagai set, menghasilkan rangkaian kesalahan E2010 Incompatible types: 'Integer' and 'class of ...' yang terlihat seperti ketidakcocokan tipe pada kelas tindakan Anda. Solusinya adalah satu entri uses saja, tetapi diagnosisnya menunjuk ke mana-mana kecuali ke sana. Untuk bilah alat zoom, TPDFlibViewer.EffectiveZoomPercent melaporkan persentase zoom yang sebenarnya berlaku — termasuk faktor yang dihitung dalam mode fit-width dan fit-page — sehingga langkah zoom-in dapat didasarkan pada pembesaran saat ini yang sebenarnya, bukan pada nilai terakhir yang Anda tetapkan

Penyorotan hasil pencarian dan pembalikan koordinat di belakangnya

HighlightSearchHits mencari kueri di seluruh dokumen dan melukis bilah transparan di atas setiap kecocokan, mengmengembalikan jumlah hasil; properti ClearSearchHighlights, SearchHighlightCount, dan SearchHighlightColor melengkapi fitur ini. Karena persegi panjang hasil disimpan dalam ruang halaman dan diproyeksikan kembali pada setiap pengecatan, bilah-bilah tersebut tetap menempel pada teksnya saat pengguna menggulir, memperbesar, dan memutar tampilan. Jika Anda menggunakan komponen pendamping TPDFlibSearchPanel, RunSearch miliknya akan melukis bilah yang sama di viewer yang terpasang secara otomatis melalui properti HighlightInView, yang aktif secara default

procedure TMainForm.btnSearchClick(Sender: TObject);
var
  Hits: Integer;
begin
  FViewer.SearchHighlightColor := clYellow;
  Hits := FViewer.HighlightSearchHits(edtQuery.Text, False);  // tidak sensitif huruf besar/kecil
  StatusBar1.SimpleText := Format('%d matches', [Hits]);
end;

Bagian yang rumit, dan alasan untuk lebih memilih jalur bawaan daripada membuat sendiri dari hasil pencarian mentah, adalah konversi sistem koordinat. Mesin teks melaporkan persegi panjang kecocokan dalam koordinat yang bergantung pada pengaturan Origin pustaka: dengan Origin 0 atau 3, sumbu Y berjalan dari bawah ke atas seperti dalam ruang pengguna PDF asli, dan dengan Origin 2 or 3, sumbu X diukur dari tepi kanan. Overlay viewer bekerja dalam ruang halaman berbasis kiri atas (top-down, left-based), sehingga setiap persegi panjang kecocokan harus dibalik (Y = PageHeight - Bottom, dan jika berlaku X = PageWidth - Right) before it is stored — mengambil tepi atas yang dilaporkan apa adanya di bawah origin default akan melukis penyorotan pada posisi cermin vertikal di halaman. TPDFlibViewer melakukan konversi ini sesuai dengan origin yang aktif saat merekam setiap kecocokan, kemudian menerapkan pemetaan rotasi maju pada saat pengecatan, itulah sebabnya bilah-bilah tersebut mendarat dengan benar di setiap sudut. Transparansi itu sendiri menggunakan API Windows AlphaBlend dengan source alpha konstan, karena kanvas VCL tidak memiliki pencampuran warna alfa (alpha compositing) bawaan. API pencarian teks dan geometri dasar dibahas secara mendalam dalam artikel pencarian teks dan enumerasi elemen halaman

Klik anotasi, petunjuk, dan ekspor lampiran

TPDFlibViewer memperlakukan anotasi sebagai objek interaktif kelas satu. Mengklik anotasi non-tautan akan memicu kejadian OnAnnotClick dengan nomor halaman, indeks anotasi berbasis 1, dan string subtipe; AnnotAtPagePoint mengekspos pengujian klik yang sama secara terprogram dan melewatkan anotasi pendamping Popup sehingga Anda selalu mendapatkan anotasi yang benar-benar dilihat pengguna. Mengarahkan kursor ke anotasi akan menampilkan teks Contents sebagai petunjuk (hint) kontrol melalui sakelar AnnotHints, yang aktif secara default dan bekerja sama dengan properti standar VCL ShowHint. Untuk anotasi FileAttachment, SaveAnnotAttachmentToFile menulis berkas yang disematkan ke disk dan mengmengembalikan nilai 1 jika berhasil, yang menyelesaikan alur kerja klik-untuk-menyimpan dalam beberapa baris kode saja

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;

Pencetakan dan batasan yang harus Anda rencanakan

Pencetakan tidak memerlukan integrasi terpisah. PrintDoc menampilkan dialog cetak standar Windows — pilihan printer, rentang halaman, salinan, kolasi — dan menyerahkan pekerjaan tersebut ke mesin pencetakan pustaka, sementara PrintDoc(False) mengirimkan seluruh dokumen ke printer default tanpa antarmuka pengguna sama sekali. PrintDocRange berjalan sepenuhnya secara terprogram dengan nama printer eksplisit, halaman mulai dan akhir, jumlah salinan, serta bendera kolasi, yang merupakan titik masuk yang tepat untuk pekerjaan cetak massal atau yang dipicu oleh server yang dijalankan dari instans viewer yang sama

Dua batasan patut disebutkan secara jujur. Pertama, TPDFlibViewer adalah kontrol VCL Windows; lapisan viewer dikecualikan dari build NOVCL, sehingga layanan konsol dan target non-VCL harus menggunakan API rendering TPDFlib dasar secara langsung. Kedua, penggunaan tanpa kepala (headless) didukung dengan sengaja tetapi terbatas: CaptureRegion merender wilayah klien mana pun — halaman ditambah penyorotan — ke dalam bitmap milik pemanggil dan berfungsi pada kontrol tanpa induk tanpa handel jendela, karena jalur pengecatan menghindari panggilan VCL yang akan memaksa pembuatan handel. Hal ini membuat verifikasi tingkat piksel dalam pengujian otomatis menjadi praktis, tetapi apa pun yang benar-benar memerlukan loop pesan, seperti alat mouse interaktif, tetap termasuk dalam sesi antarmuka pengguna yang sebenarnya. Dari sisi kinerja, kontrol mempertahankan cache halaman memori dengan anggaran yang dapat dikonfigurasi melalui SetCacheLimit, dan dapat mempertahankan halaman yang dirender di seluruh sesi; artikel cache halaman disk viewer membahas lapisan tersebut dan perilaku DPI per monitor secara mendalam

Lima langkah singkatnya: tempatkan kontrol dan panggil LoadFromFile, lampirkan tindakan siap pakai dari PDFlibViewerActions, panggil HighlightSearchHits untuk pencarian dalam halaman, tangani OnAnnotClick untuk alur kerja anotasi, dan ekspos PrintDoc. Setiap bagian yang ditampilkan di sini disertakan dalam losLab PDF Library standar untuk Delphi, di mana kontrol viewer, kelas tindakan, and mesin rendering diinstal bersama-sama