كيفية العمل مع تعليقات PDF في Python

كيفية العمل مع تعليقات PDF في Python

Aspose.PDF FOSS for Python يكشف كل تعليقة على صفحة ككائن Annotation حي من خلال AnnotationCollection للصفحة، بحيث يمكنك إضافة تعليقات توضيحية، وروابط، وتعليقات ثلاثية الأبعاد، وفحص الخصائص الخاصة بنوعها، وإنشاء تدفقات المظهر التي يحتاجها عارضو PDF لعرضها — كل ذلك من خلال Python نقي. يوضح هذا الدليل كيفية تثبيت المكتبة، إضافة التعليقات، قراءتها مرة أخرى، وإنشاء تدفقات مظهرها.

دليل خطوة بخطوة

الخطوة 1: تثبيت الحزمة

قم بتثبيت حزمة Aspose.PDF FOSS:

git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .

تحقق من التثبيت عن طريق استيراد وحدة aspose_pdf العليا، التي تكشف عن الفئة Document المستخدمة في الخطوات أدناه. يُطبع المقتطف aspose_pdf OK عند نجاح الاستيراد؛ عادةً ما يعني ModuleNotFoundError أن الحزمة تم تثبيتها في بيئة Python مختلفة عن تلك التي تُشغل سكريبتك:

import aspose_pdf
print("aspose_pdf OK")

الخطوة 2: استيراد الفئات المطلوبة

استورد Document لحفظ ملف PDF، بالإضافة إلى فئات التعليقات التوضيحية التي ستستخدمها لإنشاء وفحص التعليقات التوضيحية:

from aspose_pdf import Document
from aspose_pdf.annotations import (
    Annotation,
    AnnotationType,
    AnnotationFlags,
    MarkupAnnotation,
    LinkAnnotation,
)

الخطوة 3: إضافة تعليق توضيحي إلى صفحة

كل Page يكشف عن تعليقاته التوضيحية من خلال خاصية annotations، وهي AnnotationCollection. استدعِ add(subtype, rect, contents) مع اسم النوع الفرعي، ومستطيل (left, bottom, right, top)، ومحتوى النص للتعليق التوضيحي. الأنواع الفرعية للوسم القياسي مثل "Highlight" تُرجع ككائن MarkupAnnotation:

from aspose_pdf import Document

document = Document()
document.pages.add()
page = document.pages[0]

annotation = page.annotations.add(
    "Highlight",
    (100, 700, 300, 720),
    "Key clause",
)
print(type(annotation).__name__)   # MarkupAnnotation
print(annotation.contents)         # Key clause

الخطوة 4: إنشاء تعليقات توضيحية من الأنواع الفرعية للـ Enum

AnnotationType تُعدّ كل نوع فرعي قياسي للتعليقات التوضيحية في PDF (PDF 32000-1:2008, Table 169)، بحيث يمكنك تمرير عضو تعداد بدلاً من سلسلة نصية مباشرة. البيانات الخاصة بالنوع — مثل رؤوس المضلع — تُوضع في القاموس properties وتُقرأ مرة أخرى باستخدام get_property:

from aspose_pdf import Document
from aspose_pdf.annotations import AnnotationType

document = Document()
document.pages.add()
page = document.pages[0]

annotation = page.annotations.add(
    AnnotationType.POLYGON,
    (0, 0, 10, 10),
    "",
    properties={"Vertices": [0, 0, 10, 0, 5, 10]},
)
print(annotation.subtype)                    # Polygon
print(annotation.get_property("Vertices"))   # [0, 0, 10, 0, 5, 10]

الخطوة 5: قراءة وتكرار التعليقات التوضيحية الموجودة

AnnotationCollection قابل للتكرار، لذا يمكنك استعراض كل تعليق توضيحي موجود بالفعل على صفحة — بما في ذلك تلك التي تم تحميلها من PDF موجود — وقراءة الخصائص المشتركة التي يكشف عنها كل Annotation (subtype, contents, rect, title, author, color):

from aspose_pdf import Document

document = Document()
document.pages.add()
page = document.pages[0]
page.annotations.add("Text", (50, 50, 70, 70), "First note")
page.annotations.add("Text", (80, 80, 100, 100), "Second note")

for annotation in page.annotations:
    print(annotation.subtype, "-", annotation.contents)

الخطوة 6: إنشاء تدفقات مظهر التعليقات التوضيحية

التعليق التوضيحي الذي تم إنشاؤه دون appearance_normal صريح لا يمتلك عرضًا مرئيًا (/AP /N) حتى يتم إنشاؤه. استدعِ generate_appearance(force) على Annotation واحد، أو generate_appearances(force) على كامل AnnotationCollection لتوليف كل تدفق مظهر مفقود في الصفحة مرة واحدة:

from aspose_pdf import Document
from aspose_pdf.engine.cos import AnnotationName

document = Document()
document.pages.add()
page = document.pages[0]

stamp = page.annotations.add(
    "Stamp",
    (100, 100, 260, 150),
    "",
    properties={"Name": AnnotationName("Approved")},
)
if stamp.generate_appearance():
    print(f"Appearance stream: {len(stamp.appearance_normal)} byte(s)")

# Regenerate every missing appearance stream on the page in one call:
count = page.annotations.generate_appearances(force=True)
print(f"Regenerated {count} appearance stream(s)")

