Wewnętrzna struktura silnika przetwarzania PDF

Wewnętrzna struktura silnika przetwarzania PDF

Wewnętrzne mechanizmy silnika przetwarzania PDF

Klasy Document, Page i Annotation, których używasz do codziennego przetwarzania PDF, są fasadą nad niższym poziomem pakietu aspose_pdf.engine. Silnik implementuje rzeczywiste mechanizmy PDF: model obiektowy COS (Carousel Object Structure), z którego zbudowany jest każdy plik PDF, parser i writer, które konwertują pomiędzy obiektami COS a bajtami PDF, syntezę wyglądu adnotacji, rasteryzację stron, wewnętrzne kodeki czcionek i obrazów oraz prymitywy kryptograficzne stojące za szyfrowaniem dokumentu i podpisami cyfrowymi. Większość aplikacji nigdy nie musi importować bezpośrednio z aspose_pdf.engine — ale jest to właściwe miejsce, aby zajrzeć, gdy potrzebujesz własnych narzędzi, forensycznej inspekcji PDF lub zachowań, których wysokopoziomowy API nie udostępnia.


Generowanie wyglądu dla pojedynczej adnotacji

Interaktywne adnotacje, takie jak kwadraty, koła i pieczątki, nie zawierają automatycznie normalnego strumienia wyglądu (/AP /N). Wywołanie Annotation.generate_appearance uruchamia wewnętrzne mechanizmy syntezy wyglądu silnika, aby na żądanie zbudować go na podstawie właściwości adnotacji.

from aspose_pdf import Document

doc = Document()
doc.pages.add()
ann = doc.pages[0].annotations.add(
    "Square", (100, 100, 200, 200), "", properties={"C": [1, 0, 0], "IC": [0, 1, 0]}
)

print(ann.has_appearance)  # False -- no appearance stream yet
ann.generate_appearance()
print(ann.has_appearance)  # True -- the engine synthesised one
print(b"1 0 0 RG" in ann.appearance_normal)  # True -- red stroke operator
print(b"0 1 0 rg" in ann.appearance_normal)  # True -- green fill operator

Masowe generowanie wyglądów na stronach i w dokumentach

AnnotationCollection.generate_appearances syntezuje wyglądy dla każdej kwalifikującej się adnotacji na stronie w jednym wywołaniu, pomijając podtypy, które silnik nie potrafi renderować (np. Text):

from aspose_pdf import Document

doc = Document()
doc.pages.add()
page = doc.pages[0]
page.annotations.add("Square", (0, 0, 50, 50), "")
page.annotations.add("Circle", (60, 0, 110, 50), "")
page.annotations.add("Text", (0, 60, 20, 80), "")  # unsupported subtype -> skipped

print(page.annotations.generate_appearances())  # 2

Document.generate_appearances robi to samo na każdej stronie dokumentu i jest idempotentny — drugie wywołanie jest operacją pustą, gdy wyglądy już istnieją:

from aspose_pdf import Document

doc = Document()
doc.pages.add()
doc.pages.add()
doc.pages[0].annotations.add("Square", (0, 0, 50, 50), "")
doc.pages[1].annotations.add(
    "Line", (0, 0, 50, 50), "", properties={"L": [0, 0, 50, 50]}
)

print(doc.generate_appearances())  # 2 -- one per page
print(doc.generate_appearances())  # 0 -- already generated, no-op

Spłaszczanie adnotacji w statyczną treść strony

Document.flatten() rysuje każdy wygląd adnotacji bezpośrednio w strumieniu zawartości strony (jako wywołanie Do XObject) i następnie usuwa sam obiekt adnotacji, tak aby strona renderowała się identycznie w przeglądarkach, które całkowicie ignorują adnotacje:

from aspose_pdf import Document

doc = Document()
doc.pages.add()
doc.pages[0].annotations.add(
    "Square", (100, 100, 200, 200), "", properties={"C": [0, 0, 0]}
)

doc.flatten()

Po tym wywołaniu strumień zawartości strony jest dłuższy niż wcześniej (zawiera teraz wstawiony kwadrat) i doc.pages[0].annotations już nie zawiera spłaszczonej adnotacji.


Wyprowadzanie kluczy szyfrowania opartego na haśle (rewizja 4 / AES-128)

EncryptionUtils implementuje bezpośrednio wyprowadzanie kluczy oraz prymitywy AES-CBC obsługi standardowego handlera zabezpieczeń PDF, niezależnie od Document API. Jest to przydatne przy tworzeniu własnych narzędzi lub forensycznej analizie zaszyfrowanych plików PDF:

import os
from aspose_pdf.engine.encryption import EncryptionUtils

file_id = os.urandom(16)
user_pwd = "mypassword"

