عند تسليم المستندات المشروحة، لا تقم فقط بتسليم ملف PDF يبدو نظيفًا.

توفر هذه المقالة حلاً للاستخراج متعدد الطبقات والتحقق من الأمان استنادًا إلى PyMuPDF لمعالجة مشكلات الخلط بين النص والتعليقات، وتسرب البيانات الحساسة، وارتباك أنظمة الإحداثيات في استخراج التعليقات التوضيحية بتنسيق PDF. يغطي المحتوى مبدأ طبقة البيانات المستقلة، وأمثلة البرمجة الدفاعية، ومعالجة حالة الحدود ومعايير القبول اليدوي، ويشرح كيفية توصيل OmniDoc بشكل صحيح في سير عمل ترجمة المستندات للمقارنة والقبول ثنائي اللغة.

قبل تسليم التعليقات التوضيحية بتنسيق PDF، سيستخدم العديد من الأشخاص page.get_text() مباشرة لتصدير نص نظيف المظهر لترجمته أو أرشفته أو تسليمه إلى المراجع التالي. لكن هذا النص عادة لا يحتوي على تعليقات توضيحية. ستقوم بعض طرق الاستخراج أيضًا بإدراج التعليقات في منتصف النص، مما يؤدي إلى مقاطعة الدلالات؛ قد يتم تفويت التعليقات التعديلية والملاحظات الحساسة في الشريط الجانبي.

هذه المقالة مكتوبة للمطورين ومالكي المستندات الذين يحتاجون إلى العمل مع ملفات PDF المشروحة. بعد القراءة، ستفهم سبب اعتبار التعليقات التوضيحية طبقات بيانات مستقلة، وكيفية استخراج النص والتعليقات التوضيحية في الطبقات، وما هي حالات الحافة التي تحتاج إلى التعامل معها بشكل دفاعي، وما هي نقاط القبول التي يجب تأكيدها يدويًا.

تستخدم جميع الأمثلة الواردة في هذه المقالة العينات الاصطناعية. لقد تم فحص عينة التعليمات البرمجية في بيئة معزولة، ولكن هذا لا يضمن جميع الملفات الحقيقية أو أداء المنتج. قبل معالجة المستندات المهمة، يرجى الاحتفاظ بالنسخ الأصلية ومراجعتها وفقًا للحدود وبنود القبول في النص.

كيفية استخراج ملف PDF المشروح قبل التسليم؟ استنتاج جملة واحدة

تعامل مع النص والتعليقات التوضيحية كتدفقين مستقلين للبيانات واستخرجهما بشكل منفصل، وقم بإجراء مراجعة أمنية صريحة لمحتوى التعليقات التوضيحية.

حالتكالممارسات الموصى بهاسبب
استخدم get_text() فقط لتصدير النصلا تعاملها على أنها كاملةعادةً لا يحتوي الإخراج الافتراضي على تعليقات توضيحية
يجب الاحتفاظ بتعليقات المراجعة للمراجعينكرر التعليقات التوضيحية بشكل فردي باستخدام page.annots()التعليقات التوضيحية هي كائنات مستقلة مرفقة بالصفحة
قد تحتوي التعليقات على أرقام هوية ورموز داخلية.قم بالمطابقة حسب القواعد الحساسة، ضع علامة على redacted=True واستبدلها بالعنصر النائبقد تحتوي ملاحظات المراجعة على بيانات حساسة
يتم تدوير الصفحةاستخدم أولاً page.rotation_matrix أو page.derotation_matrix لتحويل الإحداثياتمستطيل التعليق التوضيحي بناءً على الصفحة غير المدورة
جاهز لعملية الترجمةقم بتنظيف علامات النص المنسق أولاً، ثم تحقق يدويًا بعد الترجمةتجنب الترجمات التي تحتوي على التعليمات البرمجية

لماذا تكون التعليقات التوضيحية مستقلة عن طبقة بيانات النص

في مواصفات PDF، يتم فصل تدفق محتوى الصفحة (Content Stream) وقاموس التعليقات التوضيحية (Annots Array) هيكليًا. يتكون النص من تعليمات عرض النص؛ التعليقات التوضيحية هي كائنات مستقلة مرفقة بالصفحة، ولها إحداثياتها ونوعها وسمات المحتوى الخاصة بها. تقوم طريقة Page.annots() الخاصة بـ PyMuPDF بإرجاع مولد يجتاز قائمة التعليقات التوضيحية المستقلة بدلاً من دفق نص الصفحة.