الخطوة 7: تمييز الفئات الفرعية للتعليقات التوضيحية

AnnotationCollection.add() يوجه إلى فئة فرعية محددة بناءً على النوع الفرعي: الأنواع الفرعية ذات نمط العلامات (Highlight, Square, Stamp، وما شابه) تُعيد كـ MarkupAnnotation، و"Link" تُعيد كـ LinkAnnotation. كلاهما يرث كل طريقة وخاصية من Annotation، لذا فحوصات isinstance تسمح لك بالتفرّع حسب نوع التعليق دون فحص سلاسل subtype مباشرةً:

from aspose_pdf import Document
from aspose_pdf.annotations import LinkAnnotation, MarkupAnnotation

document = Document()
document.pages.add()
page = document.pages[0]

link = page.annotations.add("Link", (50, 750, 200, 770), "")
highlight = page.annotations.add("Highlight", (50, 700, 200, 720), "")

print(isinstance(link, LinkAnnotation))         # True
print(isinstance(highlight, MarkupAnnotation))  # True

المشكلات الشائعة والحلول

get_property returns None لخاصية قمت لتوّي بتعيينها

properties المفاتيح هي أسماء حقول PDF دقيقة وحساسة لحالة الأحرف ("Vertices", "Name"، وما شابه) — أي خطأ إملائي أو حالة غير صحيحة يتم تجاهله بصمت بدلاً من إثارة استثناء. مرّر وسيط default إلى get_property(name, default) وتحقق منه صراحةً أثناء تصحيح نوع فرعي جديد.

generate_appearance() returns False

ليس كل تركيبة من النوع الفرعي والخاصية يمكن توليفها إلى تدفق مظهر بواسطة المُولِّد المدمج. تحقق من has_appearance قبل افتراض أن النداء نجح، وقدِّم appearance_normal (bytes) المُسبق التجسيد مباشرةً على add() للأنواع الفرعية التي لا يغطيها المُولِّد.

فئة فرعية غير متوقعة للتعليق بعد add()

سلسلة النوع الفرعي (أو عضو AnnotationType) التي تمرّرها تحدد الفئة المسترجعة: الأنواع الفرعية للعلامات تُعيد كـ MarkupAnnotation، "Link" تُعيد كـ LinkAnnotation، وأي نوع فرعي آخر مُعترف به يُعيد الفئة الأساسية Annotation. استخدم isinstance() مقابل MarkupAnnotation/LinkAnnotation بدلاً من افتراض سلسلة نوع فرعي محددة.

AnnotationFlags القيم لا تبدو أنها تُغيّر العرض

AnnotationFlags (PRINT, HIDDEN, NO_ZOOM, READ_ONLY، وما إلى ذلك) هو تعداد Python IntFlag قياسي لتكوين وتفسير بتات سلوك التعليق باستخدام عامل | — إنه نوع قيمة، وليس خاصية يكتبها Annotation.add() تلقائيًا. اجمع العلامات التي تحتاجها ومررها عبر نفس آلية properties الخاصة بالنوع المستخدمة للبيانات الخاصة بالأنواع الفرعية الأخرى.

العمل مع صفحة لا تحتوي على تعليقات توضيحية بعد

page.annotations دائمًا ما يكون AnnotationCollection صالحًا (قد يكون فارغًا) — لا تحتاج أبدًا إلى التحقق من None قبل استدعاء add()، أو التكرار، أو استدعاء clear().

الأسئلة الشائعة

ما هي الأنواع الفرعية للتعليقات التوضيحية التي يدعمها Aspose.PDF FOSS لـ Python؟

AnnotationType يعدد جميع الأنواع الفرعية الـ 25 القياسية في جدول 169 من معيار PDF 32000-1:2008، بما في ذلك TEXT، LINK، FREE_TEXT، LINE، SQUARE، CIRCLE، POLYGON، HIGHLIGHT، STAMP، INK، FILE_ATTACHMENT، REDACT، وأكثر.

هل تدعم هذه المكتبة التعليقات التوضيحية ثلاثية الأبعاد؟

نعم. PDF3DAnnotation, مع PDF3DArtwork, PDF3DContent, PDF3DView, PDF3DLightingScheme, و PDF3DRenderMode, يُنمذج سطح تعليقة PDF 3D بسيط (مستطيل، عمل فني مضمّن، وطرق مسماة) لتدفقات عمل PDF 3D قبل الإصدار. انظر مرجع PDF3DAnnotation لمجموعة الخصائص الكاملة الخاصة به.

كيف يمكنني إزالة تعليق توضيحي من صفحة؟

استدعِ page.annotations.delete(index) لإزالة تعليق واحد حسب الموقع، أو page.annotations.clear() لإزالة جميع التعليقات على الصفحة.

هل يمكنني إدراج تعليق توضيحي في موضع محدد بدلاً من إضافته في النهاية؟

نعم — AnnotationCollection.insert(index, subtype, rect, contents, title, appearance_normal, properties) يأخذ نفس الوسائط مثل add() بالإضافة إلى الهدف index.

كيف يتم تمثيل لون التعليق التوضيحي؟

خاصية color على Annotation (وعلى الفئات الفرعية لها) هي tuple[float, ...] تطابق عدد مكونات مدخل PDF /C (فارغة عندما لا يتم تعيين اللون) — ليست كائن لون مخصص.

انظر أيضاً

 العربية