Pemanggilan yang menaruh teks pada halaman PDF sangatlah langsung. Anda memberi AddText sebuah string, fonta, ukuran, dan posisi, maka glif pun muncul. Apa yang tidak dikerjakannya adalah memberitahu Anda seberapa lebar string tersebut setelah digambar, dan fungsi ini tidak memecah string panjang ke beberapa baris. Sebuah pemanggilan tunggal hanya melukis satu baris teks di satu posisi. Jika baris tersebut lebih lebar dari kolom, teks akan melampaui batas tepi tanpa peringatan. Saat Anda menginginkan sebuah paragraf, kepingan yang hilang adalah mengetahui lebar dari string diukur sebelum Anda mengirimnya ke halaman
Ini adalah masalah tata letak (layout) yang klasik. Untuk memenggal teks paragraf ke dalam suatu kolom Anda harus tahu spasi horizontal yang dibutuhkan oleh setiap kata sebelum menggambarnya. Fitur pengukuran panjang teks (text measurement) dalam komponen PDFium telah menambal kekurangan ini lewat dua fungsi, MeasureText dan MeasureTextWidth, yang melaporkan lebar ukuran suatu string tanpa perlu memberi coretan pada halaman
Mengapa fitur pengukuran ini dibuat sebagai class helper
Dukungan ukuran ini hadir sebagai class helper Delphi untuk tipe TPdf, diletakkan di unit terpisah. Fitur class helper adalah fasilitas bahasa yang mengizinkan Anda untuk menempelkan method ke tipe yang sudah ada dari luar blok deklarasinya. Sesudah unit tersebut dimasukkan ke scope, method baru itu dipanggil seolah-olah ia milik kelas tersebut, sehingga metode penolong ini dibaca sebagai Pdf.MeasureTextWidth(...) tanpa harus membentuk objek terpisah
Alasan meletakkannya seperti ini adalah separasi. Tipe inti TPdf tetap utuh, tanpa tambahan field baru, sehingga proyek yang tidak membutuhkan fitur tata letak tidak perlu memuat kode pengukuran. Proyek yang membutuhkannya cukup menambahkan unit ini ke klausa uses. Kemampuan ini menjadi opsional yang rapi untuk memperluas kemampuan sebuah tipe data tanpa mengganggu struktur intinya
uses
PDFium, FPdfView, FPdfEdit,
FPdfMeasure; // the helper unit; brings MeasureText into scope on TPdf
// With the unit in scope the methods read as members of TPdf:
var
W, H: Double;
begin
Pdf.MeasureText('Subtotal', 'Helvetica', 11, W, H);
// W and H are now the rendered width and height in PDF user units
end;
Mengukur tanpa menyentuh halaman
Proses ukur ini harus bersih dari efek samping. Ia harus melaporkan hasil lebarnya tanpa meninggalkan sisa, karena Anda memanggilnya berkali-kali selagi mengatur susunan tata letak. Teknik yang memungkinkan hal ini adalah dengan membangun suatu objek teks, menanyakan ukurannya, dan lantas membuangnya sebelum ia menempel ke sebuah halaman dokumen
Urutannya berupa empat panggilan ke PDFium. Fungsi FPDFPageObj_NewTextObj menciptakan objek teks yang mengarah ke dokumen. Fungsi FPDFText_SetText menetapkan string-nya. Fungsi FPDFPageObj_GetBounds kemudian membaca kotak pembatas (bounding box) objek tersebut. Terakhir, FPDFPageObj_Destroy menghancurkan objek tersebut membebaskannya dari memori. Yang amat krusial di sini, tidak ada satupun urutan tersebut yang memanggil API penambahan ke halaman. Objek diciptakan, ditanya, lalu dihancurkan secara terisolasi
Metode ini sangat tangguh sebab PDFium tidak memberikan info lebar yang spesifik untuk tiap-tiap karakter. Ukuran metrik glif amat bergantung pada informasi fonta, pengkodean, dan cara PDFium memuatnya. Kotak batas terluar (bounding box) suatu objek teks sejati diproses kalkulasinya langsung oleh mesin PDFium yang kelak dipakai untuk melukis teks sungguhan. Membentuk suatu objek sekali pakai dan membaca ukurannya adalah proses pengukuran paling andal yang mampu diberikan oleh pustaka PDFium
Koordinat dan unit dari hasilnya
Kotak pembatas dikembalikan sebagai empat tepi: kiri, bawah, kanan, dan atas. Lebar didapatkan dari nilai kanan dikurangi kiri, dan tinggi adalah nilai atas dikurangi bawah. Keduanya dinyatakan dalam satuan unit pengguna PDF, di mana satu unit sama dengan 1/72 inci. Tidak ada satuan perangkat maupun piksel yang terlibat di tahap ini. Lebar bernilai 36 bermakna berukuran setengah inci dari halaman, apa pun resolusi perenderan (rendering resolution) yang akhirnya nanti digunakan
Sumbu vertikal berjalan sesuai standar definisi PDF, di mana dimensi Y terus meningkat saat ke atas, sehingga itulah alasan hitungan ketinggian merupakan letak titik atas dikurangi bawah dan bukan sebaliknya. Rincian ini menjadi perhatian ketika Anda memajukan letak kursor menelusuri rentang arah bawah sebuah kolom. Pertama, ukur tinggi muatan baris, kemudian kurangi ukurannya bersumber letak dasar (baseline) saat ini demi melacak lokasi dasar untuk barisan berikutnya, lantaran bergerak memindahkan letak ke ruang dimensi alas arah bawah dari lembar tulisan bermakna angka koordinat tatanan muatan porsi Y akan bertambah nilainya menuju titik besaran angka nilai yang berkurang (smaller Y). Jika tujuan dimensi akhir lukisan penampang yang dirujuk porsi muatannya bukan medium selembar perwujudan lembaran dokumen kertas fisik sungguhan tapi sebatas penampang layar monitor (screen), segera tukar atau konversi format takaran dimensi parameter unit tatanan satuan (user units) ke wujud unit piksel dengan acuan takaran resolusi layarnya. Caranya adalah dengan mengambil porsi besaran nilainya kalikan dengan komponen ukuran porsi besaran DPI, lalu parameter dimensi lantas bagikan nilainya membaginya terhadap nominal 72, dengan begini porsi lebar tatanan dimensi titik lebar rute yang ukurannya disetel berdasar takaran parameter titik (in points) sanggup luwes purna disesuaikan disejajarkan dipadankan diselaraskan klop dengan wujud elemen rupa bentangan panjang peliputan baris sebelum putusan letak lokasi spasi pemenggalan ditentukan lokasinya
Apa yang terjadi pada inputan yang gagal (degenerate)
Metode-metodenya disusun supaya tidak menyebabkan error aplikasi berhenti. Bila urung dapati sebuah elemen rupa berkas dokumen tatanan lembar yang tengah menganga isian statusnya dibuka, atau andaikata keping wujud objek elemen benda rupa tulisan dari muatan rute rute wujud urung tak berhasil urung diracik diproses peliputan dibentuk pembuatannya dicetak purna, luaran purna hasil porsi komponen laporannya menampakkan parameter luaran kembalian komponen berisikan nominal elemen luasan dimensi murni nol (zero extent) di ranah laporannya dan bukannya menghempaskan membanting mendaratkan wujud tatanan operasi pelemparan parameter lapor sisa komponen status kesalahan rupa wujud eror kegagalan rute aplikasi komponen (exception). Keping parameter dimensi tatanan rupa rincian besaran angka ukuran nilai letak elemen parameter ukur lebar (width) beserta atribut dari besaran parameter ukuran titik penampang rentang nilai wujud dimensi ketinggian tinggi dimensi diinisialisasi nilai awal isian pada besaran nominal titik 0 persis terletak di posisi isian di bagian struktur parameter elemen wujud mula di kerangka atas, dan rupa dari tatanan dari atributnya digantikan muatannya ditimpa diganti ulang secara purna murni digantikan nilainya hanya sesudah porsi muatan dari rupa objek boks lokasi isian luaran parameter dimensi (bounding box) tuntas purna diringkus didapat terbaca dilacak ditarik purna diproses luaran kembaliannya. Karakter utusan obyek tanpa isi melompong kosong wujud rute string tanpa hampa muatan tiada urung purna (empty string), komponen absensi dokumen tiada dokumen, parameter absen wujud wujud jenis huruf tulisan dari pustaka yang urung mampu memformulasikan komponen porsi mengurai (resolve) nilainya menjadi sosok wujud objek, semuanya purna akan memberikan kembalian isian nilai 0 ketimbang melemparkan eror
Pilihan itu mempertahankan siklus ukuran tatanan perulangan wujud loop pengukuran ini jadi ringkas luwes dan pendek. Harga dari metode pola fungsi taktik pola parameter perihal tersebut bahwasanya parameter entitas wujud porsi entitas instrumen obyek si pihak peliputan program elemen pelacak instruksi (caller) disandangkan di bahunya dititipkan parameter dititipkan parameter porsi dititipkan tuntutan elemen rute diwajibkan melakukan fungsi pemeriksaan wujud pemeriksa mengecek ukuran dimensinya. Luaran lapor berisikan dimensi ukuran nilai angka lebar isian berangka dari nol merupakan instrumen obyek pertanda alarm wujud elemen indikator (sentinel), mutlak alih-alih isian rupa perihal realitas ukuran rupa fakta dari elemen dimensi rute objek tulisan utuh elemen teks. Perlakukanlah tanggapi posisikan angka 0 laksana sebagai sepotong penyampaian pelaporan dari komponen seruan isian rute pesan isian makna wujud dari tak gagal diukur (could not measure); wujud jika mengabaikan parameter instruksi wujud itu kelak membuat rupa masukan yang salah gagal tersebut luwes purna rupa melenggang akan mengacaukan desain layout Anda wujud kolom rupa diisi wujud aksara glif tumpang tindih (overlapping glyphs)
Pemenggalan kata jenis serakah (greedy) berbekal ukurannya
Dengan alat bantu ukuran panjang, porsi instruksi parameter komando pembagian tulisan (word wrap) sekadar penulisan loop sederhana wujud tipe serakah (greedy). Pecah isian elemen rupa kerangka dari elemen paragraf di isian porsi kata-kata diisikan kata, rute simpan seutas muatan parameter wujud rute fungsi baris letak di rute penampang saat isian letak baris elemen berjalannya, serta untuk porsi rupa wujud saban wujud elemen rute isian komponen rute untai keping rupa untai katanya, ukuran elemen takaran dimensinya perihal panjang porsi dimensi ruang ukuran letak dimensinya bakal diperiksa bilamana untai elemen kata ini ditambahkan ke rute posisi letak rute parameter baris rentang tersebut. Selagi dimensi bentangan rupa parameter porsi panjang ukuran rentang baris isian dari ukuran percobaan rentangan barisan (trial line) isian tatanan dari parameter dari isian rute ini urung gagal tuntas masuk melampaui menyeberang lurus batas ukur batasan letak parameter dimensi tatanan parameter ukur lebar nilai kolom rentang parameter wujud lajur rentangan rute targetnya Anda leluasa dibolehkan dipersilakan melanjutkan peruntukan tugas menambah meneruskan menggabungkan kata melanjutkannya; lantas kapan tiba saatnya tatkala kondisi dimensi ukur rentang isian porsi nilainya meledak melebihi melewati rentang porsi (overflow) di situlah momen tatanan pemanggilan komando dari isian komponen AddText purna menumpahkan membersihkan menggelar wujud isian memoleskan elemen tatanan komando penulisan mendaratkan menuntaskan peliputan (flush) barisnya di halaman letak rute dimensi posisi peliputan lembaran porsi halamannya, menyusul mengawali komando penempatan pembuatan muatan letak isian seutas parameter porsi elemen barisan rute dari komponen tatanan wujud baris rupa rentang wujud baris yang segar segar rentang baris letak baru memuat keping obyek elemen rentang isian elemen kata keping yang kelebihan porsi rentang urung tuntas masuk ukuran batas wujud yang tadi (did not fit). Pelaksanaan rutinitas elemen himpunan rutinitas akumulasi dikerjakan tuntas via MeasureTextWidth, dan rutinitas proses operasional fungsi mencetak goresan tulisan isian fungsi yang tuntas disodorkan dicoret dibubuhkan di porsi wadah letak target wadah wujud tatanan area dimensi permukaan wajah layar wujud halaman purna adalah hanya dari perihal wujud untaian parameter ukuran rute barisan porsi baris wujud dari teks baris yang sebelumnya murni telah diakui dipastikan wujud dikonfirmasi isian dijamin disahkan dipastikan lolos lolos isian dikonfirmasi (confirmed fits)
procedure WrapParagraph(Pdf: TPdf; const Para, Font: WString;
FontSize: Single; X, TopY, ColumnWidth, LineHeight: Double);
var
Words: TArray<WideString>;
Line, Trial: WideString;
I: Integer;
Y: Double;
begin
Words := WideString(Para).Split([' ']);
Line := '';
Y := TopY;
for I := 0 to High(Words) do
begin
if Line = '' then
Trial := Words[I]
else
Trial := Line + ' ' + Words[I];
// Measure the candidate line before drawing anything.
if (Line <> '') and (Pdf.MeasureTextWidth(Trial, Font, FontSize) > ColumnWidth) then
begin
Pdf.AddText(X, Y, Font, FontSize, Line); // flush the line that fit
Y := Y - LineHeight; // Y decreases going down
Line := Words[I]; // overflowing word starts next line
end
else
Line := Trial;
end;
if Line <> '' then
Pdf.AddText(X, Y, Font, FontSize, Line); // flush the final line
end;
Loop ini mengukur calon baris secara keseluruhan ketimbang mengukur tiap kata dan menjumlahkannya, sebab lebar baris tidak sama dengan jumlah lebar kata-katanya. Spasi antar kata turut berkontribusi, dan proses ukur yang menyeluruh menangkap hal tersebut secara presisi. Prinsip greedy (serakah), muatkan sebanyak mungkin kata yang diizinkan kolom dan pisahkan di batas ujungnya, merupakan prinsip yang menjembatani jarak antara komando murni AddText menjadi paragraf sejati. Pemanggilan fungsi menggambar tidak pernah menjadi hal yang sulit. Proses pengukuran sebelum menggambarlah yang sulit, dan persis kemampuan inilah yang disajikan oleh fasilitas helper tersebut
Di mana fungsi ini cocok digunakan
Pengukuran ini merupakan lapisan yang menengahi proses menyusun konten dan saat merendernya, jadi fungsionalitasnya berpadu alami bersama alur kerja pembuatan dokumen dari awal. Jika Anda menata halaman dan menempatkan teks sejak awal, pengerjaan dasarnya bisa ditemukan di menciptakan dokumen PDF dari nol bersama komponen PDFium di Delphi, di mana AddText dan pengaturan halaman diulas lengkap. Ketika fonta yang Anda ukur sama pentingnya dengan isi string-nya, karena metriknya bergantung pada tampilan (face), baca artikel menganalisa properti fonta PDF memakai PDFium di Delphi untuk mempelajari cara library ini menyajikan info fonta penentu ukuran bounding box. Keduanya bernaung pada antarmuka binding yang sama, yakni Komponen PDFium untuk Delphi dan Lazarus, di mana fungsi ukuran ini didistribusikan bersamaan dengan ragam API bagi komponen dokumen, halaman, serta teks yang diulas melintasi penjuru blog ini