PPDF123
Formats8 menit baca

Cara Kerja Penyuntingan Teks di PDF: Content Stream, Encoding Font, dan Mengapa Hanya Satu Baris per Kali

Halaman PDF tidak punya paragraf atau kotak teks, hanya instruksi untuk menggambar glif dengan sebuah font pada suatu posisi. Menyunting satu baris berarti menghapus instruksi lama dan menulis yang baru di tempat yang sama, dan itulah yang menentukan apa yang bisa dan tidak bisa disunting.

PDF123 Β· Updated 2026-10-14
Cara Kerja Penyuntingan Teks di PDF: Content Stream, Encoding Font, dan Mengapa Hanya Satu Baris per Kali

Halaman PDF tidak punya paragraf dan tidak punya kotak teks. Isinya daftar instruksi: pada posisi ini, dengan font dan ukuran ini, gambar glif-glif ini. Mengubah teks berarti menghapus instruksi yang menggambar baris itu dan menulis instruksi baru di posisi yang sama, dengan font, ukuran, dan warna yang sama. Itu sebabnya Sunting PDF menyunting satu baris per kali dan tidak bisa membungkus teks: hal itu mengikuti cara teks disimpan.

Seperti apa satu baris teks di dalam berkas

Isi sebuah halaman berada di content stream, program kecil yang terdiri dari operator. Empat operator mengerjakan sebagian besar tugas untuk teks: BT dan ET mengapit blok teks, Tf memilih font dan ukuran, Td berpindah ke posisi berikutnya, dan Tj menggambar sebuah string. Dengan font standar, kasus paling sederhana tampak seperti ini:

BT /F1 18 Tf 20 150 Td (Hello World) Tj ET

Artinya: pilih font F1 dengan ukuran 18 poin, pindah ke x 20, y 150, lalu gambar Hello World. PDF yang dicetak dari Chrome biasanya terlihat berbeda: tanda kurung tidak lagi berisi karakter melainkan nomor glif dari font, dan Tm menetapkan posisi sekali saja. Berikut baris Hello World from Georgia dari halaman yang diekspor Chrome, dengan setiap empat digit heksadesimal sebagai satu nomor glif:

BT /F4 24 Tf 1 0 0 -1 30 52 Tm <002b0048004f004f00520003003a00520055004f0047000300490055005200500003002a004800520055004a004c0044> Tj ET

002b adalah H, 0048 adalah e, 004f adalah l, 0003 adalah spasi, 003a adalah W, dan seterusnya. Nomor-nomor ini hanya bermakna di dalam satu font itu; nomor tersebut bukan Unicode. Saat Anda menyalin teks, penampil mengubah nomor itu kembali menjadi karakter lewat tabel pencarian yang disimpan di tempat lain dalam berkas.

Ada dua akibatnya. Pertama, tidak ada apa pun di dalam content stream yang menyatakan "ini paragraf": pemisah baris hanyalah Td atau Tm lain yang memindahkan posisi ke baris berikutnya, dan jumlah baris dalam satu paragraf harus disimpulkan dari posisi. Kedua, untuk menulis karakter baru ke dalam baris, Anda memerlukan nomor karakter itu di font tersebut, padahal font sering hanya memuat glif yang terpakai saat berkas ditulis. Itu hasil dari font subsetting.

Anda dapat membuka isi stream dengan qpdf:

qpdf --qdf --object-streams=disable in.pdf out.pdf

Buka out.pdf di editor teks dan cari Tj untuk melihat setiap string yang digambar di halaman. Untuk isi PDF lainnya, lihat Apa isi di dalam PDF: objek, stream, dan tabel cross-reference.

Bagaimana editor menyusun ulang "baris" dari glif

Editor lebih dulu harus mengelompokkan glif lepas menjadi baris yang bisa diklik pengguna. Glif dengan font, ukuran, dan warna yang sama, yang jaraknya dari glif sebelumnya tidak lebih dari satu ukuran font, termasuk dalam satu segmen teks yang sama; pergantian baris, font baru, atau warna baru mengakhiri segmen itu. Teks yang berjalan dari kanan ke kiri, atau vertikal, tidak dikelompokkan dan tidak bisa dibuka untuk disunting.