وهذا يعني أنه لا يمكنك افتراض أنه يمكن استخراج كل النص الذي تراه بنفس الطريقة.

الفرق بين التعليقات التوضيحية لفئة العلامة والمحتوى

  • التعليقات التوضيحية للعلامة (مثل التمييز والتسطير) لا تحتوي على نص بحد ذاته، ولكنها تسجل فقط المنطقة (المربعات/المستطيلات) المقابلة للنص الأصلي. لا يمكن الحصول على النص الحقيقي إلا من خلال البحث عن النص من خلال الإحداثيات.
  • التعليقات التوضيحية للمحتوى (مثل الملاحظات والنص الحر) لها سلاسل محتوى خاصة بها ويمكن قراءتها مباشرةً.
  • إذا قرأت annot.info["content"] مباشرة دون تمييز النوع، فسوف تفقد السياق الأصلي الذي يشير إليه التعليق التوضيحي لفئة العلامة، أو ستطرح استثناءً إذا كان المحتوى فارغًا.

مثال تركيبي: استخراج الطبقات واعتراض المعلومات الحساسة

لتوضيح منطق المعالجة الصحيح، قمنا ببناء سيناريو تركيبي يحتوي على ثلاثة تعليقات توضيحية نموذجية في التعليمات البرمجية. المدخلات التالية عبارة عن نماذج تم إنشاؤها داخل التعليمات البرمجية، وليست من ملفات عملاء حقيقية، وهي مخصصة لأغراض العرض التوضيحي التعليمي فقط.

يحتوي الإخراج المتوقع على ثلاثة حقول منظمة:

  1. جزء النص: يحتوي فقط على النص الأصلي للصفحة، دون أي محتوى للتعليقات التوضيحية.
  2. قائمة التعليقات التوضيحية: يتضمن كل سجل النوع والموقع والمؤلف والوقت والمحتوى (إن وجد).
  3. علامة الأمان: إذا كان محتوى التعليق التوضيحي يتطابق مع القواعد الحساسة المعدة مسبقًا (مثل رقم المعرف والرمز الداخلي)، فسيتم وضع علامة على الإدخال كـ redacted=True ويتم استبدال المحتوى بعنصر نائب.

ثلاثة أنواع من الحدود التي يجب الدفاع عنها

  • تعليق توضيحي فارغ للمحتوى: التعليقات التوضيحية بالحبر أو التعليقات التوضيحية الرسومية التي أنشأها بعض القراء لا تحتوي على سمات نصية. قد يؤدي الوصول المباشر إلى .info["content"] إلى سلسلة فارغة أو لا شيء، ويجب أن يقوم الكود بإجراء فحوصات دفاعية ولا يمكنه افتراض أن جميع التعليقات التوضيحية تحتوي على نص قابل للقراءة.
  • إحداثيات الصفحة التي تم تدويرها: بعد تدوير الصفحة بمقدار 90 درجة، يظل مستطيل التعليق التوضيحي قائمًا على الصفحة التي لم يتم تدويرها. إذا استخدمت هذه الإحداثيات مباشرةً لقص النص أو تحديد موضعه، فسيتم إفساد الموضع تمامًا، ويجب إجراء تحويل الإحداثيات أولاً.
  • الكائن اليتيم: إذا تم إغلاق المستند أو إعادة تحميل الصفحة أثناء عملية الاجتياز، فسيصبح كائن التعليق الحالي غير صالح على الفور. يجب إكمال جميع عمليات القراءة خلال عمر الصفحة الواحدة.

تنفيذ بايثون: اجتياز التعليقات التوضيحية والتحقق منها بشكل آمن

يستخدم المثال PyMuPDF لإنشاء ملف PDF اختباري في الذاكرة، مما يوضح الاستخراج الهرمي ومنطق الإخفاء الأساسي. المكتبة التابعة هي PyMuPDF (أي حزمة pymupdf). يرجى تشغيله في بيئة تبعية مقفلة. يجب أن يكون الإصدار >=1.23.0 للوصول الكامل إلى السمة annot. لا يقوم هذا الرمز بتنفيذ عمليات الشبكة أو كتابة الملفات، بل يتم استخدامه فقط لتوضيح المنطق.

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.")

