ניהול מסמכים

ניהול מסמכים

ניהול מסמכים

המחלקה 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(); שניהם אידמפוטנטים, ולכן קריאה אליהם יותר מפעם אחת בטוחה.

רק PDF מיושם כיעד שמירה — זה הליבה של הספרייה, פונקציה עובדת במלואה. העברת ערך ייצוא כגון SaveFormat.PPTX או DocFormat.HTML ל-save() זורקת UnsupportedFeatureException במקום לכתוב קובץ מתויג שגוי, ולכן ייצוא כושל תמיד יופיע בולט ולא שקט.


ניהול אוסף הדפים

doc.pages הוא PageCollection. הוא תומך ב-len(), איטרציה, ו-indexing מבוסס-אפס (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’s אינדקס מבוסס-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 ואת מזהה קובץ ה-trailer. 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 documentPDF מוצפן נפתח ללא ארגומנט passwordהעבר Document(path, password="...") או קרא load_from(path, password="...")
מספרי עמודים off-by-one בין PageCollection ל-PdfFileEditordoc.pages[i] הוא מבוסס על 0; ארגומנטים של עמודים PdfFileEditor.extract()/.insert() הם מבוססי 1הוסף או הפחת 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()שחרר משאבי מנוע; אידמפוטנט
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קלט/פלט מבוסס קובץ עבור ממשקי ה-API של התוסף
PdfFileEditorחזית עבור concatenate(), extract(), insert(), delete(), append() (דפים מבוססי 1)
PdfLoadLimitsמדיניות בלתי-ניתנת לשינוי של מגבלת משאבים עבור קלט בלתי מהימן
AsposePdfExceptionמחלקת בסיס לכל חריגה שהספרייה מעלה
PdfSecurityExceptionנוצר עבור ססמאות חסרות/שגויות ושגיאות הרשאה
PdfIOExceptionנוצר עבור שגיאות קלט/פלט במהלך עיבוד PDF

ראה גם

 עברית