# Derive the owner (O) and user (U) key material for Revision 4 (128-bit AES)
o_value = EncryptionUtils.compute_owner_key_v4("owner", user_pwd, 16, 4)
u_value, enc_key = EncryptionUtils.compute_user_key_v4(
    user_pwd, o_value, -4, file_id, 16, 4
)

# Encrypt data with the derived file-encryption key
plaintext = b"Confidential PDF content"
ciphertext = EncryptionUtils.encrypt_aes_cbc(enc_key, plaintext)

# Re-derive the key from the password before trusting it to decrypt
verified_key = EncryptionUtils.verify_password_v4(
    user_pwd, u_value, o_value, -4, file_id, 16, 4
)
print(verified_key is not None)  # True -- password matches

decrypted = EncryptionUtils.decrypt_aes_cbc(verified_key, ciphertext)
print(decrypted == plaintext)  # True

Szyfrowanie surowej zawartości przy użyciu AES-CBC

Dla potrzeb niższego poziomu, EncryptionUtils.encrypt_aes_cbc() i decrypt_aes_cbc() działają bezpośrednio na dowolnym kluczu o długości 16, 24 lub 32 bajtów, pomijając całkowicie wyprowadzanie klucza opartego na haśle:

import os
from aspose_pdf.engine.encryption import EncryptionUtils

key = os.urandom(32)  # AES-256; 16 and 24-byte keys are also accepted
plaintext = b"Hello, PDF AES 256!"

ciphertext = EncryptionUtils.encrypt_aes_cbc(key, plaintext)
decrypted = EncryptionUtils.decrypt_aes_cbc(key, ciphertext)
print(decrypted == plaintext)  # True

Wskazówki i najlepsze praktyki

  • Preferuj wysokopoziomową fasadę Document, Page i Annotation do codziennego przetwarzania dokumentów. Pakiet aspose_pdf.engine jest wewnętrzną implementacją, na której opierają się te klasy — sięgaj po niego tylko wtedy, gdy potrzebujesz własnych narzędzi, analizy forensic lub zachowań, których fasada nie udostępnia.
  • Dopasuj argument revision do obsługi zabezpieczeń, którą celujesz: compute_owner_key_v4/compute_user_key_v4 obejmują rewizje 2–4 (40- i 128-bitowe RC4/AES), natomiast compute_hash_v5 implementuje algorytm rewizji 5/6 używany przez AES-256. Mieszanie rewizji i długości klucza cicho generuje nieprawidłowy klucz.
  • Document.generate_appearances i AnnotationCollection.generate_appearances są idempotentne — wywołuj je ostrożnie przed renderowaniem lub spłaszczaniem dokumentu, którego nie stworzyłeś sam.
  • Document.flatten() jest destrukcyjny: usuwa każdą adnotację, którą wstawia do treści strony. Najpierw zakończ edycję innych adnotacji lub pracuj na kopii.
  • Nie każdy podtyp adnotacji ma wbudowany syntezator wyglądu — Text i Popup są powszechnymi przykładami. Sprawdź has_appearance po wywołaniu generate_appearance(), zamiast zakładać, że zakończyło się sukcesem.

Typowe problemy

ProblemPrzyczynaRozwiązanie
EncryptionUtils.encrypt_aes_cbc/decrypt_aes_cbc zwraca błąd „AES key must be 16, 24, or 32 bytes”Podano klucz o nieprawidłowej długościWygeneruj klucz przy użyciu os.urandom(16), os.urandom(24) lub os.urandom(32)
EncryptionUtils.verify_password_v4 zwraca None zamiast podnosić błądPodane hasło nie pasuje do wyprowadzonych z dokumentu wartości U/OSprawdź wyraźnie None przed przekazaniem wyniku do decrypt_aes_cbc
Annotation.generate_appearance zwraca FalsePodtyp adnotacji nie ma wbudowanego syntezatora wyglądu (na przykład Text lub Popup)Podaj własne bajty appearance_normal lub zaakceptuj domyślne renderowanie przeglądarki
Drugie wywołanie Document.generate_appearances zwraca 0Wywołanie jest idempotentne — adnotacje, które już mają has_appearance == True, są pomijaneOczekiwane zachowanie, a nie błąd

FAQ

Czy muszę importować z aspose_pdf.engine do codziennego przetwarzania dokumentów?

Nie. Klasy Document, Page i Annotation obejmują standardowe przepływy dokumentów. Warstwa silnika jest miejscem, w którym zachowanie tych klas jest implementowane i jest najbardziej przydatna do własnych narzędzi lub bezpośredniego przeglądania wewnętrznych struktur PDF.

Jaka jest różnica między Annotation.generate_appearance a AnnotationCollection.generate_appearances?

