Saat menyerahkan dokumen beranotasi, jangan hanya menyerahkan PDF yang terlihat bersih.

Artikel ini memberikan solusi ekstraksi berlapis dan verifikasi keamanan berdasarkan PyMuPDF untuk mengatasi masalah kebingungan antara teks dan komentar, kebocoran data sensitif, dan kebingungan sistem koordinat dalam ekstraksi anotasi PDF. Kontennya mencakup prinsip lapisan data independen, contoh pemrograman defensif, pemrosesan kondisi batas, dan kriteria penerimaan manual, serta menjelaskan cara menghubungkan OmniDoc dengan benar dalam alur kerja terjemahan dokumen untuk perbandingan dan penerimaan bilingual.

Sebelum menyerahkan anotasi PDF, banyak orang akan langsung menggunakan page.get_text() untuk mengekspor teks yang tampak bersih untuk diterjemahkan, diarsipkan, atau diserahkan ke pengulas berikutnya. Namun teks ini biasanya tidak memuat anotasi. Beberapa metode ekstraksi juga akan menyisipkan komentar di tengah teks, sehingga mengganggu semantik; komentar modifikasi dan komentar sensitif di sidebar mungkin terlewatkan.

Artikel ini ditulis untuk pengembang dan pemilik dokumen yang perlu bekerja dengan PDF beranotasi. Setelah membaca, Anda akan memahami mengapa anotasi merupakan lapisan data independen, cara mengekstrak teks dan anotasi dalam lapisan, kasus tepi mana yang perlu ditangani secara defensif, dan titik penerimaan mana yang harus dikonfirmasi secara manual.

Contoh dalam artikel ini semuanya menggunakan sampel sintetis. Kode telah diperiksa sampelnya di lingkungan yang terisolasi, namun ini bukan jaminan atas semua file atau kinerja produk yang sebenarnya. Sebelum memproses dokumen penting, harap simpan dokumen asli dan tinjau sesuai dengan batasan dan item penerimaan dalam teks.

Bagaimana cara mengekstrak PDF beranotasi sebelum serah terima? Kesimpulan satu kalimat

Perlakukan teks dan anotasi sebagai dua aliran data independen dan ekstrak keduanya secara terpisah, dan lakukan tinjauan keamanan eksplisit pada konten anotasi.

situasi AndaPraktik yang direkomendasikanalasan
Hanya gunakan get_text() untuk mengekspor teksJangan menganggapnya lengkapOutput default biasanya tidak berisi anotasi
Komentar revisi dari reviewer perlu disimpanUlangi anotasi satu per satu dengan page.annots()Anotasi adalah objek independen yang dilampirkan pada halaman
Komentar mungkin berisi nomor ID dan kode internal.Cocokkan berdasarkan aturan sensitif, tandai redacted=True dan ganti dengan placeholderCatatan ulasan mungkin berisi data sensitif
Halaman diputarPertama gunakan page.rotation_matrix atau page.derotation_matrix untuk mengubah koordinatPersegi panjang anotasi berdasarkan halaman yang tidak diputar
Siap untuk proses penerjemahanBersihkan tag teks kaya terlebih dahulu, lalu periksa secara manual setelah terjemahanHindari terjemahan yang mengandung kode

Mengapa anotasi tidak bergantung pada lapisan data teks

Dalam spesifikasi PDF, aliran konten halaman (Content Stream) dan kamus anotasi (Annots Array) dipisahkan secara struktural. Badan terdiri dari instruksi tampilan teks; anotasi adalah objek independen yang dilampirkan pada halaman, dengan koordinat, jenis, dan atribut kontennya sendiri. Metode Page.annots() PyMuPDF mengembalikan generator yang melintasi daftar anotasi independen ini alih-alih aliran teks halaman.

Ini berarti Anda tidak dapat berasumsi bahwa semua teks yang Anda lihat dapat diekstraksi dengan cara yang sama.