في جوهرها، الكود هو برمجة دفاعية: نقاء محتوى التعليق التوضيحي غير موثوق به، ولا يُفترض سلامة نوع التعليق التوضيحي. يتم استخدام عبارة assert للتحقق من المنطق المتوقع، ولكن هذا مجرد عرض توضيحي ولا يمثل ضمانًا للأداء الشامل لجميع متغيرات PDF.

مقارنة فئات التعليقات التوضيحية

نوع التعليق التوضيحيما إذا كان يجب إحضار النص الخاص بككيفية الحصول على المحتوىنقاط يجب ملاحظتها عند التسليم
تسليط الضوء، تسطيرلا، مناطق التسجيل فقط (رباعية/مستطيلة)التحقق من النص باستخدام الإحداثياتيجب الاحتفاظ بسياق النص الأصلي المقابل
ملاحظات، نص مجانينعم، يأتي مع سلسلة المحتوى الخاصة بهقراءة مباشرةالتحقق من وجود محتوى حساس
الحبر والرسومات والأختامفي كثير من الأحيان لا توجد سمة النصقم بإجراء مكالمة دفاعية قصيرةتأكد يدويًا ما إذا كان التوقيع أو ختم الموافقة

معايير القبول وحدود المراجعة اليدوية

لا يمكن أن يغطي الاستخراج الآلي جميع حالات الحافة. يسرد الجدول التالي نقاط القبول التي يجب الانتباه إليها أثناء التسليم، مع التمييز بين النطاق الذي يمكن للتعليمة البرمجية التعامل معه والسيناريوهات التي تتطلب التدخل اليدوي.

مراقبة الظواهرمعالجة مستوى الكودمراجعة الإنسان أو اتخاذ القرار
محتوى التعليق فارغ ولكن الأيقونة موجودةنوع السجل هو حبر أو ختم، ويتم ترك المحتوى فارغًاقم بتأكيد ما إذا كان التوقيع أو ختم الموافقة، وقرر ما إذا كنت تريد الاحتفاظ بلقطة الصورة
موضع التعليق يتجاوز CropBoxالإحداثيات لا تزال صالحة، ولكن العرض غير مرئيتحديد ما إذا كانت عبارة عن تعليق توضيحي مهجور متبقي من التاريخ، والذي يمكن عادةً تجاهله.
تحتوي التعليقات النصية المنسقة على علامات HTMLاستخراج السلسلة الأصلية، والحفاظ على العلاماتقم بتنظيف العلامات أو تحويلها إلى نص عادي قبل الترجمة لتجنب الترجمات التي تحتوي على تعليمات برمجية.
اسم مؤلف التعليق التوضيحي مشوهاستخراج كما هو، لا تخمين الترميزتحقق من البيانات التعريفية للملف المصدر للتأكد مما إذا كان اسمًا لترميز معين
موضوع الرد المتداخليقوم PyMuPDF بإرجاع قائمة مسطحةقم بإعادة إنشاء شجرة الحوار بناءً على ParentID، وإلا سيتم فقدان السياق

غير قابل للتطبيق: لا ينطبق هذا الحل على ملفات PDF المشفرة دون توفير كلمة مرور، وملفات PDF التالفة هيكليًا، والملفات التي تستخدم امتدادات خاصة غير قياسية لتحديد أنواع التعليقات التوضيحية. في هذه المواقف، قد يتخطى البرنامج النصي بصمت أو يطرح استثناء C++ منخفض المستوى، والذي يجب تأكيده عن طريق فتح الملف المصدر يدويًا باستخدام أدوات احترافية.

استخدم قوائم المراجعة لترجمة المستندات

تأكد أولاً من ترتيب الصفحة وموقع المصدر وسلامة النص، ثم أرسل نفس العينة غير الحساسة إلى عملية الترجمة. بعد الترجمة، لا تزال بحاجة إلى التحقق مما إذا كان العنوان والنص والرسوم التوضيحية متطابقين بشكل صحيح. لا يمكنك فقط التحقق مما إذا كان النص سلسًا.