Dua akibat dapat diamati langsung. Baris yang mencampur dua font, misalnya baris Mandarin dengan satu kata Inggris di dalamnya, dipecah menjadi dua segmen yang berdampingan dan diklik secara terpisah. Setelah penyuntingan hal yang sama terjadi: jika teks baru memakai font lain, baris menjadi dua segmen, dan menyunting salah satunya membiarkan yang lain tidak berubah.

Menyunting satu baris: hapus teks lama, lalu tulis yang baru

Penghapusan memakai bentuk coret hitam yang khusus teks: glif di dalam area baris dibuang dari content stream, gambar dan garis dibiarkan, dan tidak ada kotak berwarna yang digambar di atas teks lama, sehingga penyalinan dan pencarian tidak lagi menemukannya. Ini hanya mengubah isi halaman; jika teks yang sama juga muncul di anotasi atau di properti dokumen, keduanya tidak terpengaruh.

Penulisan menambahkan instruksi teks baru di akhir content stream halaman, dimulai dari posisi garis dasar baris asli dan memakai ukuran serta warnanya. Setelah baris di atas diubah menjadi Hello World 2, yang ditambahkan di akhir halaman adalah:

q 1 0 0 1 22.5 148.92 cm 0 0 0 rg
/Span <</ActualText <feff00480065006c006c006f00200057006f0072006c006400200032>>> BDC
BT /F4 18 Tf 0 0 Td <002b0048004f004f00520003003a00520055004f00470003> Tj ET
BT /F9 18 Tf 102.18 0 Td (2) Tj ET
EMC
Q

BT pertama memakai font asli F4 dan nomor glif asli, sehingga Hello World dipakai ulang persis seperti semula. Angka "2" tidak ada di subset font asli, sehingga BT kedua memulai font Helvetica standar baru (F9) untuk menggambarnya. q dan Q membatasi transformasi koordinat dan warna blok ini agar hanya berlaku di dalamnya; editor juga membungkus konten asli dalam pasangan q/Q, supaya status yang tidak seimbang di akhir halaman asli tidak memengaruhi teks baru. Begitulah bentuk satu segmen; angkanya berbeda-beda tergantung berkas.

Penambahan di akhir membawa tiga akibat:

  • Teks baru digambar paling akhir, di atas semua yang lain di halaman. Teks yang tadinya berada di bawah gambar atau blok berwarna muncul di atasnya setelah penyuntingan.
  • Alat yang mengekstrak teks menurut urutan content stream (seperti pdftotext -raw) membaca baris yang disunting paling akhir di halaman itu, sedangkan ekstraksi menurut posisi (pdftotext -layout) tidak menunjukkan perubahan. Halaman terlihat sama, tetapi urutan bacanya sudah berubah.
  • Editor menyertakan ActualText pada teks baru, yang memberi tahu penampil karakter asli apa yang diwakili glif-glif itu. Satu glif bisa dipetakan ke beberapa karakter, dan pencarian hanya dari nomor glif kadang menghasilkan karakter kompatibilitas (misalnya ζ–‡ terbaca sebagai radikal Kangxi ⽂); ActualText memastikan yang Anda salin adalah yang Anda ketik.

Font mana yang menggambar teks baru

Memakai ulang font asli adalah pilihan paling aman, karena bentuk glif, ketebalan, dan lebarnya cocok dengan teks di sebelahnya. Bisa tidaknya font dipakai ulang bergantung pada apakah editor dapat mengetahui kode karakter itu di font tersebut:

  • Font komposit seperti yang di atas (Type0, nomor glif dua byte, encoding Identity-H): cari karakter di font untuk mendapatkan nomor glifnya, lalu pakai jika ditemukan. Jika tidak ditemukan, karakter itu tidak ada di subset.
  • Font sederhana satu byte (TrueType, Type1) dengan encoding WinAnsi atau MacRoman: pemetaan dari karakter ke byte bersifat tetap, dan lebar diambil dari tabel lebar di dalam berkas.
  • Font dengan encoding khusus (Differences) atau yang mengandalkan encoding bawaan font: tidak ada pemetaan yang andal, sehingga editor tidak menebak dan beralih ke font cadangan, kalau tidak teksnya akan rusak.