Perbedaan antara anotasi kelas tanda dan kelas konten

  • Anotasi tag (seperti menyorot dan menggarisbawahi) tidak berisi teks itu sendiri, tetapi hanya mencatat area (Segi Empat/Persegi Panjang) yang sesuai dengan teks aslinya. Teks sebenarnya hanya dapat diperoleh dengan mencari teks melalui koordinat.
  • Anotasi konten (seperti catatan, teks bebas) memiliki string kontennya sendiri dan dapat dibaca langsung.
  • Jika Anda membaca annot.info["content"] secara langsung tanpa membedakan jenisnya, Anda akan kehilangan konteks asli yang ditunjukkan oleh anotasi kelas tag, atau mengeluarkan pengecualian jika kontennya kosong.

Contoh sintesis: ekstraksi berlapis dan intersepsi informasi sensitif

Untuk mendemonstrasikan logika pemrosesan yang benar, kami membuat skenario sintetis yang berisi tiga anotasi umum dalam kode. Masukan berikut adalah contoh yang dibuat dalam kode, bukan dari file pelanggan sebenarnya, dan hanya untuk tujuan demonstrasi pendidikan.

Output yang diharapkan berisi tiga bidang terstruktur:

  1. Fragmen teks: Hanya berisi teks asli halaman, tanpa konten anotasi apa pun.
  2. Daftar Anotasi: Setiap catatan mencakup jenis, lokasi, penulis, waktu, dan konten (jika ada).
  3. Tanda keamanan: Jika konten anotasi cocok dengan aturan sensitif yang telah ditetapkan sebelumnya (seperti nomor ID, kode internal), entri ditandai sebagai redacted=True dan konten diganti dengan placeholder.

Tiga jenis batas yang perlu dipertahankan

  • Anotasi konten kosong: Tinta (Tinta) atau anotasi grafis yang dibuat oleh beberapa pembaca tidak memiliki atribut teks. Akses langsung ke .info["content"] dapat menghasilkan string kosong atau Tidak Ada, kode harus melakukan pemeriksaan defensif dan tidak dapat berasumsi bahwa semua anotasi memiliki teks yang dapat dibaca.
  • Koordinat halaman yang diputar: Setelah halaman diputar 90 derajat, persegi panjang anotasi masih berdasarkan pada halaman yang tidak diputar. Jika Anda langsung menggunakan koordinat ini untuk memotong atau memposisikan teks, posisinya akan kacau balau, dan transformasi koordinat harus dilakukan terlebih dahulu.
  • Orphan Object: Jika dokumen ditutup atau halaman dimuat ulang selama proses traversal, objek annot saat ini akan langsung menjadi tidak valid. Semua operasi baca harus diselesaikan dalam satu halaman seumur hidup.

Implementasi Python: traversal dan verifikasi anotasi yang aman

Contoh ini menggunakan PyMuPDF untuk membuat PDF pengujian di memori, menunjukkan ekstraksi hierarki dan logika penyembunyian dasar. Pustaka yang bergantung adalah PyMuPDF (yaitu paket pymupdf). Silakan jalankan di lingkungan ketergantungan yang terkunci. Versinya harus >=1.23.0 agar dapat mengakses atribut annot sepenuhnya. Kode ini tidak melakukan operasi jaringan atau penulisan file, hanya digunakan untuk mendemonstrasikan logika.

import fitz  # PyMuPDF
import re

# 合成示例:仅在内存中构造,无需外部文件
def create_sample_pdf():
    doc = fitz.open()
    page = doc.new_page()
    # 插入正文
    page.insert_text((72, 72), "Confidential Project Alpha Report", fontsize=12)
    # 添加便签批注(含敏感信息模拟)
    page.add_text_annot((200, 72), "Reviewer: SSN 123-45-6789 approved.")
    # 添加高亮批注(无自身文本,关联正文)
    highlight = page.add_highlight_annot(fitz.Rect(72, 60, 250, 80))
    # 必须调用update()使info变更生效
    highlight.set_info(title="Editor", content="Check this term")
    highlight.update()
    return doc

