Artikel Teknis

HotPDF Delphi Component Delphi TextOut: penempatan teks PDF

Setiap string yang terlihat dalam dokumen HotPDF tiba melalui satu panggilan: TextOut(X, Y, angle, Text). Contoh Hello World menggunakannya pada bentuk paling polosnya, font disetel sekali dan empat argumen dibiarkan pada default yang masuk akal. Melewati halaman pertama itu empat argumen yang sama membawa seluruh bobot tata letak. Argumen ketiga memutar run. Font yang disetel tepat sebelumnya memutuskan ukuran dan gaya. Dan pasangan X, Y, diukur dari sudut halaman dalam poin, adalah satu-satunya yang berdiri di antara laporan yang bersih dan teks yang tumpang tindih, terpotong, atau menyimpang satu baris lebih rendah di printer orang lain. Di sinilah TextOut mendapat nilainya, dan di sinilah default berhenti cukup

Tanda tangan layak diingat sebelum hal lain: X dan Y adalah Single dalam poin, angle adalah Extended dalam derajat, dan Text adalah WideString, sehingga Unicode lewat tanpa panggilan terpisah. Overload kedua mengambil PWORD ditambah panjang untuk saat Anda sudah memegang kode glyph, tetapi untuk string biasa bentuk WideString adalah yang Anda jangkau

Ukuran dan gaya datang dari SetFont, bukan TextOut

TextOut tidak punya parameter ukuran. Ukuran, bobot, kemiringan, semuanya hidup dalam panggilan SetFont yang mendahului run, dan tetap berlaku sampai SetFont berikutnya menggantikannya. Itu satu fakta yang menjelaskan sebagian besar kebingungan hari-pertama: sebuah baris keluar tebal karena tiga panggilan sebelumnya sesuatu menyetel [fsBold] dan tidak ada yang membersihkannya

Pdf.CurrentPage.SetFont('Times New Roman', [], 24);
Pdf.CurrentPage.TextOut(72, 740, 0, 'Quarterly Report');        // 24pt regular

Pdf.CurrentPage.SetFont('Times New Roman', [fsBold], 12);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Revenue');                 // 12pt bold

Pdf.CurrentPage.SetFont('Times New Roman', [fsItalic], 11);
Pdf.CurrentPage.TextOut(72, 694, 0, 'figures in thousands');    // 11pt italic

Pdf.CurrentPage.SetFont('Courier New', [fsBold, fsItalic], 10);
Pdf.CurrentPage.TextOut(72, 676, 0, '  +18.4% YoY');            // styles combine

Argumen kedua adalah himpunan TFontStyles, jadi [fsBold, fsItalic] adalah tebal miring dan [] adalah polos. Ukuran dalam poin, unit yang sama dengan koordinat, yang membuat spasi vertikal mudah dipikirkan: baris 12-poin menginginkan kira-kira 14 sampai 16 poin langkah vertikal untuk bernapas, jadi menurunkan Y sebesar 14 per baris adalah leading awal yang wajar. Tidak ada kemajuan baris otomatis. Anda menghitung setiap baseline sendiri, yang melelahkan untuk paragraf tetapi tepat untuk formulir, di mana setiap field duduk di koordinat tetap

Dua catatan praktis tentang nama font. Itu diselesaikan terhadap font yang dipasang di mesin build, dan apa pun yang dikembalikan OS yang menjadi tersemat, jadi nama yang terselesaikan di desktop Anda dan nama yang terselesaikan di server build tidak dijamin wajah yang sama. Dan font harus mencakup skrip dalam string. Run teks Cyrillic atau CJK di bawah wajah Latin-saja terender sebagai kotak glyph-hilang tanpa kesalahan, yang menjadi alasan halaman Hello World menjangkau wajah Unicode luas saat mencampur bahasa

Halaman TextOut HotPDF yang menunjukkan Arial, Times New Roman, dan Courier New dirender dengan gaya regular, bold, dan italic melintasi beberapa set karakter

Argumen sudut berputar di sekitar jangkar

Argumen ketiga adalah yang paling banyak kode dibiarkan di nol selamanya. Berikan nilai bukan-nol dan run berputar berlawanan-jarum-jam tentang jangkar (X, Y)-nya sendiri, kiri-bawah teks, sebanyak derajat itu. Jangkar itu sendiri tidak bergerak, jadi koordinat yang sama yang menempatkan label horizontal menempatkan kembarannya yang diputar; hanya arah glyph berbaris yang berubah