Bila sebuah karakter tidak ada di font asli, font cadangan dipakai. Huruf Latin biasa memakai yang terdekat dari Helvetica, Times, dan Courier, font standar yang dimiliki setiap penampil, sehingga tidak ada yang perlu disematkan. Semua selain itu, seperti aksara Han, kana, Hangul, Thai, huruf Latin beraksen, Sirilik, dan Yunani, memakai font Noto sumber terbuka: server mengambil karakter dalam permintaan lalu memotong hanya glif-glif itu dari font penuh dengan pustaka subsetting sumber terbuka HarfBuzz, biasanya beberapa KB, dan peramban menyematkannya ke berkas Anda. Bentuk regional aksara Han mengikuti bahasa antarmuka: Sederhana, Tradisional, Jepang, atau Korea.

Glif disematkan alih-alih hanya menulis nama font karena font yang dirujuk hanya lewat nama akan diganti dengan font cadangan apa pun yang dipilih tiap penampil, dan ketebalannya bisa berbeda antarpenampil; setelah disematkan, setiap penampil menampilkan bentuk yang sama.

Mengapa hanya satu baris per kali

Editor tidak punya mesin tata letak. Setiap posisi glif sudah tetap di dalam berkas; teks baru hanya ditata ke kanan dari titik awal memakai lebar font, tanpa logika "bungkus di tepi", dan tidak ada yang sesudahnya digeser. Perpanjang satu baris dan karakter tambahannya terus berjalan ke kanan, dan apa pun yang melewati tepi halaman tidak terlihat. Menulis ulang paragraf atau menambah baris pada tabel memerlukan tata letak baru, yang berarti kembali ke berkas sumber tempat PDF itu dibuat.

Lebar juga hanya lebar maju milik font itu sendiri (jarak titik tulis bergeser ke kanan setelah tiap glif), tanpa kerning dan tanpa substitusi glif. Teks yang tidak memerlukan shaping (penentuan bentuk dan posisi glif menurut konteks: Latin, Sirilik, Yunani, dan aksara Han) ditata dengan benar. Tanda nada Thai memerlukan pemosisian glif agar berada di tempat yang benar, yang tidak dilakukan editor, sehingga posisinya bisa meleset. Arab memerlukan bentuk glif yang bergantung pada konteks dan tata letak kanan ke kiri, Ibrani memerlukan tata letak kanan ke kiri, dan aksara India memerlukan konsonan dan tanda vokal digabung menjadi glif; semuanya memerlukan shaping teks penuh, yang kini belum dilakukan editor, sehingga mengetikkannya ditolak alih-alih menghasilkan karakter yang salah.

Dua batas lagi berasal dari berkas itu sendiri. Isi halaman hasil pindai adalah satu gambar tanpa operator teks, sehingga tidak ada yang bisa dihapus atau diubah. Setelah berkas bertanda tangan digital disunting, konten asli yang dilindungi tanda tangan telah berubah, dan tanda tangan tidak lagi valid.

Periksa sendiri

Anda dapat melihat perubahan yang dijelaskan di atas pada berkas yang diunduh dengan tiga perintah:

pdftotext -raw edited.pdf -      # ekstrak menurut urutan content stream: teks lama hilang, baris yang disunting paling akhir
pdffonts edited.pdf              # daftar font: font asli yang dipakai ulang, dan subset font baru yang disematkan
qpdf --qdf --object-streams=disable edited.pdf edited.qdf   # kembangkan content stream; blok BT ... ET yang ditambahkan ada di akhir

Bacaan lanjutan

Open tool
Process in the browser β€” no watermark, files removed after the job.
Open tool