def extract_with_safety(page, sensitive_pattern=r"\d{3}-\d{2}-\d{4}"):
    body_text = page.get_text("text")
    annotations = []

    # 显式遍历批注生成器
    for annot in page.annots():
        info = annot.info
        # 防御性获取内容,处理None或空字符串
        content = info.get("content", "") or ""

        # 边界处理:敏感词检测与脱敏
        is_sensitive = bool(re.search(sensitive_pattern, content))
        safe_content = "[REDACTED]" if is_sensitive else content

        annotations.append({
            "type": annot.type[1],
            "author": info.get("title", "Unknown"),
            "content": safe_content,
            "is_redacted": is_sensitive,
            # 注意:此为未旋转坐标系,若页面有旋转需配合rotation_matrix使用
            "rect": list(annot.rect)
        })
    return body_text, annotations

# 执行校验
doc = create_sample_pdf()
page = doc[0]
text, annots = extract_with_safety(page)

assert "SSN 123-45-6789" not in str(annots), "敏感信息未被拦截"
assert any(a["type"] == "Highlight" for a in annots), "标记类批注丢失"
assert len(text.strip()) > 0, "正文提取失败"
print(f"Extracted {len(annots)} annotations safely.")

Pada intinya, kode ini merupakan pemrograman defensif: kemurnian konten anotasi tidak dipercaya, dan integritas jenis anotasi juga tidak diasumsikan. Pernyataan assert digunakan untuk memverifikasi logika yang diharapkan, namun ini hanyalah demonstrasi dan tidak mewakili jaminan kinerja menyeluruh untuk semua varian PDF.

Perbandingan kategori anotasi

Jenis anotasiApakah akan membawa teks Anda sendiriCara mendapatkan kontenHal-hal yang perlu diperhatikan saat serah terima
Sorot, garis bawahiTidak, hanya area rekaman (Quads/Rects)Periksa teks menggunakan koordinatKonteks teks asli yang sesuai perlu dipertahankan
Catatan, teks bebasYa, hadir dengan string kontennya sendirimembaca secara langsungPeriksa konten sensitif
Tinta, grafik, segelSeringkali tidak ada atribut teksBuatlah keputusan singkat yang bersifat defensifKonfirmasikan secara manual apakah itu tanda tangan atau segel persetujuan

Kriteria penerimaan dan batasan tinjauan manual

Ekstraksi otomatis tidak dapat mencakup semua kasus edge. Tabel berikut mencantumkan poin penerimaan yang harus diperhatikan selama serah terima, membedakan antara cakupan yang dapat ditangani oleh kode dan skenario yang memerlukan intervensi manual.

Amati fenomenaPemrosesan tingkat kodeTinjauan manusia atau pengambilan keputusan
Isi komentarnya kosong tetapi ikonnya adaJenis rekaman adalah Tinta atau Stempel, konten dibiarkan kosongKonfirmasikan apakah itu tanda tangan atau stempel persetujuan, dan putuskan apakah akan menyimpan cuplikan gambar tersebut
Posisi komentar melebihi CropBoxKoordinatnya masih valid, namun renderingnya tidak terlihatTentukan apakah itu merupakan anotasi terbengkalai yang tersisa dari sejarah, yang biasanya dapat diabaikan.
Komentar teks kaya berisi tag HTMLEkstrak string asli, simpan tagBersihkan tag atau ubah menjadi teks biasa sebelum diterjemahkan untuk menghindari terjemahan yang mengandung kode.
Nama penulis anotasi kacauEkstrak apa adanya, tidak perlu menebak-nebak pengkodeanPeriksa metadata file sumber untuk mengonfirmasi apakah itu nama pengkodean tertentu
Utas balasan bersarangPyMuPDF mengembalikan daftar datarBangun kembali pohon dialog berdasarkan ParentID, jika tidak, konteksnya akan hilang

Tidak berlaku: Solusi ini tidak berlaku untuk PDF terenkripsi tanpa memberikan kata sandi, PDF yang rusak secara struktural, dan file yang menggunakan ekstensi pribadi non-standar untuk menentukan jenis anotasi. Dalam situasi ini, skrip mungkin secara diam-diam melewatkan atau memunculkan pengecualian C++ tingkat rendah, yang harus dikonfirmasi dengan membuka file sumber secara manual menggunakan alat profesional.

Gunakan daftar periksa untuk terjemahan dokumen