Diagram geometri rotasi TextOut HotPDF: run pada 0, 45, dan 90 derajat berporos berlawanan arah jarum jam di sekitar jangkar kiri-bawah yang tetap, dengan contoh pemanggilan TextOut Delphi untuk label punggung, watermark, dan header kolom miring
Sudut tak nol memutar run berlawanan arah jarum jam mengelilingi anchor kiri-bawahnya yang tak bergeser, dan baseline bersama melangkahkan X persis seperti baris horizontal melangkahkan Y
Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);

// Label sumbu vertikal di margin kiri: 90 derajat terbaca dari bawah ke atas
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');

// Watermark DRAFT diagonal melintasi badan halaman
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');

// Header kolom dimiringkan 60 derajat agar label panjang muat di tabel sempit
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');

Sembilan puluh derajat adalah kasus umum, label berjalan ke atas sisi bagan atau judul punggung. Empat puluh lima derajat menangani tajuk kolom miring, trik yang membiarkan label lebar duduk di atas kolom sempit tanpa tumpah ke tetangganya. Rotasi tidak mengubah bagaimana jangkar ditafsirkan, yang menjebak orang: run 90-derajat masih dimulai di (X, Y) dan tumbuh ke atas dari sana, jadi untuk memusatkan label yang diputar Anda menyesuaikan jangkar, bukan sudutnya. Saat beberapa run diputar berbagi baseline, beri mereka Y yang sama dan langkah X, persis seperti Anda melangkah Y untuk baris horizontal bertumpuk

Menempatkan koordinat tanpa menebak

Koordinat adalah bagian yang bertahan tinjauan atau diam-diam gagal. HotPDF mengukur dari sudut kiri-bawah halaman, Y tumbuh ke atas, dalam poin pada 72 per inci. Halaman US Letter adalah 612 kali 792 poin; A4 adalah 595 kali 842. Margin atas satu-inci pada Letter karena itu menempatkan baseline pertama Anda dekat Y = 792 dikurangi 72 dikurangi ukuran font, bukan di beberapa angka kecil dekat atas. Siapa pun yang tiba dari koordinat layar, di mana Y tumbuh ke bawah dari nol, menulis baris pertama di luar tepi bawah dan menghabiskan sepuluh menit bertanya-tanya ke mana perginya

HotPDF: Diagram halaman US Letter yang menunjukkan aritmetika baseline dengan LeftMargin 72, TopBaseline 720, dan Leading tetap yang melangkah menuju dasar margin bawah di Y 72, di samping loop tata letak konstanta-bernama dengan guard AddPage manual dan reset SetFont-nya
Anchor bernama mengubah kolom magic numbers menjadi aritmetika: kurangi baseline berjalan sebesar Leading setiap baris dan jagalah lantainya sendiri dengan AddPage

Perlakukan tata letak sebagai aritmetika terhadap jangkar bernama alih-alih kolom angka ajaib. Margin kiri, baseline berjalan yang Anda kurangi per baris, dan leading tetap mengubah blok label menjadi loop pendek alih-alih dinding literal:

const
  LeftMargin = 72;        // 1 inch in
  TopBaseline = 720;       // baris pertama, sekitar 1 inci ke bawah pada Letter
  Leading = 16;            // jarak vertikal antarbaris
var
  Y: Single;
  Line: string;
begin
  Pdf.CurrentPage.SetFont('Arial', [], 11);
  Y := TopBaseline;
  for Line in ReportLines do
  begin
    Pdf.CurrentPage.TextOut(LeftMargin, Y, 0, Line);
    Y := Y - Leading;
    if Y < 72 then            // margin bawah tercapai
    begin
      Pdf.AddPage;
      Pdf.CurrentPage.SetFont('Arial', [], 11);  // font direset pada halaman baru
      Y := TopBaseline;
    end;
  end;
end;

Penjaga pemutusan-halaman adalah baris yang pertama dilupakan semua orang dan paling keras menbran. Tidak ada tata letak aliran di bawah TextOut. Kurangi melewati margin bawah dan teks terus menggambar ke selokan, keluar halaman, ke ketiadaan, tanpa peringatan. Jadi Anda mengawasi Y sendiri, memanggil AddPage saat melintasi lantai, dan mereset baseline. SetFont setelah AddPage bukan isian opsional: font saat ini tidak bertahan pemutusan halaman, dan run pertama di halaman baru keluar dalam wajah default penampil jika Anda melewatkannya

Spasi karakter dan kata untuk pencocokan dan perapian