توفر OmniDoc بوابة لترجمة المستندات متعددة التنسيقات، ويقدم الموقع الرسمي وظائف التعرف الضوئي على الحروف (OCR) والمسرد ووظائف المقارنة ثنائية اللغة. إذا أراد الفريق بدء المعالجة مباشرة من الملف، فيمكن تقييم هذا المسار باستخدام عينات حقيقية. الرجاء استخدام الملفات غير الحساسة التي لديك إذن بتحميلها، ومراجعة النتائج وفقًا لعناصر التحقق الواردة في هذه المقالة. لا يوجد ادعاء هنا بأن OmniDoc يستخدم المكتبات مفتوحة المصدر أو الخوارزميات الداخلية لهذه المقالة، ولا يحل المثال محل اختبار أداء المنتج.

المراجع والخطوات التالية

  1. حدد ملف مشروع تاريخي يحتوي على أنواع التعليقات التوضيحية المختلطة.
  2. قم بتشغيل البرنامج النصي للتحقق أعلاه واحسب نسبة الإدخالات التي تتطلب مراجعة يدوية.
  3. إذا تجاوزت النسبة التوقعات، أضف خطوة ما قبل المعالجة إلى عملية التسليم بدلاً من الاعتماد على الأدوات النهائية لتقديم الإجابة.

🎯 ما هي الطريقة المناسبة لك؟

إذا كنت بحاجة فقط إلى ترجمة النص

يمكنك استخراج النص مباشرةً، ولكن عليك التأكد مما إذا كانت هناك أية تعليقات توضيحية مفقودة في المحتوى الذي تم تصديره.

إذا كنت تريد إعطاء المستند لشخص آخر للأرشفة

وفي الوقت نفسه، احتفظ بالنص الرئيسي وقائمة التعليقات التوضيحية، وقم بوضع علامة على المحتوى الحساس باعتباره غير حساس.

إذا كان ملف PDF الخاص بك يحتوي على صفحات مدورة

قم أولاً بإجراء تحويل الإحداثيات، ثم استخدم موضع التعليق التوضيحي لتحديد موقع النص.

إذا كان الملف مشفرًا أو تالفًا هيكليًا

هذا الحل غير قابل للتطبيق. يرجى استخدام الأدوات الاحترافية يدويًا لفتح الملف المصدر للتأكيد.

❓ الأسئلة الشائعة (الأسئلة الشائعة)

1. لماذا لا يحتوي get_text() على تعليقات توضيحية؟

عادةً ما يحتوي الإخراج الافتراضي على نص الصفحة فقط. التعليقات التوضيحية هي كائنات مستقلة عن تدفق نص الصفحة ويجب اجتيازها بشكل منفصل عبر page.annots().

2. هل يمكن قراءة نص كافة التعليقات مباشرة؟

لا أستطيع. التعليقات التوضيحية من نوع العلامة، مثل التمييز والتسطير، لا تحتوي على نص بحد ذاته ولكنها تسجل مناطق فقط؛ قد لا تحتوي التعليقات التوضيحية بالحبر والرسومات أيضًا على سمات نصية وتتطلب حكمًا دفاعيًا.

3. لماذا يتم تغيير موضع الصفحة بعد تدويرها؟

يستند مستطيل التعليق التوضيحي إلى صفحة لم يتم تدويرها. إذا تم استخدامه مباشرة لوضع النص، فإنه سوف يسبب أخطاء. تحتاج إلى استخدام page.rotation_matrix أو page.derotation_matrix لتحويل الإحداثيات أولاً.

4. هل سيتم فقدان الردود المتداخلة؟

يقوم PyMuPDF بإرجاع قائمة مسطحة، وإذا لم تتم إعادة بناء شجرة الحوار بناءً على ParentID، فسيتم فقدان السياق.

5. هل يمكن معالجة ملف PDF المشفر باستخدام هذا البرنامج النصي؟

ملفات PDF المشفرة والتي لا توفر كلمة مرور ليست ضمن نطاق هذا الحل وتتطلب تأكيدًا يدويًا.

📝 ملخص

التعليقات التوضيحية هي طبقة بيانات مستقلة في PDF. قبل التسليم، يجب استخراج النص والشروح بشكل منفصل، وينبغي مراجعة الشروح للمحتوى الحساس. يمكن أن تغطي البرامج النصية التلقائية الحالات الشائعة، ولكن لا يزال يتعين إجراء حالات الحافة والقبول النهائي يدويًا.

جربه الآن: قم بتحميل المستند لبدء الترجمة، مع الاحتفاظ بالتخطيط الأصلي

تاريخ التحديث: 2026-11-14