Ingin mem-parsing PDF?
(eliot-jones.com)- Parsing PDF idealnya bekerja berdasarkan urutan dan struktur yang jelas, tetapi file nyata sering kali tidak mengikuti spesifikasi ini
- Berbagai error dan ketidaksesuaian muncul saat mencari pointer cross-reference (xref) dan offset
- Dalam praktiknya, banyak masalah muncul karena data yang tidak perlu sebelum header PDF atau posisi pointer dan offset yang salah
- Ada juga banyak kasus ketika tabel xref PDF itu sendiri tidak jelas atau salah format
- Karena itu, viewer utama menambahkan implementasi logika tambahan untuk mendukung file PDF nonstandar
Pendekatan ideal terhadap parsing PDF
- Secara teori, parsing PDF berjalan melalui langkah-langkah yang tetap
- Mencari komentar header versi di awal file
- Mencari pointer cross-reference (xref)
- Mengumpulkan semua offset objek
- Mencari dictionary trailer untuk mengakses keseluruhan struktur katalog
Pengenalan objek PDF
- Objek PDF adalah unit yang membungkus dan menyimpan berbagai elemen PDF seperti angka, string, dictionary, dan lain-lain
- Setiap objek berada di antara marker "
obj/endobj" - Objek saling terhubung melalui referensi tidak langsung (indirect reference, misalnya: "16 0 R")
- Cara objek dipisahkan di dalam file bersifat bebas, tetapi beberapa jenis objek wajib berupa referensi tidak langsung
Mencari offset cross-reference
- Dalam struktur PDF terdapat tabel cross-reference (xref), yang berfungsi sebagai indeks lokasi objek
- Di akhir file, posisi byte tertentu dinyatakan sebagai pointer melalui sintaks "startxref"
- Pointer ini menunjuk lokasi xref, tetapi ada perbedaan antara spesifikasi dan file nyata. Misalnya, marker "%EOF" seharusnya berada di baris terakhir, tetapi pada PDF dunia nyata bisa berada di mana saja dalam 1.024 byte terakhir
- Pada file nyata ditemukan berbagai variasi seperti kesalahan format pointer (
startrefdan sebagainya), tidak adanya line break, dan lain-lain
Mencari offset objek
- Tabel xref terdiri dari "xref", nomor awal objek, dan jumlah objek secara berurutan, lalu offset/generation number/status tiap objek (
natauf) dicatat per baris - Tabel xref bisa berjumlah lebih dari satu, atau saling terhubung melalui entri
/Prev
Menelusuri lokasi dictionary trailer
- Di atas marker startxref terdapat dictionary trailer, yang berisi metadata penting untuk menemukan objek root
- Berdasarkan objek root, interpretasi seluruh struktur dapat dimulai
Lingkungan nyata: masalah-masalah tak terduga
-
Banyak file yang tidak mematuhi spesifikasi PDF, sehingga sulit ditangani dengan parser umum
-
Kasus kegagalan yang umum saat menelusuri pointer cross-reference
- Pointer tidak berada di akhir file atau 1.024 byte terakhir
- Salah ketik (
startrefdan sebagainya) - Format yang tidak lazim
-
Dalam investigasi terhadap 3.977 sampel PDF nyata, sekitar 0,5% memiliki kesalahan deklarasi xref
Konten PDF dimulai pada offset yang bukan 0
- Jika ada data sampah (junk) sebelum header, semua offset byte akan bergeser sehingga posisi startxref menjadi meleset
- Offset harus dihitung ulang berdasarkan posisi header, dan kedua posisi perlu diperiksa
- Ini mencakup sekitar 50% dari seluruh error
Pointer xref menunjuk ke tengah tabel xref
- Offset yang ditentukan bisa saja bergeser ke tengah isi tabel xref
- Ditemukan pada sekitar 5 dari 3.977 sampel
Pointer berada di dekat xref
- Sering kali pointer tidak tepat, tetapi hanya meleset sebesar spasi atau karakter newline tepat sebelum atau sesudah xref
Pointer benar, tetapi offset xref salah
- Offset yang tercatat di tabel xref itu sendiri bisa salah
- Sebagian objek mungkin benar, sementara sisanya memiliki error offset
Pointer pertama normal, tetapi offset sebelumnya (/Prev) aneh
- Ada banyak kasus ketika pointer
/Prevyang dibuat saat PDF dimodifikasi menyimpan nilai yang salah (misalnya 0)
Format tabel xref tidak normal
- Ada berbagai kasus seperti
"xref"dan angka yang menempel tanpa line break, jumlah entri yang lebih banyak daripada objek yang dideklarasikan, atau data sampah di tengah tabel - Kasus-kasus seperti ini banyak dilaporkan sebagai issue di PdfPig dan lainnya
Kesimpulan
- Menurut spesifikasi, parsing PDF seharusnya diproses dalam urutan yang terstruktur, tetapi banyak file nyata tidak seperti itu sehingga berbagai masalah parsing pun muncul
- Viewer PDF untuk penggunaan nyata pada dasarnya menyertakan fitur untuk memperluas dukungan terhadap PDF nonstandar
- Ringkasan kali ini hanya membahas sebagian parsing yang termasuk dalam spesifikasi PDF (22 halaman dari total 1300 halaman)
5 komentar
Ringkasan kali ini hanya membahas parsing sebagian kecil dari spesifikasi PDF (22 halaman dari total 1300 halaman) <- ... 1300 halaman, luar biasa sekali...
Wow..
PDF, terus terang saja, adalah format yang ramah untuk dibaca manusia karena sebisa mungkin mempertahankan tata letak buatan manusia, dan benar-benar buruk untuk dipadukan dengan mesin.
Saya paham. Sebenarnya, saya juga tidak yakin apakah itu nyaman dibaca.. Terlalu berat dan tidak praktis.
Komentar Hacker News
Jawabannya jelas
Dalam praktiknya, nama saya Geoff, tetapi setengah dari parser resume mengenali nama saya secara terpisah sebagai "Geo" dan "ff"
Ini terjadi karena cara teks dimasukkan ke dalam PDF, dan masalah ini terus muncul dari berbagai aplikasi sumber
Parsing PDF dan parsing konten PDF adalah dua hal yang sepenuhnya berbeda
Parsing file PDF saja sudah merepotkan, tetapi karena PDF sendiri berbasis "menaruh sesuatu di posisi tertentu", bukan teks yang terdefinisi jelas di dalam kotak pembatas, untuk mengekstrak kata Anda harus menebak huruf mana yang termasuk bersama
Jika ingin membantu parser resume, ada baiknya memperhatikan accessibility tree
Tidak semua renderer PDF mengekspor PDF aksesibel, tetapi PDF aksesibel setidaknya bisa membantu membaca hal seperti nama dengan benar
Masalah "ff" kemungkinan karena analis resume tidak bisa menangani karakter non-ASCII, misalnya ligatur
ffRenderer PDF bisa diatur agar tidak membuat ligatur, tetapi ini bisa membuat tampilan teks jadi jelek
Rasanya terlalu banyak berharap pada kata "should"
Kalau penggunaan PDF pada kenyataannya cukup bersifat memusuhi, sepertinya orang tidak akan berpikir sejauh itu
Salah satu tujuan mengirim resume sebagai PDF memang agar perantara di tengah tidak bisa mengubahnya, dan "pengeditan" juga punya banyak alasan lain, seperti menutupi sesuatu dengan kotak di atas gambar, atau membuat tabel sebagai PDF alih-alih CSV agar lebih sulit dianalisis
Sebenarnya pendekatan ini kadang memang bekerja dengan baik, dan beberapa aplikasi sudah menggunakannya
Hanya saja, masalah dua representasi (isi/metadata) yang tidak benar-benar cocok tetap ada
Ada juga pertanyaan tentang bagaimana dengan hasil scan tulisan tangan atau dokumen hasil scan lain jika scanner dan komputer rumahan biasa tidak punya dukungan OCR yang sempurna
Mungkin masalahnya memang karena ff dirender sebagai ligatur
Saya pendiri Tensorlake
Kami membuat API parsing dokumen untuk developer
Inilah alasan pendekatan Computer Vision benar-benar bekerja di lapangan untuk parsing PDF
Hanya bergantung pada metadata di dalam file tidak skalabel untuk beragam sumber PDF
Jadi pendekatannya adalah mengubah PDF menjadi gambar, lalu menerapkan model pengenalan layout terlebih dahulu, kemudian menjalankan model khusus seperti pengenalan teks dan tabel, lalu menggabungkan potongan-potongannya, sehingga menghasilkan output yang layak dipakai bahkan di bidang yang menuntut akurasi tinggi
Sekilas pendekatan ini terlihat konyol, tetapi sebenarnya terasa seperti solusi yang paling realistis
PDF pada dasarnya dirancang untuk merepresentasikan layout yang dibaca manusia, bukan format yang dirancang agar bisa dibaca komputer, melainkan format yang berfokus pada tampilan yang bagus
Karena itu, pendekatan yang meniru cara manusia membaca terasa masuk akal
Meski begitu, tetap disayangkan bahwa selama lebih dari 30 tahun PDF belum berhasil menambahkan keterbacaan mesin
Saya penasaran insentif apa yang kurang sehingga hal ini tidak pernah terwujud
Kalau ada yang punya wawasan soal ini, saya ingin mendengarnya
Ada sisi yang agak lucu
Mencetak PDF, memindainya, lalu mengirimkannya lewat email terasa seperti sesuatu yang pantas ditertawakan, tetapi dalam parsing PDF kita pada dasarnya melakukan hal yang sama
Kenyataan bahwa pendekatan seperti itu diperlukan memang membuat frustrasi
Dunia tidak mem-parsing HTML seperti itu
Saya salah satu pendiri Nutrient.io, sudah lebih dari 10 tahun menangani PDF
Seperti browser web, viewer PDF harus menerima PDF dengan variasi yang sangat besar
Karena PDF sudah sangat tua, pembuat file sering melakukan modifikasi sembarangan selama tampilannya baik-baik saja di viewer yang mereka pakai
Karena itu perusahaan kami membuat AI document processing SDK (REST API yang menerima PDF sebagai input dan mengembalikan data terstruktur dalam JSON)
Bukan hanya metode visual, dengan pengalaman pada preprocessing/postprocessing struktural kami bisa memberi hasil yang lebih baik baik dari sisi performa maupun biaya dibanding pendekatan vision murni
Jika Anda tidak ingin repot memikirkan pemrosesan PDF secara langsung dan ingin fokus pada pekerjaan inti Anda, ini mungkin bisa membantu
https://www.nutrient.io/sdk/ai-document-processing
Mumpung ada ahli struktur internal PDF di sini, saya punya pertanyaan
Saya penasaran kenapa mupdf-gl (setidaknya pada desktop Linux standar) jauh lebih cepat daripada semua program lain
Kecepatan pencarian pada PDF besar terasa jelas lebih unggul, dan saya selalu penasaran kenapa viewer lain tidak bisa secepat ini
Kalau ada wawasan terkait, saya ingin mendengarnya
Pada akhirnya, Anda hanya mengalihdayakan pekerjaan parsing ke perangkat lunak yang dipakai saat merender PDF menjadi gambar
Sudah lama saya berpikir bahwa kita perlu keluar dari komunikasi dokumen yang terlalu berpusat pada layout
Artinya, layout yang dipoles secara profesional itu sendiri sebenarnya lebih mirip kebiasaan lama, dan hampir tidak berhubungan dengan pemahaman terhadap konten yang sebenarnya
Misalnya, dokumen yang dikirim ke berbagai lembaga regulator sering kali sangat tebal, dan untuk memenuhi aturan layout Anda akhirnya menghabiskan banyak waktu bekerja di Microsoft Word
Untuk menjamin layout seperti ini, dokumen dikirim dalam format DOCX atau PDF, tetapi format-format ini sangat tidak cocok untuk program yang ingin mengekstrak atau mengolah isinya secara otomatis
LLM memang bisa membaca file-file ini, tetapi biaya komputasinya jauh lebih besar dibanding file yang sederhana dan ramah mesin seperti teks, markdown, XML, JSON, dan sebagainya
Sebagai alternatif, saya membayangkan kemungkinan menstandarkan format sederhana yang benar-benar 'machine-first' dan 'content-first' (misalnya berbasis JSON, XML, HTML)
Cukup punya struktur minimal dan informasi embed gambar, lalu saat dibaca manusia, viewer app yang menyusunnya ulang agar enak dilihat
Pemrosesan mesin akan jauh lebih mudah
Meski format serupa seperti HTML/browser dan EPUB sudah ada, saya rasa sekarang waktunya menggantikan cara klasik
Saya berharap revolusi LLM mendorong arah ini, dan semoga parsing PDF mahal nantinya hanya tersisa di pipeline lama
Saya belum pernah membuat parser DOCX, tetapi karena DOCX berbasis XML dan tidak semua hal dipakukan ke koordinat absolut kecuali layout ditentukan secara eksplisit, dugaan saya jika JPEG nilainya 0, PDF 15, dan markdown 100, maka DOCX mungkin sekitar 80 dari sisi kemudahan
Menurut saya ini rangkuman yang sangat bagus, dan ada poin tambahan yang menarik bagi saya
Rantai incremental-save: offset
startxrefpertama baik-baik saja, tetapi tautan/Prevyang ditambahkan berulang kali setiap kali Acrobat mengubah file sering menunjuk beberapa byte lebih pendek dari xref berikutnyaKebanyakan viewer (bahkan PDF.js, MuPDF, dan Adobe Reader) akan secara bodoh mencari token
objdi seluruh file dan membangun ulang tabel baru, sedangkan parser yang taat spesifikasi justru meledakJika Anda ingin menangani dokumen di dunia nyata yang telah dimodifikasi berulang kali oleh berbagai aplikasi, jalur pemulihan seperti ini wajib ada
Referensi sebelumnya, atau salah satu elemen dalam rantainya, sering menunjuk ke offset di luar file, offset 0, atau nilai yang salah
Alasan saya menulis artikel itu adalah karena saya sedang merombak logika parsing awal di proyek saya, PdfPig
Awalnya saya mem-porting kode Java PDFBox, tetapi saya ingin membuatnya lebih cepat dan lebih sederhana
Logika baru akan memindai seluruh file jika ada satu saja tabel/stream xref yang terlewat, dan pada jalur pemulihan hanya mempercayai offset tersebut
Namun hasilnya jelas lebih lambat dari sebelumnya, dan saya sulit yakin apakah perubahan ini benar-benar layak
Saya sedang menelusuri berbagai kasus aneh (edge case) dengan test set berisi 10.000 file
https://github.com/UglyToad/PdfPig/pull/1102
Rasanya ini akan mudah jika ada asumsi yang bekerja dan parser objek PDF yang memadai, tetapi kenyataannya sama sekali tidak begitu
Situasi ini seperti neraka PDF
PDF bukan spesifikasi, melainkan kesepakatan sosial, semacam 'vibes'
Semakin Anda berjuang, semakin dalam Anda tenggelam, dan sekarang rasanya kita semua hidup di rawa yang jauh dari pandangan Tuhan
Saya tertawa membaca ini
Untuk pertanyaan "Ingin mem-parsing PDF?", saya bisa mengatakan dengan tegas: sama sekali tidak
Alasannya dijelaskan dengan baik di tulisan aslinya
Saya berharap bank saya menyediakan dokumen dalam format yang lebih mudah dibaca, tetapi sampai saat itu ya mau bagaimana lagi
Saya sudah pernah melakukan kesalahan itu, dan tidak berniat mengulanginya
Sebagai orang yang pernah menulis parser PDF, menurut saya PDF itu format yang benar-benar aneh
Sepertinya desain dasarnya sebagai campuran biner dan teks yang melahirkan banyak keanehan ini
Masalah offset xref yang sedikit meleset kemungkinan juga berasal dari bug saat menangani konversi line ending LF/CR
Salah satu hal yang tidak disebut di tulisan adalah bahwa PDF modern (v1.5+) sering disimpan sebagai "xref stream" tanpa tabel xref teks biasa
Pada v1.6 ke atas, objek itu sendiri juga bisa disimpan di dalam object stream
Awalnya terlihat tidak masalah, tetapi begitu objek yang Anda cari ternyata ada di dalam stream, dan stream itu sendiri memakai varian kompresi PNG, atau offset berada di xref stream yang dikompresi flate, segalanya jadi merepotkan
Ditambah lagi berbagai versi dokumen bercampur, sehingga menentukan bagian mana yang paling mutakhir juga rumit
Dokumen PDF 1.7 mudah ditemukan, tetapi sampai dua tahun lalu materi spesifikasi PDF 2.0 masih berada di balik paywall
PDF bukan format yang mempertimbangkan streaming
Karena ada trailer dictionary di bagian akhir, file sulit diparsing sebelum seluruhnya dimuat
Meski begitu, ada juga "streaming-capable PDF", jadi jika informasi yang dibutuhkan ada di bagian awal, halaman pertama bisa langsung dirender tanpa mengunduh seluruh file, walau sisanya belum tentu
Sudah agak lama saya jauh dari dunia PDF, jadi mohon dimaklumi
Meski ada footer, selama situs web mendukung Range Request dan menggunakan header Content-Length dengan benar, PDF tetap bisa di-stream
Reader streaming cukup melakukan permintaan HEAD, lalu meminta beberapa ratus byte terakhir file untuk mendapatkan pointer dan tabel, setelah itu melanjutkan mengambil sisanya
Ini memang tidak cocok untuk PDF yang dibuat secara real-time, tetapi untuk web server yang cukup tua pun tambahan 1-2 round trip saja sudah cukup
Memang sayangnya jarang ada yang benar-benar memperhatikan parser berbasis Range per file, tetapi secara teknis ini bukan sesuatu yang mustahil
Betul, ada format bernama Linearized PDF yang dirancang agar halaman pertama bisa ditampilkan cepat tanpa harus mengunduh seluruh file
Perlu diketahui bahwa dalam ringkasannya, pendekatan itu dihilangkan karena membutuhkan banyak penjelasan tambahan
Salah satu proyek pertama yang saya coba setelah belajar Python adalah parser PDF
Tujuannya mengekstrak peta secara otomatis untuk kampanye DnD, tetapi hasilnya gagal total, haha
Saya pernah menulis reader TIFF
TIFF juga terkenal sebagai format yang mudah ditulis tetapi sulit dibaca
Sepertinya PDF masuk ke kategori yang sama