Kadang sebuah string benar tetapi lebarnya salah: tajuk yang harus membentang aturan tetap, kode yang harus terbaca dengan digit lebih lapang, kolom yang perlu nilainya didorong untuk rapat. PDF membawa dua operator status-teks untuk ini, character spacing (Tc, ruang ekstra ditambahkan setelah setiap glyph) dan word spacing (Tw, ruang ekstra ditambahkan di setiap karakter spasi), dan keduanya dinyatakan dalam unit text-space tidak diskalakan, efektif poin pada ukuran font saat ini. Mereka adalah status, bukan argumen ke TextOut, jadi Anda menyetelnya, menggambar, dan menyetelnya kembali

HotPDF: Spasi karakter Tc yang menyebarkan ruang ekstra merata setelah setiap glyph SUMMARY versus spasi kata Tw yang mengumpulkannya hanya pada karakter spasi, tersambung ke siklus set, draw, reset yang menjaga status spasi tak bocor ke paragraf berikutnya
Tc menyebarkan penyesuaiannya ke setiap glyph sementara Tw hanya bertindak pada karakter spasi, dan reset di baris berikutnya menjaga drawing state tetap bersih
// Atur jarak huruf heading pendek agar membentang sepanjang garis
Pdf.CurrentPage.SetCharacterSpacing(4);
Pdf.CurrentPage.SetFont('Arial', [fsBold], 14);
Pdf.CurrentPage.TextOut(72, 740, 0, 'S U M M A R Y');
Pdf.CurrentPage.SetCharacterSpacing(0);   // reset sebelum teks isi normal

// Perlebar jarak antar kata pada satu baris lebar
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name        Department        Extension');
Pdf.CurrentPage.SetWordSpacing(0);

Word spacing hanya bertindak pada karakter spasi (kode 32), yang punya konsekuensi yang layak diketahui: ia tidak melakukan apa pun di dalam run CJK yang tidak punya spasi ASCII, dan berinteraksi aneh dengan teks yang dikodekan sebagai indeks glyph alih-alih byte. Untuk output tabular Latin itu cara murah melebarkan celah tanpa mengetik ulang string. Character spacing adalah alat yang lebih baik untuk tajuk yang harus mencapai lebar target, karena menyebarkan penyesuaian secara merata ke setiap glyph alih-alih mengumpulkannya di spasi

Reset adalah seluruh disiplin. Spasi, seperti font, adalah bagian dari status gambar halaman, dan status bertahan sampai Anda mengubahnya. Letter-space satu tajuk dan lupa menolenya, dan setiap paragraf di bawah mewarisi peregangan, yang terbaca sebagai keanehan halus-sulit-ditempatkan yang bertahan proofread kasual dan gagal yang hati-hati. Kebiasaan andal adalah menyetel nilai spasi, menggambar run yang membutuhkannya, dan menyetelnya kembali ke nol di baris berikutnya, sehingga tidak ada kode nanti yang harus tahu apa yang dilakukan bagian sebelumnya

Halaman TextOut HotPDF yang membandingkan penskalaan teks horizontal, spasi karakter, spasi kata, dan mode render fill versus stroke

Memeriksa output di mana ia benar-benar pecah

Tata letak teks gagal di mesin kedua, bukan pertama, jadi pemeriksaan yang penting terjadi jauh dari meja Anda. Buka file yang dihasilkan pada sistem tanpa set font pengembang Anda terpasang dan konfirmasi wajah yang tersemat masih merender, termasuk Latin beraksen, skrip non-Latin apa pun, dan tanda baca, dalam satu pase alih-alih mengecek karakter mudah secara spot. Pilih dan salin beberapa baris untuk mengkonfirmasi teks adalah teks nyata dan bukan kerangka, yang penting saat pencarian atau ekstraksi masuk cakupan. Beri tata letak data representatif, label Jerman terpanjang dan angka terlebar, bukan placeholder rapi, karena run yang meluap field selalu yang tidak Anda ketik dengan tangan. Dan jika halaman harus mendarat di formulir pra-cetak, cetak atau rasterisasi satu sampel dan letakkan terhadap aslinya; drift baseline seperempat-milimeter tidak terlihat di layar dan jelas di kertas

Jika Anda belum menulis satu halaman pun, mulailah dengan contoh HotPDF Hello World, yang menyiapkan dokumen, font, dan sistem koordinat kiri-bawah yang menjadi dasar semua di atas. Panggilan TextOut, SetFont, dan spasi yang ditunjukkan di sini adalah bagian dari HotPDF Delphi Component untuk Delphi dan C++Builder