Zarządzanie dokumentami

Zarządzanie dokumentami

Zarządzanie dokumentami

Klasa Document jest punktem wejścia dla prawie każdej operacji w Aspose.PDF FOSS dla Python: tworzenia nowego PDF, ładowania istniejącego, edycji jego stron i zapisywania wyniku. Ten przewodnik przechodzi przez cykl życia dokumentu, operacje na kolekcji stron, optymalizację, przepływy pracy z wieloma plikami, szyfrowanie oraz wyjątki, które należy obsłużyć.


Cykl życia dokumentu: tworzenie, otwieranie i zapisywanie

Document() bez argumentów tworzy pusty dokument w pamięci. Przekaż ścieżkę do pliku, surowy bytes lub dowolny czytelny strumień binarny jako pierwszy argument (lub wywołaj load_from() explicite), aby zamiast tego załadować istniejący PDF. save() akceptuje ścieżkę lub zapisywalny strumień binarny, taki jak 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() zgłasza FileExistsError, jeśli docelowa ścieżka już istnieje, chyba że przekażesz overwrite=True. close() jest aliasem dla dispose(); oba są idempotentne, więc wywoływanie ich więcej niż raz jest bezpieczne.

Jedynie PDF jest zaimplementowany jako cel zapisu — jest to rdzeń biblioteki, w pełni działająca funkcja. Przekazanie wartości eksportu, takiej jak SaveFormat.PPTX lub DocFormat.HTML, do save() zgłasza UnsupportedFeatureException zamiast zapisać nieprawidłowo oznaczony plik, więc nieudany eksport zawsze jest wyraźny, a nie cichy.


Zarządzanie kolekcją stron

doc.pages jest PageCollection. Obsługuje len(), iterację i indeksowanie od zera (doc.pages[0]), a także add(), insert(index, page) i delete(index) do edycji strukturalnych. Każdy Page udostępnia index, rect (to MediaBox), oraz 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) dodaje pustą stronę, gdy wywołany jest bez argumentu. pages.insert() ogranicza indeks poza zakresem do najbliższej prawidłowej pozycji zamiast zgłaszać błąd.


Optymalizacja i kompresja dokumentów

Document.optimize wykonuje deduplikację obrazów/strumieni, zbieranie śmieci nieużywanych obiektów oraz kompresję strumienia w jednym wywołaniu. Przekaż instancję OptimizationOptions, aby kontrolować, które techniki zostaną uruchomione; pomiń ją, aby użyć standardowego profilu czyszczenia.

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() jest aliasem dla optimize(). Jeśli potrzebujesz tylko kompresji strumienia bez przebiegu czyszczenia strukturalnego, wywołaj bezpośrednio doc.compress_streams().


Łączenie, dzielenie i edycja plików

Dla dokumentów, które już masz otwarte, Document.merge() dodaje inne instancje Document do bieżącej:

from aspose_pdf import Document

base = Document("part1.pdf")
extra = Document("part2.pdf")

base.merge(extra)
base.save("combined.pdf", overwrite=True)

Dla przepływów pracy plik-do-pliku bez otwierania własnego Document, wtyczki low-code Merger i Splitter przyjmują obiekt MergeOptions/SplitOptions zbudowany z wejść i wyjść 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 oferuje tę samą rodzinę operacji jako fasada, która zwraca True/False zamiast podnosić wyjątek, co jest wygodne w skryptach wsadowych:

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 liczony od 1 numery stron, w przeciwieństwie do PageCollectionindeksowanie od 0 — zobacz Typowe problemy poniżej.


Szyfrowanie i zabezpieczenia dokumentu

Document.encrypt(user_password, owner_password=None, permissions=-4) szyfruje dokument w pamięci; decrypt(password) i change_passwords(old, new_user, new_owner=None) odwracają lub obracają hasła. is_encrypted i permissions raportują bieżący stan.

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)

Otwarcie zaszyfrowanego dokumentu bez hasła lub z niewłaściwym hasłem podnosi PdfSecurityException — przechwyć tę klasę (z aspose_pdf.exceptions) zamiast zakładać, że ładowanie zawsze się powiedzie.


Metadane, walidacja i obsługa wyjątków

Metadane dokumentu znajdują się w doc.info (zwykły dict[str, str]), a doc.version / doc.id udostępniają wersję nagłówka PDF oraz identyfikator pliku w trailerze. validate() (aliasowany jako check()) raportuje integralność strukturalną; repair() próbuje naprawić typowe problemy, takie jak brakująca lista stron lub MediaBox poza zakresem.

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 ogranicza pamięć i liczbę obiektów dla niepewnych plików; wywołaj PdfLoadLimits.unlimited(), aby wyłączyć wszystkie limity, gdy w pełni ufasz źródłu. AsposePdfException jest klasą bazową dla całej hierarchii wyjątków (w tym PdfIOException i PdfSecurityException), więc pojedynczy except AsposePdfException przechwytuje każdy błąd podniesiony przez bibliotekę.


Wskazówki i najlepsze praktyki

  • Zawsze wywołuj dispose() (lub close()) na Document, gdy skończysz z nim pracę, lub używaj go jako krótkotrwałej zmiennej lokalnej — silnik przechowuje zdekodowaną zawartość stron i obrazy w pamięci aż do zwolnienia.
  • Przekaż overwrite=True do save() przy ponownym zapisywaniu ścieżki, którą już utworzyłeś w tym samym uruchomieniu; domyślnie jest False i podnosi FileExistsError.
  • Preferuj doc.optimize() przed udostępnieniem wygenerowanego PDF — to pojedyncze wywołanie usuwa nieużywane obiekty i kompresuje strumienie, a zazwyczaj zauważalnie zmniejsza rozmiar wyjścia.
  • Ustaw politykę PdfLoadLimits explicite za każdym razem, gdy wczytujesz pliki PDF z niepewnego źródła (przesyłki, załączniki e-mail, zeskrobywanie stron); domyślne ustawienia są hojne, ale ograniczone, nie stanowią granicy bezpieczeństwa, na której można ślepo polegać.
  • Przechwytuj AsposePdfException (lub konkretną podklasę, taką jak PdfSecurityException) wokół wywołań ładowania/zapisu zamiast samego Exception — jest to wspólna podstawa dla każdego błędu zgłaszanego przez bibliotekę.

