إدارة المستندات
إدارة المستندات
الفئة Document هي نقطة الدخول لمعظم العمليات في Aspose.PDF FOSS لـ Python: إنشاء PDF جديد، تحميل ملف موجود، تحرير صفحاته، وكتابة النتيجة مرة أخرى. يوضح هذا الدليل دورة حياة المستند، عمليات مجموعة الصفحات، التحسين، سير العمل متعدد الملفات، التشفير، والاستثناءات التي يجب أن تتوقع التعامل معها.
دورة حياة المستند: إنشاء، فتح، وحفظ
Document() بدون أي حجج ينشئ مستندًا فارغًا في الذاكرة. مرّر مسار ملف، bytes الخام، أو أي تدفق ثنائي قابل للقراءة كالحجة الأولى (أو استدعِ load_from() صراحة) لتحميل PDF موجود بدلاً من ذلك. save() يقبل مسارًا أو تدفقًا ثنائيًا قابلًا للكتابة مثل io.BytesIO.
from aspose_pdf import Document
# Create a new, empty document and add a blank page
doc = Document()
doc.pages.add()
doc.save("hello.pdf")
# Re-open it — a path, bytes, or a binary stream all work
reopened = Document("hello.pdf")
print(reopened.page_count) # 1
# ...or load explicitly onto an existing instance
another = Document()
another.load_from("hello.pdf")
reopened.close()
another.dispose()
doc.dispose()save() يثير FileExistsError إذا كان مسار الوجهة موجودًا بالفعل، ما لم تمرّر overwrite=True. close() هو اسم مستعار لـ dispose()؛ كلاهما متطابق (idempotent)، لذا فإن استدعائهما أكثر من مرة آمن.
فقط PDF هو الهدف المدعوم للحفظ — هذا هو جوهر المكتبة، وظيفة تعمل بالكامل. تمرير قيمة تصدير مثل SaveFormat.PPTX أو DocFormat.HTML إلى save() يثير UnsupportedFeatureException بدلاً من كتابة ملف مسمى خطأ، لذا فإن فشل التصدير يكون دائمًا واضحًا وليس صامتًا.
إدارة مجموعة الصفحات
doc.pages هو PageCollection. يدعم len()، التكرار، وفهرسة صفرية القاعدة (doc.pages[0])، بالإضافة إلى add()، insert(index, page)، وdelete(index) لتعديلات هيكلية. كل Page يكشف عن index، rect (الـ MediaBox)، وrotation.
from aspose_pdf import Document
doc = Document()
doc.pages.add() # page 0
doc.pages.add() # page 1
doc.pages.insert(1, None) # insert a blank page at index 1
print(doc.page_count) # 3
first_page = doc.pages[0]
print(first_page.rect) # (0, 0, 612, 792)
for page in doc.pages:
print(page.index, page.rotation)
doc.pages.delete(1) # remove the page we inserted
doc.save("pages_demo.pdf", overwrite=True)pages.add(page=None) يضيف صفحة فارغة عندما يُستدعى بدون أي وسيط. pages.insert() يقيد الفهرس خارج النطاق إلى أقرب موقع صالح بدلاً من إلقاء استثناء.
تحسين وضغط المستندات
Document.optimize ينفّذ إزالة التكرار للصور/المجاري، جمع القمامة للكائنات غير المستخدمة، وضغط التدفق في استدعاء واحد. مرّر كائن OptimizationOptions للتحكم في التقنيات التي تُشغل؛ احذفها لاستخدام ملف التنظيف القياسي.
from aspose_pdf import Document, OptimizationOptions
doc = Document("large_report.pdf")
options = OptimizationOptions()
options.remove_unused_objects = True
options.link_duplicate_streams = True
options.image_compression_quality = 60
options.subset_fonts = True
doc.optimize(options)
doc.save("large_report_optimized.pdf", overwrite=True)optimize_resources() هو اسم مستعار لـ optimize(). إذا كنت تريد فقط ضغط التدفق دون مرحلة التنظيف الهيكلية، استدعِ doc.compress_streams() مباشرةً.
دمج، تقسيم، وتحرير الملفات
بالنسبة للمستندات المفتوحة بالفعل، Document.merge() يضيف مثيلات Document أخرى إلى الحالية:
from aspose_pdf import Document
base = Document("part1.pdf")
extra = Document("part2.pdf")
base.merge(extra)
base.save("combined.pdf", overwrite=True)لتدفقات من ملف إلى ملف دون فتح Document بنفسك، الإضافات منخفضة الكود Merger وSplitter تأخذ كائن MergeOptions/SplitOptions مُنشأ من مدخلات ومخرجات FileDataSource:
from aspose_pdf import Merger, MergeOptions, Splitter, SplitOptions, FileDataSource
# Merge two files into one
merge_options = MergeOptions()
merge_options.add_input(FileDataSource("part1.pdf"))
merge_options.add_input(FileDataSource("part2.pdf"))
merge_options.add_output(FileDataSource("combined.pdf"))
Merger().process(merge_options)
# Split the result into one file per page
split_options = SplitOptions()
split_options.add_input(FileDataSource("combined.pdf"))
split_options.add_output(FileDataSource("combined_page1.pdf"))
split_options.add_output(FileDataSource("combined_page2.pdf"))
Splitter().process(split_options)PdfFileEditor يقدم نفس عائلة العمليات كواجهة تُعيد True/False بدلاً من رفع الاستثناء، وهو ما يُسهّل كتابة سكريبتات الدُفعات:
from aspose_pdf import PdfFileEditor
with PdfFileEditor() as editor:
ok = editor.concatenate(["part1.pdf", "part2.pdf"], "combined.pdf")
if not ok:
print("concatenate failed:", editor.last_exception)
editor.extract("combined.pdf", "first_page_only.pdf", page_from=1, page_to=1)PdfFileEditor.extract() and .insert() take مستند إلى 1 أرقام الصفحات، على عكس PageCollectionفهرسة تبدأ من 0 — انظر المشكلات الشائعة أدناه.
التشفير وأمن المستند
Document.encrypt(user_password, owner_password=None, permissions=-4) يشفر المستند الموجود في الذاكرة؛ decrypt(password) و change_passwords(old, new_user, new_owner=None) يعيدان أو يدوّران كلمات المرور. is_encrypted و permissions تُبلغ عن الحالة الحالية.
from aspose_pdf import Document
from aspose_pdf.exceptions import PdfSecurityException
doc = Document()
doc.pages.add()
doc.encrypt("user-pass", "owner-pass", permissions=-4)
doc.save("secured.pdf", overwrite=True)
try:
Document("secured.pdf", password="wrong-pass")
except PdfSecurityException as exc:
print("could not open:", exc)
reopened = Document("secured.pdf", password="user-pass")
print(reopened.is_encrypted) # True
reopened.decrypt("user-pass")
reopened.save("unsecured.pdf", overwrite=True)فتح مستند مُشفّر بدون كلمة مرور، أو بكلمة خاطئة، يرفع PdfSecurityException — امسك بهذه الفئة (من aspose_pdf.exceptions) بدلاً من افتراض أن التحميل ينجح دائمًا.
البيانات الوصفية، التحقق، ومعالجة الاستثناءات
البيانات الوصفية للمستند موجودة على doc.info (قائمة dict[str, str] عادية)، وdoc.version / doc.id تُظهر إصدار رأس PDF ومعرّف ملف المُلحق. validate() (المعروف باسم check()) يُبلغ عن سلامة البنية؛ repair() يحاول إصلاح المشكلات الشائعة مثل قائمة صفحات مفقودة أو MediaBox خارج النطاق.
from aspose_pdf import Document, PdfLoadLimits
from aspose_pdf.exceptions import AsposePdfException, PdfIOException
doc = Document()
doc.pages.add()
doc.info["Title"] = "Quarterly Report"
doc.info["Author"] = "Reporting Bot"
doc.save("report.pdf", overwrite=True)
# Load untrusted input under an explicit resource-limit policy
safe_limits = PdfLoadLimits(max_input_bytes=50 * 1024 * 1024, max_pages=1000)
try:
untrusted = Document("incoming.pdf", limits=safe_limits)
if not untrusted.validate():
untrusted.repair()
except (AsposePdfException, PdfIOException) as exc:
print("failed to process incoming.pdf:", exc)PdfLoadLimits يفرض حدودًا على الذاكرة وعدد الكائنات للملفات غير الموثوقة؛ استدعِ PdfLoadLimits.unlimited() لتعطيل كل الحدود عندما تثق تمامًا بالمصدر. AsposePdfException هي الفئة الأساسية لكل شجرة الاستثناءات (بما في ذلك PdfIOException و PdfSecurityException)، لذا فـ except AsposePdfException واحد يلتقط أي خطأ يُرفع من المكتبة.
نصائح وأفضل الممارسات
- دائمًا استدعِ
dispose()(أوclose()) علىDocumentعندما تنتهي منه، أو استخدمه كمتغيّر محلي قصير الأمد — يحتفظ المحرّك بمحتوى الصفحة المُفكّك والصور في الذاكرة حتى يتم التخلص منه. - مرّر
overwrite=Trueإلىsave()عند إعادة كتابة مسار قمت بإنشائه بالفعل في نفس التنفيذ؛ القيمة الافتراضية هيFalseوتثيرFileExistsError. - يفضَّل استخدام
doc.optimize()قبل نشر ملف PDF مُولَّد — إنها استدعاءة واحدة تُزيل الكائنات غير المستخدمة وتضغط التدفقات، وعادةً ما تُقلِّص حجم الإخراج بشكل ملحوظ. - حدِّد سياسة
PdfLoadLimitsصراحةً كلما قمت بتحميل ملفات PDF من مصدر غير موثوق (التحميلات، مرفقات البريد الإلكتروني، استخراج الويب)؛ الإعدادات الافتراضية سخية لكن محدودة، وليست حدًا أمنيًا يجب الاعتماد عليه بشكل أعمى. - التقط
AsposePdfException(أو فئة فرعية محددة مثلPdfSecurityException) حول استدعاءات التحميل/الحفظ بدلاً منExceptionالعارية — فهي القاعدة المشتركة لكل خطأ تُطلقه المكتبة.
مشكلات شائعة
| المشكلة | السبب | الإصلاح |
|---|---|---|
FileExistsError على save() | مسار الوجهة موجود بالفعل وoverwrite تُرك على القيمة الافتراضية False | تجاوز save(path, overwrite=True) |
UnsupportedFeatureException على save() | تم طلب save_format غير PDF (مثلاً SaveFormat.PPTX، DocFormat.HTML) | احفظ كـ PDF — أي قيمة أخرى لـ SaveFormat/DocFormat تثير UnsupportedFeatureException بدلاً من كتابة المخرجات |
PdfSecurityException: Password required for encrypted document | تم فتح ملف PDF مشفر دون وسيط password | مرّر Document(path, password="...") أو استدعِ load_from(path, password="...") |
إزاحة صفحة واحدة في أرقام الصفحات بين PageCollection و PdfFileEditor | doc.pages[i] يبدأ من الصفر؛ معطيات الصفحات PdfFileEditor.extract()/.insert() تبدأ من الواحد | أضف أو اطرح 1 عند التحويل بين واجهتي API |
IndexError: Page index out of range. من pages.delete() | الفهرس الممرَّ إلى delete() غير موجود في المجموعة | تحقق من doc.page_count (أو len(doc.pages)) قبل الحذف |
FAQ
هل أحتاج إلى ترخيص لاستخدام Aspose.PDF FOSS لـ Python؟
لا. هذه النسخة مفتوحة المصدر (مرخصة بموجب MIT)؛ لا يوجد ملف ترخيص أو خطوة تفعيل لتكوينها.
هل يمكنني تصدير Document إلى صيغ غير PDF؟
ليس في هذا الإصدار. save() يقتصر على تنفيذ إخراج PDF فقط — تمرير قيمة SaveFormat/DocFormat أخرى يثير UnsupportedFeatureException بدلاً من إنتاج ملف مسمى بشكل خاطئ.
ما الفرق بين Document.merge() وملحق Merger؟
Document.merge() يجمع بين حالات Document التي لديك مفتوحة بالفعل في الذاكرة. Merger (مع MergeOptions وFileDataSource) هو غلاف ملائم من ملف إلى ملف يفتح، يدمج، ويحفظ لك في استدعاء واحد — مفيد لسكربتات الدفعات البسيطة التي لا تحتاج أبداً إلى كائن Document الوسيط.
لماذا لا يثير pages.insert() خطأً أبداً عندما يكون الفهرس خارج النطاق؟
PageCollection.insert() يحد الفهرس إلى النطاق الصالح (القيم السالبة تصبح 0، والقيم التي تتجاوز النهاية تصبح len(doc.pages)) بدلاً من إثارة خطأ، لذا لا يفشل الإدراج أبداً لمجرد قيمة الفهرس.
كيف يمكنني تحميل ملف PDF بأمان من مصدر غير موثوق؟
قم بإنشاء PdfLoadLimits مع حدود صريحة (max_input_bytes، max_pages، max_objects، وما إلى ذلك) ومرره كمعامل limits= إلى Document(...) أو load_from(). كل حقل له قيمة افتراضية محدودة بالفعل، ولكن تضييقها لتتناسب مع حجم الإدخال المتوقع يقلل من الموارد التي يمكن أن يستهلكها ملف غير صالح.
API Reference ملخص
| فئة / طريقة | وصف |
|---|---|
Document() / Document.load_from | أنشئ مستندًا فارغًا أو حمّله من مسار أو بايتات أو تدفق ثنائي |
Document.save | اكتب المستند إلى مسار أو تدفق قابل للكتابة (PDF فقط) |
Document.dispose() / Document.close() | إطلاق موارد المحرك؛ idempotent |
Document.pages | PageCollection الخاص بالمستند |
Document.info | بيانات تعريف المستند كـ dict[str, str] |
Document.optimize / Document.optimize_resources / Document.compress_streams() | إزالة الموارد غير المستخدمة وضغط التدفقات |
Document.merge() | أضف حالات Document أخرى إلى هذا |
Document.encrypt / Document.decrypt / Document.change_passwords | تطبيق أو إزالة أو تدوير كلمات مرور المستند |
Document.validate() / Document.check() / Document.repair() | تحقق وحاول إصلاح سلامة الهيكل |
PageCollection.add() / .insert() / .delete() / .item() | تحريرات تجميع الصفحات الهيكلية (بدءًا من الصفر) |
Page.rect / Page.rotation / Page.index | الهندسة والموضع لكل صفحة |
OptimizationOptions | أعلام دقيقة المستوى يستخدمها Document.optimize |
MergeOptions / Merger | ملحق دمج من ملف إلى ملف |
SplitOptions / Splitter | ملحق تقسيم من ملف إلى ملف صفحة واحدة لكل ناتج |
FileDataSource | إدخال/إخراج مدعوم بالملف لواجهات برمجة التطبيقات الخاصة بالملحق |
PdfFileEditor | واجهة أمامية لـ concatenate()، extract()، insert()، delete()، append() (صفحات مرقمة من 1) |
PdfLoadLimits | سياسة حد الموارد غير القابلة للتغيير للمدخلات غير الموثوقة |
AsposePdfException | الفئة الأساسية لكل استثناء تطرحه المكتبة |
PdfSecurityException | يتم رفعها عند عدم وجود كلمة مرور أو كلمة مرور غير صحيحة وأخطاء الأذونات |
PdfIOException | يتم رفعها عند حدوث أخطاء الإدخال/الإخراج أثناء معالجة PDF |
انظر أيضاً
- API Reference: توثيق كامل للفئة والطريقة لـ
aspose_pdf - قاعدة المعرفة: أدلة إرشادية موجهة للمهام
- نظرة عامة على المنتج: ملخص الميزات والقدرات
- البدء / التثبيت: تثبيت وإعداد
- Aspose.PDF for Python — Enterprise Documentation