Dua dokumen terbuka sekaligus, nomor halaman yang sama, masing-masing dalam panel yang dapat digulir: itulah inti dari viewer perbandingan. PDFium Component menyediakan ini melalui model objek yang mudah di mana TPdf memiliki file dan TPdfView memiliki tampilan. Satu dokumen, satu TPdf, satu TPdfView. Anda ingin tiga panel, Anda memiliki tiga pasang. Bagian yang sulit bukan panggilan API; itu adalah aritmatika tata letak ketika jendela diubah ukurannya dan logika sinkronisasi halaman ketika Anda memutuskan tampilan mana yang harus mengikuti yang mana
Form VCL menggunakan dua atau tiga TScrollBox berdampingan, masing-masing berisi TPdfView yang diatur alClient. Dua TSplitter memungkinkan lebar panel diubah saat runtime, sementara toolbar menyediakan pembukaan file, zoom, dan pilihan tampilan dua atau tiga panel
Tata letak form
Form VCL menampung tiga kontainer TScrollBox berdampingan, masing-masing dengan TPdfView di dalamnya dan disejajarkan ke alClient sehingga mengisi kotak. Dua komponen TSplitter duduk di antara kotak sehingga pengguna dapat menyesuaikan lebar kolom saat runtime. Toolbar di atas panel membawa tombol buka, kontrol zoom, dan tombol toggle dua tampilan / tiga tampilan
Mode tiga tampilan adalah boolean yang dilacak form secara internal. Ketika berubah, Anda menghitung ulang lebar dan menampilkan atau menyembunyikan kolom ketiga. Pendekatan paling sederhana adalah menghapus semua properti Align, menyembunyikan splitter, lalu mengatur posisi absolut:
procedure TFormMain.UpdateLayout;
var
TotalWidth: Integer;
begin
TotalWidth := ClientWidth;
if ThreeViewMode then
begin
ScrollBox3.Visible := True;
ScrollBox1.Left := 0;
ScrollBox1.Width := TotalWidth div 3;
ScrollBox2.Left := ScrollBox1.Width;
ScrollBox2.Width := TotalWidth div 3;
ScrollBox3.Left := ScrollBox2.Left + ScrollBox2.Width;
ScrollBox3.Width := TotalWidth - ScrollBox3.Left;
// Apply the same (ClientHeight - toolbar height) to all three Height values
end
else
begin
ScrollBox3.Visible := False;
ScrollBox1.Left := 0;
ScrollBox1.Width := TotalWidth div 2;
ScrollBox2.Left := ScrollBox1.Width;
ScrollBox2.Width := TotalWidth - ScrollBox2.Left;
end;
end;
Mengatur Align := alNone pada semua tiga kotak sebelum aritmatika integer menghindari engine constraint VCL melawan penugasan Anda. Pulihkan visibilitas splitter setelah pemosisian jika Anda ingin drag-to-resize dalam mode dua tampilan
Tinggi setiap kotak gulir adalah area klien dikurangi tinggi panel toolbar. Karena toolbar berlabuh di atas dengan alTop, ClientHeight - PanelButtons.Height memberi Anda ruang vertikal yang dapat digunakan. Tetapkan ini ke semua tiga kotak di dalam panggilan UpdateLayout yang sama sehingga tidak pernah ada frame di mana satu kotak lebih tinggi dari yang lain dan menyebabkan flicker tata letak
Membuka dokumen
Setiap pasang panel membutuhkan prosedur buka sendiri. Polanya singkat: nonaktifkan komponen, atur nama file, coba aktifkan, tangkap EPdfError jika file memerlukan kata sandi. Perhatikan bahwa TPdfView.Active yang mengontrol rendering, tetapi TPdf.Active yang sebenarnya membuka file; keduanya independen. Mengatur PdfView.Active := True ketika TPdf tertautnya belum aktif tidak berbahaya tetapi tidak menampilkan apa pun
procedure TFormMain.OpenPdfFile(PdfComponent: TPdf;
PdfViewComponent: TPdfView);
var
Password: string;
begin
if not OpenDialog.Execute then
Exit;
PdfComponent.Active := False;
PdfComponent.FileName := OpenDialog.FileName;
PdfComponent.Password := '';
try
PdfComponent.Active := True;
except
on E: EPdfError do
begin
if InputQuery('Password', 'Enter document password:', Password) then
begin
PdfComponent.Password := Password;
PdfComponent.Active := True;
end
else
raise;
end;
end;
if PdfComponent.Active then
begin
PdfViewComponent.PageNumber := 1;
SetActivePdfView(PdfViewComponent);
end;
end;
Selalu periksa PdfComponent.Active setelah penugasan; file yang rusak atau kata sandi yang salah menyebabkan pemuatan gagal secara diam-diam tanpa memunculkan pengecualian di jalur default. Mengatur PdfViewComponent.PageNumber := 1 secara eksplisit setelah pembukaan yang berhasil menghindari nomor halaman yang basi dari dokumen sebelumnya
Kode penanganan kata sandi di atas memunculkan pengecualian apa pun selain pesan kata sandi yang diketahui. Itu disengaja: Anda ingin file yang rusak atau tidak didukung muncul segera daripada ditelan sebagai panel kosong yang tenang. Pengguna yang tidak melihat apa pun tidak tahu apakah file dimuat dan hanya kosong, atau apakah komponen menolaknya. Memunculkan membuat kesalahan terlihat
Pelacakan panel aktif
Ketika pengguna mengklik di dalam panel, panel tersebut menjadi aktif. Form melacak field FActivePdfView: TPdfView privat. Umpan balik visual adalah perubahan warna border pada TScrollBox yang berisi: atur ke clHighlight untuk yang aktif dan clWindow untuk yang lain. Hubungkan ini ke setiap TPdfView.OnClick dan ke prosedur buka sehingga fokus mengikuti dokumen yang baru saja dibuka
Beberapa operasi berlaku untuk semua panel yang terlihat daripada hanya yang aktif. Boolean FAllViewsMode pada form mendorong cabang tersebut. Ketika benar, perubahan zoom dan navigasi halaman menyebar ke setiap panel yang memiliki dokumen aktif:
procedure TFormMain.ApplyZoomToAll(NewZoom: Double);
begin
if PdfView1.Active then PdfView1.Zoom := NewZoom;
if PdfView2.Active then PdfView2.Zoom := NewZoom;
if ThreeViewMode and PdfView3.Active then PdfView3.Zoom := NewZoom;
end;
Navigasi halaman tersinkronisasi
Navigasi tersinkronisasi opsional tetapi berguna untuk alur kerja revisi dokumen di mana kedua file mencakup rentang halaman yang sama. Logikanya berada dalam event handler yang diaktifkan setelah pengguna menavigasi satu tampilan. Ketika tampilan sumber mengubah PageNumber-nya, handler menyebarkan nomor tersebut ke tampilan lain, dengan satu penjaga: tampilan target harus memiliki setidaknya halaman sebanyak itu, jika tidak lewati
PageNumber pada TPdfView dan pada TPdf independen. TPdf.PageNumber melacak halaman mana yang dianggap saat ini oleh komponen dokumen; TPdfView.PageNumber melacak apa yang ditampilkan di layar. Untuk tujuan navigasi Anda ingin properti tampilan, bukan properti dokumen
Kotak centang berlabel sesuatu seperti "Sinkronkan halaman" memberi pengguna kontrol. Ketika tidak dicentang, setiap panel menavigasi secara independen dan handler keluar segera. Independensi itu penting untuk kasus penggunaan di mana dua dokumen memiliki jumlah halaman yang berbeda, atau di mana pengguna ingin menemukan bagian yang setara dalam terjemahan yang dimulai pada halaman yang berbeda. Memaksa sinkronisasi selalu akan membuat alat lebih sulit digunakan daripada susunan dua jendela desktop biasa
Satu hal yang perlu diperhatikan: mengatur PdfView.PageNumber secara programatik di dalam handler sinkronisasi itu sendiri akan memicu acara perubahan pada tampilan tersebut. Lindungi dari rekursi tak terbatas dengan flag boolean yang Anda set sebelum penugasan dan hapus segera setelahnya. Flag tersebut per-form, bukan per-tampilan, karena semua tiga tampilan berbagi handler yang sama
Zoom per panel
Setiap TPdfView membawa properti Zoom-nya sendiri, sebuah Double dalam persen di mana Zoom := 100 berarti ukuran sebenarnya (100%). Mengaturnya menggantikan FitMode aktif apa pun. Untuk tombol fit-to-width pada panel aktif, baca fit zoom dari PdfView.PageWidthZoom[PdfView.PageNumber] dan tetapkan. Untuk fit-to-page, gunakan PageZoom[PageNumber]. Keduanya adalah properti array yang diindeks oleh nomor halaman berbasis 1, jadi lindungi terhadap nomor halaman nol sebelum mengaksesnya
Ketika Anda mengekspor halaman saat ini ke gambar, baca rotasi dari tampilan tetapi panggil RenderPage pada komponen TPdf, bukan tampilan. Bentuk bitmap dari TPdf.RenderPage mengambil dimensi piksel eksplisit ditambah nilai TRotation dan set TRenderOptions. Varian fungsi mengembalikan TBitmap yang dimiliki pemanggil yang Anda bebaskan sendiri setelah menyimpan:
procedure TFormMain.SaveActiveViewAsImage;
var
Pdf: TPdf;
Bmp: TBitmap;
Jpeg: TJpegImage;
begin
if not Assigned(FActivePdfView) or not FActivePdfView.Active then
Exit;
Pdf := FActivePdfView.Pdf;
Pdf.PageNumber := FActivePdfView.PageNumber;
Bmp := Pdf.RenderPage(
0, 0,
Round(Pdf.PageWidth * 2),
Round(Pdf.PageHeight * 2),
FActivePdfView.Rotation, [], clWhite);
try
if SavePictureDialog.Execute then
begin
Jpeg := TJpegImage.Create;
try
Jpeg.Assign(Bmp);
Jpeg.CompressionQuality := 90;
Jpeg.SaveToFile(SavePictureDialog.FileName);
finally
Jpeg.Free;
end;
end;
finally
Bmp.Free;
end;
end;
Pengganda 2x pada lebar dan tinggi memberikan output yang lebih tajam untuk dokumen dengan teks halus. try/finally di sekitar bitmap free tidak opsional; pembatalan TSaveDialog masih mencapai blok finally, dan Anda ingin bitmap dibebaskan terlepas dari apa yang dilakukan pengguna
Persyaratan DLL
PDFium Component membungkus pustaka pdfium native. Proses host 32-bit membutuhkan pdfium32.dll; host 64-bit membutuhkan pdfium64.dll. Varian dengan engine JavaScript V8 menambahkan sufiks v8 dan berbobot sekitar 23-27 MB dibandingkan build standar 5-6 MB. Untuk viewer perbandingan yang menonaktifkan pengisian form (Pdf.FormFill := False), build standar non-V8 sudah cukup dan menjaga distribusi lebih kecil
Tempatkan DLL di direktori yang sama dengan executable, atau di direktori mana pun di PATH sistem. Komponen memuatnya sesuai permintaan ketika TPdf pertama diaktifkan, sehingga DLL yang hilang muncul pada saat itu daripada saat aplikasi mulai. Jika Anda menggunakan installer, pendekatan paling andal adalah menyalin DLL ke folder aplikasi selama instalasi daripada mengandalkan direktori sistem yang mungkin kemudian dibersihkan oleh administrator
Build V8 terutama berguna ketika Anda perlu berinteraksi dengan tindakan JavaScript PDF, misalnya untuk memicu field kalkulasi atau handler submit. Viewer perbandingan pasif tidak memiliki alasan untuk menjalankan JavaScript; mengatur Pdf.FormFill := False sebelum Active := True melewatkan lingkungan pengisian form sepenuhnya, yang juga berarti tidak ada engine JS yang diinisialisasi bahkan jika build standar digunakan. Itu adalah default yang benar untuk viewer read-only terlepas dari varian DLL mana yang Anda kirimkan
Untuk detail lebih lanjut tentang komponen PDFium Component dan API lengkapnya, kunjungi halaman produk Delphi PDFium Component