HotPDF Component dapat mencari dan mengganti teks di dalam PDF yang ada dari Delphi dan C++Builder. SearchLoadedPageText dan SearchLoadedDocumentText menemukan setiap kemunculan string dengan presisi tingkat glif, dan ReplaceLoadedPageText serta ReplaceLoadedDocumentText menulis ulang bita yang cocok di tempat — asalkan setiap karakter pengganti dapat dikodekan ulang melalui font asli, sebuah batasan fisik yang dibahas artikel ini secara jujur alih-alih menyembunyikannya di catatan kaki
Permintaan di balik fitur ini selalu biasa saja. Sebuah perusahaan mengubah namanya dan tiga ribu faktur yang diarsipkan masih menggunakan nama lama. Templat kontrak dikirimkan dengan tanggal kedaluwarsa tahun lalu. Kode produk dihentikan dan setiap lembar data yang menyebutkannya memerlukan kode penerusnya sebagai gantinya. Di pengolah kata, masing-masing dari ini adalah pekerjaan tiga puluh detik. Di PDF, ini adalah masalah yang sangat sulit, dan memahami alasannya menjadi pembeda antara menggunakan API dengan baik dan mengirimkan laporan bug yang sebenarnya merupakan sitasi spesifikasi
Mengapa mengganti teks dalam PDF sangat sulit?
Mengganti teks dalam PDF itu sulit karena halaman PDF tidak berisi teks yang dapat diedit — ia berisi glif yang diposisikan. Di bawah model penampilan teks ISO 32000-1 §9.4, aluran konten menggerakkan operator seperti Tj dan TJ yang melukis urutan kode karakter pada koordinat yang ditetapkan oleh matriks teks. Kode-kode tersebut bukanlah Unicode; mereka adalah indeks ke dalam pengodean apa pun yang dinyatakan oleh font halaman, dan pemetaan kembali ke karakter yang dapat dibaca mungkin ada di CMap /ToUnicode, larik perbedaan pengodean, atau rantai pemetaan CID. Tidak ada objek paragraf, tidak ada alur teks, dan tidak ada jaminan bahwa satu kata visual disimpan sebagai satu string
Penggantian menambahkan tingkat kesulitan kedua di atas decoding: Anda harus tahu persis bita mana dari aliran asli yang menghasilkan setiap glif, sehingga Anda dapat menyambungkan bita baru ke dalam rentang tersebut dengan tepat dan tidak ada yang lain. Pengekstrak teks dapat membuang posisi bita setelah Unicode keluar. Pengekstrak tidak bisa. Itulah sebabnya HotPDF membagi pekerjaan tersebut di dua rilis — v2.251.0 membangun pelacakan offset dan lapisan pencarian, dan v2.252.0 membangun lapisan penulisan ulang di atasnya
Menemukan teks: pencarian tingkat glif dengan pelacakan offset bita
SearchLoadedDocumentText milik HotPDF menemukan setiap kemunculan kata kunci dengan mencocokkannya terhadap urutan glif Unicode yang didekodekan dari setiap halaman, bukan terhadap bita aliran mentah, sehingga kecocokan tetaplah kecocokan terlepas dari bagaimana font mengodenya. Infrastruktur di bawahnya diperkenalkan di v2.251.0: tokenizer aliran konten mencatat rentang bita StartOfs/EndOfs untuk setiap operan string — termasuk pembatas ( ) atau < > miliknya — dan setiap glif yang didekodekan membawa triple TokenIndex/ItemIndex/ByteOffset yang menunjuk kembali ke operan yang tepat, item larik TJ, dan unit kode yang menghasilkannya. Interpreter glif yang sama mendukung API ekstraksi yang dijelaskan dalam mengekstrak teks dari PDF yang dimuat di Delphi; pencarian cukup mempertahankan asal-usul (provenance) yang dibuang oleh ekstraksi
Setiap kecocokan dikembalikan sebagai rekaman THPDFTextMatch yang membawa indeks halaman, rentang glif inklusif, koordinat X/Y ruang pengguna dan lebar dari kecocokan, indeks token dan item sumber, serta teks yang cocok itu sendiri. Itu cukup untuk menggerakkan hamparan sorotan (highlight overlay), UI tinjauan, atau langkah penggantian. Pencarian yang tidak menemukan apa pun mengembalikan larik kosong daripada gagal, sehingga pola pemanggilan tetap sederhana
var
Pdf: THotPDF;
Matches: THPDFTextMatchArray;
I: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('invoices-2025.pdf') > 0 then
begin
if Pdf.SearchLoadedDocumentText('Acme Corp', False, Matches) then
for I := 0 to Length(Matches) - 1 do
WriteLn(Format('halaman %d pada (%.1f, %.1f): "%s"',
[Matches[I].PageIndex, Matches[I].X, Matches[I].Y,
Matches[I].Text]));
end;
finally
Pdf.Free;
end;
end;
Satu pilihan desain yang disengaja patut dicatat. Ketika CaseSensitive bernilai False, perbandingan hanya melipat huruf (folds case) untuk karakter ASCII saja, secara sengaja: pelipatan huruf Unicode lengkap berperilaku berbeda di seluruh toolchain Delphi 5 hingga XE yang didukung HotPDF, dan API pencarian yang menemukan kecocokan berbeda tergantung pada kompiler mana yang membangun aplikasi Anda lebih buruk daripada yang memiliki batasan yang terdokumentasi dan dapat diprediksi. Untuk teks bisnis Latin — nama, kode, tanggal — pelipatan ASCII mencakup kasus-kasus praktis
Mengganti teks: pengodean terbalik dan penyambungan bedah
ReplaceLoadedDocumentText, ditambahkan di HotPDF v2.252.0, menulis ulang setiap kemunculan kata kunci dengan menjalankan mesin decoding secara terbalik. Fungsi HPDFEncodeUnicode adalah kebalikan dari dekoder kode karakter: ia menelusuri rantai strategi yang sama secara terbalik — pencarian bfchar dan bfrange /ToUnicode, pemetaan CID aliran pengodean, pemetaan identitas Type0, dan tabel WinAnsi serta MacRoman bawaan — untuk mengubah setiap karakter pengganti kembali menjadi bita kode karakter yang diharapkan font asli. Bita yang dikodekan ulang kemudian diserialisasi menjadi string literal atau string heksadesimal yang terbentuk dengan baik, mencerminkan aturan escaping milik tokenizer sendiri sehingga putaran bolak-balik penguraian → serialisasi ulang menjadi stabil
Penyambungan itu sendiri bersifat bedah (surgical) alih-alih menyeluruh. Hanya rentang bita kode yang dicakup oleh kecocokan yang diganti di dalam operan string; bita yang tidak cocok dalam operan yang sama, spasi di antara token, dan setiap operator di sekitarnya dipertahankan secara verbatim, bita demi bita. Mengganti bca di dalam abcabc menghasilkan a + pengganti + bc, bukan operan yang rusak. Pengganti mungkin lebih pendek atau lebih panjang dari kata kunci — literal diserialisasi ulang dan /Length aliran disegarkan — dan setiap aliran /Contents dari halaman multi-aliran diproses secara terisolasi sehingga halaman tetap terbentuk dengan baik
var
Pdf: THotPDF;
ReplaceCount: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('contract-draft.pdf') > 0 then
begin
if Pdf.ReplaceLoadedDocumentText('2025-12-31', '2026-12-31',
True, ReplaceCount) then
WriteLn(Format('%d penulisan ulang operan dilakukan', [ReplaceCount]));
Pdf.SaveLoadedDocument('contract-final.pdf');
end;
finally
Pdf.Free;
end;
end;
Catat apa yang tidak dilakukan oleh API: ia tidak memformat ulang halaman. PDF tidak memiliki aliran ulang teks, sehingga pengganti yang secara visual lebih lebar dari aslinya hanya akan menempati lebih banyak ruang horizontal dan mungkin memadati apa pun yang dilukis di sebelah kanannya. Substitusi dengan panjang yang sama atau hampir sama — tanggal, string versi, nomor bagian, koreksi nama — adalah sasaran utama. Perubahan kata secara menyeluruh adalah milik dokumen sumber, bukan PDF
Mengapa Anda tidak dapat mengganti teks dengan karakter yang tidak pernah disertakan dalam subset font?
Anda tidak dapat mengganti teks dengan karakter yang tidak pernah disertakan dalam subset font tersemat, karena urutan bita yang akan memilih karakter tersebut tidak ada dalam tabel pemetaan font. Ketika produsen PDF menyematkan font subset, CMap /ToUnicode dan struktur pengodeannya hanya mencakup glif yang sebenarnya digunakan oleh dokumen asli. HPDFEncodeUnicode hanya dapat membalikkan pemetaan yang ada: jika dokumen tidak pernah berisi huruf E dalam font tersebut, tidak ada kode karakter untuk E untuk dibalikkan. Ini adalah sifat fisik file, bukan batasan pustaka tertentu — tidak ada alat yang dapat memunculkan pemetaan glif yang tidak pernah disematkan
HotPDF menangani kegagalan ini secara konservatif. Jika satu karakter dari pengganti tidak dapat dikodekan ulang, seluruh kemunculan kata kunci tersebut akan dilewati — tidak ada pengecualian, tidak ada teks sampah parsial, dan kemunculan tersebut tidak dihitung dalam ReplaceCount. Konsekuensi praktisnya: periksa ReplaceCount terhadap jumlah kecocokan dari pencarian sebelumnya, dan perlakukan kekurangan tersebut sebagai sinyal. Dalam contoh tanggal di atas, digit 6 harus muncul di suatu tempat dalam teks dokumen dengan font yang sama agar penulisan ulang berhasil — kemungkinan besar dalam faktur, tidak pernah dijamin secara umum. Ketika karakter yang Anda butuhkan tidak tersedia dan tujuannya adalah menghapus teks sensitif alih-alih mengubah kata-katanya, penghapusan konten yang sebenarnya adalah alat yang lebih baik; lihat meredaksi dan merestrukturisasi PDF yang dimuat di Delphi untuk jalur tersebut
var
Matches: THPDFTextMatchArray;
Expected, Replaced: Integer;
begin
Pdf.SearchLoadedDocumentText('Acme Corp', True, Matches);
Expected := Length(Matches);
Pdf.ReplaceLoadedDocumentText('Acme Corp', 'Apex Corp', True, Replaced);
if Replaced < Expected then
WriteLn(Format('%d kemunculan dilewati: karakter hilang ' +
'dari subset font, atau kecocokan membentang di beberapa operan',
[Expected - Replaced]));
end;
Kondisi dilewati kedua dalam pesan tersebut adalah batasan terdokumentasi lainnya: kata kunci yang membentang di beberapa operan string — misalnya Hello yang terpisah di antara item [(He)(llo)] TJ — ditemukan oleh pencarian, karena pencarian mencocokkan urutan glif yang didekodekan, tetapi dilewati oleh penggantian, karena penulisan ulang di seluruh batas operan akan memerlukan penggabungan rentang bita yang berdekatan. Pencarian-lalu-verifikasi membuat kedua batasan terlihat alih-alih senyap
Apa yang berubah dalam file saat Anda menyimpan?
Aliran /Contents yang diganti disimpan tanpa dikompresi. Aliran terkompresi FlateDecode didekompresi untuk pengeditan, dan saat HotPDF menulis bita yang dibangun kembali, ia menghapus entri /Filter aliran dan menyegarkan /Length alih-alih mengompresi ulang. PDF yang dihasilkan sepenuhnya valid dan merender secara normal di penampil utama; pertukarannya adalah file yang lebih besar untuk setiap aliran yang diedit. Untuk alur kerja batch yang memproses ribuan dokumen, anggarkan pertumbuhan tersebut atau jalankan lintasan kompresi terpisah di hilir. Bagaimana interaksi objek yang ditulis ulang dengan struktur referensi silang dokumen saat disimpan adalah topiknya sendiri, yang dibahas dalam aliran objek dan pembaruan inkremental di HotPDF
Semua hal lain tentang file dibiarkan saja. Aliran yang tidak tersentuh tetap mempertahankan kompresinya, font dan gambar tidak ditulis ulang, dan sambungan tingkat operan berarti bahkan aliran yang diedit hanya berbeda dari aslinya di tempat kecocokan mendarat. Konservatisme itu disengaja: semakin banyak bagian dokumen dimuat yang ditulis ulang oleh pustaka, semakin banyak peluang yang dimilikinya untuk merusak kekhasan produsen yang tidak diantisipasinya
Cari dan ganti teks bergabung dengan ekstraksi, redaksi, dan rendering halaman dalam rangkaian alat dokumen dimuat HotPDF, semuanya digerakkan oleh penerjemah aliran konten yang sama dan tersedia dari Delphi 5 hingga rilis RAD Studio saat ini tanpa ketergantungan eksternal. Referensi API lengkap dan unduhan uji coba ada di halaman produk HotPDF Component