Sebuah permintaan masuk: ambil batch pernyataan yang sudah dirender, tutup nomor rekening dengan kotak hitam, dan kirim dua halaman per lembar untuk menghemat kertas. Kedua tugas ini adalah operasi pada content stream PDF yang bukan dibangun oleh Anda, jadi tidak ada kanvas halaman yang ramah untuk menggambar dan tidak ada font manager yang bisa diandalkan. Anda sedang mengedit graph objek dari dokumen loaded secara langsung, dengan menambahkan operator gambar mentah ke halaman yang sudah dirancang tool lain. HotPDF menyediakan dua entry point untuk ini, dan yang lebih berisiko justru yang terlihat ringan
HotPDF adalah komponen VCL PDF asli untuk Delphi dan C++Builder. Pada round nine loaded-document API ditambahkan method yang memang membuat konten baru di halaman yang dimuat, bukan halaman baru dari nol. Dua method yang menjadi fokus di sini adalah RedactLoadedRect, yang menggambar rectangle opak di area tertentu, dan StitchLoadedPage, yang menskala satu halaman dan menempelkannya ke halaman lain. Keduanya menulis operator ISO 32000-1 §8.5 ke stream /Contents halaman. Memahami apa yang dilakukan operator-operator itu, dan sama pentingnya apa yang tidak dilakukannya, menjadi bedanya tool yang benar dan potensi kebocoran data
Menambahkan operator ke halaman yang dimuat
Saat Anda membangun halaman dengan API HotPDF normal, komponen mengontrol content stream dan menserialisasi TextOut serta operasi vektor untuk Anda. Pada halaman loaded berbeda: /Contents adalah stream objek yang sudah ada, kadang dipakai bersama, kadang dalam bentuk array stream. Anda harus menempel ke sana tanpa merusak konten lama. Round nine menambahkan tiga helper agar aman. NewIndirectStream mengalokasi stream baru THPDFStreamObject kosong dengan /Length 0, ResolveLoadedStream menelusuri referensi tidak langsung sampai stream sebenarnya, dan AppendLoadedStream menulis byte mentah di akhir stream lalu menulis ulang /Length agar objek tersimpan valid
Alur publik untuk kedua method sama. Temukan /Contents halaman, resolve ke stream, dan jika tidak ada stream yang bisa digunakan, buat lalu sambungkan. Setelah itu tambahkan operator. Karena byte baru ditaruh di akhir stream, model painter mengarah agar ia dirender di atas konten lama. Inilah mekanisme inti untuk rectangle redaksi, dan juga alasan mengapa rectangle itu tidak seperti yang kebanyakan orang duga
RedactLoadedRect: tutup opak, bukan hapus
RedactLoadedRect menerima indeks halaman berbasis nol, empat koordinat user-space, dan tiga komponen warna pada rentang 0-1:
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('statement.pdf') > 0 then
begin
// Cover the account-number band on page 1 with solid black.
// Coordinates are PDF user space: origin bottom-left, points.
Pdf.RedactLoadedRect(0, 56, 690, 320, 706, 0, 0, 0);
Pdf.SaveLoadedDocument('statement-covered.pdf');
end;
finally
Pdf.Free;
end;
end;
Secara internal, method ini menulis tiga operator ke content stream: set warna isi di DeviceRGB (r g b rg), jalur rectangle (x y w h re), dan fill (f). Lebar dan tinggi didapat dari X2 - X1 dan Y2 - Y1, jadi Anda memberi dua sudut berlawanan lalu library menghitung ukurannya. Nilai 0,0,0 memberi bar hitam, nilai 1,1,1 memberi putih yang cocok dengan latar putih halaman. Koordinat memakai user space halaman loaded itu, artinya origin di kiri bawah dengan unit point, sehingga Anda membutuhkan /MediaBox halaman melalui GetLoadedPageBox untuk menempatkan area secara tepat
Baca ini dua kali: rectangle berisi warna menutupi konten secara visual, tetapi tidak menghapusnya. Teks, gambar, atau vektor di bawahnya masih ada di PDF, masih ada di graph objek, dan tetap bisa diekstrak siapa pun yang menyalin halaman, menjalankan text extractor, atau cukup menghapus rectangle Anda dari content stream. Ini adalah visual masking, bukan redaksi secara legal atau security. Jika Anda menyembunyikan data sensitif seperti nomor akun, rekam medis, identitas, atau informasi yang diatur regulasi, menutup dengan kotak hitam lalu mengirim file adalah potensi kebocoran yang akan ditemukan. Redaksi sejati butuh menghapus objek konten dasar, bukan melapisi tampilan
Nama method memang "Redact", dan itu memberi warning bahwa hasilnya bisa disalahpahami, bukan janji bahwa data terhapus. Implementasi menjelaskan hal ini di komentar internal: ia menyebut "visual redaction primitive" dan mencatat bahwa redaksi yang benar-benar menghapus konten perlu interpreter content-stream yang berjalan dan menulis ulang operator existing. Jalur loaded-document HotPDF tidak melakukan itu pada tahap ini. Jadi aturan aman yang bisa dipegang: gunakan RedactLoadedRect untuk masking kosmetik non sensitif, seperti menyembunyikan watermark draft, mengosongkan area sebelum screenshot, atau menutupi logo lama pada proof internal. Saat data di balik kotak itu penting jika bocor, method ini bukan jawaban, gunakan ulang document tanpa data tersebut atau pipeline content-removal yang real
StitchLoadedPage: skala, trans, gambar
N-up imposition lebih aman karena tidak menyembunyikan apa pun, hanya mengatur ulang tata letak. StitchLoadedPage menerima indeks halaman target, indeks source page, offset X/Y, dan faktor skala, lalu menggambar source page ke target pada posisi dan ukuran itu
// Overlay page 2 (index 1) onto page 1 (index 0),
// scaled to 70% and nudged up-right.
Pdf.StitchLoadedPage(0, 1, 40, 380, 0.7);
// Convenience 2-up: source page on the right half of the target.
Pdf.StitchLoadedPageSideBySide(0, 1);
String operator yang ditulisnya mengikuti urutan transform-and-paint standar: q untuk menyimpan graphics state, cm sebagai matriks skala diagonal dan translasi, /StitchSrc Do untuk memanggil external object, dan Q untuk mengembalikan state. Pasangan q/Q penting karena mengisolasi transform sehingga page hasil stitch tidak mempengaruhi sistem koordinat setelahnya. Method juga mengecek kasus-kasus umum seperti index di luar rentang, target sama dengan sumber, dan scale tak valid (<= 0) yang diklamping ke 1.0; semua itu keluar tanpa exception, jadi validasi input tetap wajib karena no-op terlihat sama dengan sukses
StitchLoadedPageSideBySide adalah wrapper tipis di atas method umum. Ia membaca lebar media-box target, membagi dua, lalu memanggil StitchLoadedPage dengan offset X setengah lebar dan scale tetap 0.5, menaruh source di sisi kanan. Skala 0.5 ini mengasumsikan lebar source dan target sama; jika tidak, hasil akan tidak mengisi setengah area dengan benar dan Anda perlu gunakan StitchLoadedPage dengan skala yang dihitung dari kedua media box
Strategi XObject sederhana dan kompromi ISO-nya
Inilah bagian implementasi yang sengaja menjadi shortcut dan harus Anda pahami sebelum mengandalkan output ke banyak viewer. N-up yang benar secara ketat biasanya membungkus content source ke dalam Form XObject, yaitu objek drawable mandiri dengan /Type /XObject, /Subtype /Form, dan /BBox sendiri. Round nine HotPDF stitch tidak membangun wrapper ini. Ia mendaftarkan dictionary page langsung ke /Resources /XObject target dengan nama StitchSrc, lalu memanggil Do. Karena page dict dan Form XObject cukup mirip pada model konten, banyak reader tetap bisa merender
Tapi ini bukan Form XObject yang sepenuhnya sesuai ISO. Ia tidak punya marker /Subtype /Form dan /BBox sendiri, sehingga pembaca yang ketat bisa mengabaikan Do atau melakukan clipping berbeda dari yang Anda perkirakan. TechnicalNotes di ronde ini menyatakan dengan jelas: pendekatan ini "render under most readers" tapi "not a strictly ISO-compliant Form XObject", dan kepatuhan penuh butuh membuat stream Form XObject nyata sebagai langkah terpisah. Karena itu anggap hasil stitch ini sama seperti konstruksi non-konform: verifikasi di viewer tujuan pelanggan, bukan hanya viewer lokal, dan jika Anda butuh PDF arsip atau lintas-validator yang ketat, jangan andalkan jalur ini. Prinsip yang sama berlaku untuk segala sesuatu yang dibangun di atas loaded object graph, sehingga PDF preflight pass in Delphi penting saat ada mutasi programmatic
Di mana kedua fitur ini cocok dan tidak cocok
Kedua method ini adalah alat content-stream, jadi model pikirannya mirip saat menggambar langsung. Jika Anda sudah membuat halaman dari nol, operator warna dan vektor di balik method ini akan terasa familiar dari HotPDF canvas drawing in Delphi; bedanya hanya bahwa di sini Anda menambahkan ke stream yang dibuat orang lain. Simpan tiga batas:
- Redaksi bersifat kosmetik.
RedactLoadedRectmenutup konten tanpa menghapusnya. Untuk data sensitif, bangun ulang sumber atau gunakan metode penghapusan konten. Kotak hitam bukan security - Stitch bersifat non-conforming secara desain. Source page direferensikan sebagai pseudo-XObject tanpa
/Subtype /Formdan/BBoxdari ISO §8.10.1, jadi verifikasi rendering di viewer target dan hindari penggunaannya bila validasi ketat dibutuhkan - Koordinat memakai user space halaman. Origin di kiri bawah, satuan poin, mengikuti media box sendiri halaman. Selalu ambil box dari halaman melalui
GetLoadedPageBoxsebelum meletakkan apa pun, karena ukuran file yang dimuat bisa berbeda dari asumsi Anda
Dalam batas itu, keduanya mengcover alur kerja nyata: menyusun ulang halaman untuk print, menutup area non rahasia, lalu menulis kembali dengan SaveLoadedDocument tanpa rendering ulang penuh. Loaded-document API yang berisi method masking dan stitching ini dikirim dengan HotPDF Component untuk Delphi dan C++Builder, bersama form field, annotation, dan method FDF pada round yang sama