Pierwszy syntetyzuje strumień wyglądu dla pojedynczej adnotacji i zwraca bool. Drugi robi to samo dla każdej kwalifikującej się adnotacji w kolekcji (adnotacji na stronie lub, za pośrednictwem Document.generate_appearances, każdej strony w dokumencie) i zwraca liczbę utworzonych wyglądów.

Dlaczego metody wyprowadzania klucza przyjmują argument revision?

Obsługa zabezpieczeń standardu PDF ewoluowała w kolejnych rewizjach ISO 32000 — Revizja 2 używa 40-bitowego RC4, Revizje 3/4 obsługują 128-bitowy RC4 lub AES, a Revizje 5/6 (używane dla AES-256) stosują zupełnie inny algorytm haszujący (compute_hash_v5). Argument revision wybiera, którą metodę wyprowadzania mają wykonać metody EncryptionUtils.

Czy mogę bezpośrednio przeglądać lub tworzyć surowe obiekty PDF?

Tak. aspose_pdf.engine.cos udostępnia model obiektów COS — PdfObject, PdfDictionary, PdfArray, PdfStream, PdfName oraz powiązane typy — które PdfCosWriter i PdfCosParser serializują do i parsują z bajtów PDF.

Gdzie odbywa się renderowanie stron na obrazy?

Document.render_page zwraca RasterizedPage, obiekt na poziomie silnika z metodami to_png(), to_tiff() i save() umożliwiającymi przekształcenie wyrenderowanej strony w plik obrazu.


API Reference Podsumowanie

Klasa / MetodaOpis
Annotation.generate_appearance(force) -> boolSyntezuj normalny strumień appearance dla jednej adnotacji na żądanie
AnnotationCollection.generate_appearances(force) -> intMasowo generuj appearance dla każdej kwalifikującej się adnotacji na stronie
Document.generate_appearances(force) -> intMasowo generuj appearance dla każdej kwalifikującej się adnotacji w dokumencie
Document.flatten() -> DocumentWstaw inline appearance adnotacji do treści strony i usuń adnotacje
Document.render_page(page_index, dpi, scale, background, antialias) -> RasterizedPageRasteryzuj stronę poprzez potok renderowania silnika
RasterizedPageWyrenderowana strona w spakowanym formacie RGB, z to_png(), to_tiff() i save()
GeneratedAppearanceWewnętrzny wynik syntezy wyglądu: bajty treści oraz wszelkie wymagane zasoby ExtGState/font
EncryptionUtilsAES-CBC/RC4 szyfrowanie i wyprowadzanie klucza standardowego obsługującego zabezpieczenia PDF (Rewizje 2–6)
PdfObjectAbstrakcyjna klasa bazowa dla każdego obiektu COS (Carousel Object Structure)
PdfDictionary / PdfArray / PdfStreamKonkretne typy kontenerów COS, które tworzą niskopoziomowe drzewo dokumentu
PdfName / PdfNumber / PdfString / PdfBoolean / PdfNullPodstawowe typy wartości COS
PdfIndirectReferencePośrednie odwołanie COS (n g R) do innego obiektu
PdfCosWriterSerializuje w pamięci COS PdfDocument do bajtów PDF
PdfCosParser / LazyPdfObjectStoreAnalizuje bajty PDF na obiekty COS, materializując je na żądanie
IncrementalUpdate / IncrementalWriterDołącz sekcję aktualizacji przyrostowej do istniejącego PDF zamiast go przepisywać
SimplePdfNatywna-Python niskopoziomowa reprezentacja dokumentu, na której opiera się wysokopoziomowy Document API
TextFragmentAbsorber / TextFragmentCollectionNiskopoziomowe wyodrębnianie fragmentów tekstu z instancji SimplePdf
ImagePlacementAbsorber / ImagePlacementZlokalizuj, zapisz, zamień lub ukryj obrazy rastrowe umieszczone na stronie
SigningUtilsGeneruj certyfikaty własnoręcznie podpisane oraz podpisy PKCS#7/CAdES do podpisywania cyfrowego
DssMaterial / ChainResult / RevocationResult / TimestampInfoObsługa weryfikacji podpisu: materiały DSS, wyniki łańcucha certyfikatów, sprawdzanie odwołań oraz weryfikacja znaczników czasu zgodnie z RFC 3161
StandardFontsMetryki i kodowania dla 14 standardowych czcionek PDF
CidTextCodecKodowanie i dekodowanie ciągów show dla czcionek kompozytowych (Type0)
ShadingPróbka koloru RGB w shadingach axialnych, radialnych i opartych na funkcji
Color / MatrixNiskopoziomowe prymitywy koloru i dwuwymiarowych transformacji afinicznych używane w całym silniku

Zobacz także

 Polski