Pertama-tama konfirmasikan urutan halaman, lokasi sumber, dan integritas teks, lalu kirimkan sampel yang tidak peka ke proses penerjemahan. Setelah diterjemahkan, Anda masih perlu memeriksa apakah judul, teks, dan ilustrasi sudah sesuai. Anda tidak bisa hanya memeriksa apakah teksnya halus.

OmniDoc menyediakan portal terjemahan dokumen multi-format, dan situs resminya memperkenalkan fungsi OCR, glosarium, dan perbandingan bilingual. Jika tim ingin memulai pemrosesan langsung dari file, jalur ini dapat dievaluasi dengan sampel nyata. Harap gunakan file yang tidak peka dan Anda mempunyai izin untuk mengunggahnya, dan tinjau hasilnya sesuai dengan item pemeriksaan di artikel ini. Tidak ada klaim di sini bahwa OmniDoc menggunakan pustaka sumber terbuka atau algoritme internal dalam artikel ini, dan contoh tersebut juga tidak menggantikan pengujian kinerja produk.

Referensi dan langkah selanjutnya

  1. Pilih file proyek historis yang berisi tipe anotasi campuran.
  2. Jalankan skrip verifikasi di atas dan hitung proporsi entri yang memerlukan tinjauan manual.
  3. Jika rasio melebihi ekspektasi, tambahkan langkah pra-pemrosesan pada proses serah terima alih-alih mengandalkan alat hilir untuk memberikan jawabannya.

🎯 Metode mana yang cocok untuk Anda?

Jika Anda hanya perlu menerjemahkan teks

Anda dapat langsung mengekstrak teksnya, tetapi Anda perlu mengonfirmasi apakah ada anotasi yang hilang pada konten yang diekspor.

Jika Anda ingin memberikan dokumen tersebut kepada orang lain untuk diarsipkan

Pada saat yang sama, pertahankan teks utama dan daftar anotasi, dan tandai konten sensitif sebagai tidak peka.

Jika PDF Anda memiliki halaman yang dirotasi

Pertama-tama lakukan transformasi koordinat, lalu gunakan posisi anotasi untuk menemukan lokasi teks.

Jika file dienkripsi atau rusak secara struktural

Solusi ini tidak dapat diterapkan. Silakan gunakan alat profesional secara manual untuk membuka file sumber untuk mengonfirmasi.

❓ Pertanyaan yang Sering Diajukan (FAQ)

1. Mengapa get_text() tidak berisi anotasi?

Output default biasanya hanya berisi badan halaman. Anotasi adalah objek yang tidak bergantung pada aliran teks halaman dan perlu dilintasi secara terpisah melalui page.annots().

2. Apakah teks semua komentar bisa langsung dibaca?

tidak bisa. Anotasi jenis tanda seperti penyorotan dan garis bawah tidak berisi teks itu sendiri dan hanya merekam area; anotasi tinta dan grafis mungkin juga tidak memiliki atribut teks dan memerlukan penilaian defensif.

3. Mengapa posisi halaman setelah diputar menjadi kacau?

Persegi panjang anotasi didasarkan pada halaman yang tidak diputar. Jika digunakan langsung untuk memposisikan teks akan menimbulkan kesalahan. Anda perlu menggunakan page.rotation_matrix atau page.derotation_matrix untuk transformasi koordinat terlebih dahulu.

4. Apakah balasan yang disarangkan akan hilang?

PyMuPDF mengembalikan daftar datar, dan jika pohon dialog tidak direkonstruksi berdasarkan ParentID, konteksnya akan hilang.

5. Bisakah PDF terenkripsi diproses dengan skrip ini?

PDF yang dienkripsi dan tidak memberikan kata sandi tidak termasuk dalam cakupan solusi ini dan memerlukan konfirmasi manual.

📝 Ringkasan

Anotasi adalah lapisan data independen dalam PDF. Sebelum serah terima, teks dan anotasi harus diekstraksi secara terpisah, dan anotasi tersebut harus ditinjau untuk konten sensitif. Skrip otomatis dapat mencakup kasus-kasus umum, tetapi kasus-kasus tepi dan penerimaan akhir masih perlu dilakukan secara manual.

Coba sekarang: Unggah dokumen untuk memulai penerjemahan, dengan tetap mempertahankan tata letak aslinya

Diperbarui 2026-11-14