Typowe problemy

ProblemPrzyczynaRozwiązanie
FileExistsError na save()Ścieżka docelowa już istnieje i overwrite został pozostawiony w domyślnym FalsePrzekaż save(path, overwrite=True)
UnsupportedFeatureException na save()Żądano nie-PDF save_format (np. SaveFormat.PPTX, DocFormat.HTML)Zapisz jako PDF — każda inna wartość SaveFormat/DocFormat powoduje podniesienie UnsupportedFeatureException zamiast zapisu wyjścia
PdfSecurityException: Password required for encrypted documentOtworzono zaszyfrowany PDF bez argumentu passwordPrzekaż Document(path, password="...") lub wywołaj load_from(path, password="...")
Błąd o jeden w numerach stron pomiędzy PageCollection a PdfFileEditordoc.pages[i] jest indeksowane od 0; argumenty stron PdfFileEditor.extract()/.insert() są indeksowane od 1Dodaj lub odejmij 1 przy konwertowaniu pomiędzy dwoma API
IndexError: Page index out of range. z pages.delete()Indeks przekazany do delete() nie istnieje w kolekcjiSprawdź doc.page_count (lub len(doc.pages)) przed usunięciem

FAQ

Czy potrzebuję licencji, aby używać Aspose.PDF FOSS do Python?

Nie. To jest edycja open-source (na licencji MIT); nie ma pliku licencji ani kroku aktywacji do skonfigurowania.

Czy mogę wyeksportować Document do formatów innych niż PDF?

Nie w tej wersji. save() obsługuje jedynie wyjście PDF — podanie innej wartości SaveFormat/DocFormat powoduje wyrzucenie UnsupportedFeatureException zamiast utworzenia nieprawidłowo oznaczonego pliku.

Jaka jest różnica między Document.merge() a wtyczką Merger?

Document.merge() łączy instancje Document, które już masz otwarte w pamięci. Merger (z MergeOptions i FileDataSource) jest wygodnym wrapperem file-to-file, który otwiera, scala i zapisuje za Ciebie w jednym wywołaniu — przydatnym w prostych skryptach wsadowych, które nigdy nie potrzebują pośredniego obiektu Document.

Dlaczego pages.insert() nigdy nie zgłasza błędu przy indeksie poza zakresem?

PageCollection.insert() ogranicza indeks do prawidłowego zakresu (wartości ujemne stają się 0, wartości poza końcem stają się len(doc.pages)) zamiast podnosić błąd, więc wstawienie nigdy nie kończy się niepowodzeniem wyłącznie z powodu wartości indeksu.

Jak bezpiecznie załadować plik PDF z niewiarygodnego źródła?

Utwórz PdfLoadLimits z wyraźnymi limitami (max_input_bytes, max_pages, max_objects i tak dalej) i przekaż go jako argument limits= do Document(...) lub load_from(). Każde pole ma już domyślną skończoną wartość, ale ściślejsze określenie ich do oczekiwanego rozmiaru wejścia zmniejsza zasoby, które może zużyć nieprawidłowy plik.


API Reference Podsumowanie

Klasa / MetodaOpis
Document() / Document.load_fromUtwórz pusty dokument lub wczytaj go z ścieżki, bajtów lub strumienia binarnego
Document.saveZapisz dokument do ścieżki lub zapisywalnego strumienia (tylko PDF)
Document.dispose() / Document.close()Zwolnij zasoby silnika; idempotentny
Document.pagesPageCollection dokumentu
Document.infoMetadane dokumentu jako dict[str, str]
Document.optimize / Document.optimize_resources / Document.compress_streams()Usuń nieużywane zasoby i skompresuj strumienie
Document.merge()Dołącz inne wystąpienia Document do tego
Document.encrypt / Document.decrypt / Document.change_passwordsZastosuj, usuń lub zmień hasła dokumentu
Document.validate() / Document.check() / Document.repair()Sprawdź i spróbuj naprawić integralność strukturalną
PageCollection.add() / .insert() / .delete() / .item()Edycje strukturalne kolekcji stron (indeksowane od zera)
Page.rect / Page.rotation / Page.indexGeometria i pozycja dla każdej strony
OptimizationOptionsSzczegółowe flagi używane przez Document.optimize
MergeOptions / MergerWtyczka łączenia plików
SplitOptions / SplitterWtyczka rozdzielająca plik na plik, jedna strona na wyjście
FileDataSourceWejście/wyjście oparte na plikach dla API wtyczek
PdfFileEditorFasada dla concatenate(), extract(), insert(), delete(), append() (strony numerowane od 1)
PdfLoadLimitsNiezmienna polityka limitów zasobów dla niezaufanego wejścia
AsposePdfExceptionKlasa bazowa dla wszystkich wyjątków podnoszonych przez bibliotekę
PdfSecurityExceptionPodnoszone w przypadku brakujących/nieprawidłowych haseł i błędów uprawnień
PdfIOExceptionPodnoszone w przypadku błędów I/O podczas przetwarzania PDF

Zobacz także

 Polski