PDF 처리 엔진 내부

PDF 처리 엔진 내부

PDF 처리 엔진 내부

당신이 일상적인 PDF 처리를 위해 사용하는 Document, Page, 및 Annotation 클래스는 하위 수준 aspose_pdf.engine 패키지에 대한 파사드입니다. 엔진은 실제 PDF 메커니즘을 구현합니다: 모든 PDF 파일이 구축되는 COS (Carousel Object Structure) 객체 모델, COS 객체와 PDF 바이트 사이를 변환하는 파서와 라이터, 주석 외관 합성, 페이지 래스터화, 글꼴 및 이미지 코덱 내부, 그리고 문서 암호화 및 디지털 서명을 위한 암호 원시 연산. 대부분의 애플리케이션은 aspose_pdf.engine를 직접 임포트할 필요가 없습니다 — 그러나 맞춤형 도구, 포렌식 PDF 검사, 혹은 고수준 API이 노출하지 않는 동작을 필요로 할 때 올바른 장소입니다.


단일 주석에 대한 외관 생성

사각형, 원형, 스탬프와 같은 인터랙티브 주석은 자동으로 일반 외관 스트림 (/AP /N)을 포함하지 않습니다. Annotation.generate_appearance를 호출하면 엔진의 외관 합성 내부 로직이 주석의 속성으로부터 필요에 따라 외관을 생성합니다.

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

페이지와 문서 전체에 걸친 외관 일괄 생성

AnnotationCollection.generate_appearances는 한 번의 호출로 페이지 내 모든 해당 주석에 대한 외관을 합성하며, 엔진이 렌더링 방법을 모르는 하위 유형(예: 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는 문서의 모든 페이지에 대해 동일하게 수행하며, 멱등성을 가집니다 — 외관이 이미 존재하면 두 번째 호출은 아무 작업도 수행하지 않습니다:

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

주석을 정적 페이지 콘텐츠로 평탄화하기

Document.flatten()는 모든 주석의 외관을 페이지의 콘텐츠 스트림에 직접 그립니다(Do XObject 호출으로) 그리고 주석 객체 자체를 제거합니다. 따라서 주석을 완전히 무시하는 뷰어에서도 페이지가 동일하게 렌더링됩니다:

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()

이 호출 이후 페이지의 콘텐츠 스트림은 이전보다 길어지며(이제 인라인된 사각형을 포함합니다) doc.pages[0].annotations는 더 이상 평탄화된 주석을 포함하지 않습니다.


비밀번호 기반 암호화 키 파생 (Revision 4 / AES-128)

EncryptionUtils는 PDF 표준 보안 핸들러의 키 파생 및 AES-CBC 기본 연산을 직접 구현하며, Document API와는 무관합니다. 이는 맞춤형 도구나 암호화된 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

AES-CBC를 사용한 원시 콘텐츠 암호화

낮은 수준의 요구에 대해, EncryptionUtils.encrypt_aes_cbc()와 decrypt_aes_cbc()는 비밀번호 기반 키 파생 과정을 전혀 거치지 않고 16, 24, 또는 32바이트 키에 직접 작동합니다:

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

팁 및 모범 사례

  • 일상적인 문서 처리를 위해 고수준 Document, Page, Annotation 파사드를 사용하는 것이 좋습니다. aspose_pdf.engine 패키지는 해당 클래스들이 기반을 두고 있는 내부 구현이며 — 맞춤 도구, 포렌식 검사, 또는 파사드가 노출하지 않는 동작이 필요할 때만 사용하십시오.
  • revision 인자를 대상 보안 핸들러에 맞추세요: compute_owner_key_v4/compute_user_key_v4는 리비전 2–4(40비트 및 128비트 RC4/AES)를 지원하고, compute_hash_v5은 AES-256에서 사용되는 리비전 5/6 알고리즘을 구현합니다. 리비전과 키 길이를 섞으면 조용히 잘못된 키가 생성됩니다.
  • Document.generate_appearances와 AnnotationCollection.generate_appearances은 멱등합니다 — 스스로 만든 것이 아닌 문서를 렌더링하거나 플래튼하기 전에 방어적으로 호출하세요.
  • Document.flatten()은 파괴적입니다: 페이지 내용에 그린 모든 주석을 제거합니다. 다른 주석 편집을 먼저 마치거나 복사본에서 작업하세요.
  • 모든 주석 하위 유형에 내장된 외관 합성기가 있는 것은 아닙니다 — Text와 Popup이 흔한 예입니다. generate_appearance()을 호출한 후 has_appearance를 확인하고 성공했다고 가정하지 마세요.

일반적인 문제

문제원인해결책
EncryptionUtils.encrypt_aes_cbc/decrypt_aes_cbc은(는) “AES key must be 16, 24, or 32 bytes” 오류를 발생시킵니다잘못된 길이의 키가 제공되었습니다.키를 os.urandom(16), os.urandom(24), 또는 os.urandom(32)로 생성하십시오.
EncryptionUtils.verify_password_v4은(는) 오류를 발생시키는 대신 None을(를) 반환합니다.제공된 비밀번호가 문서에서 파생된 U/O 값과 일치하지 않습니다.결과를 decrypt_aes_cbc에 전달하기 전에 None를 명시적으로 확인하십시오.
Annotation.generate_appearance는 False를 반환합니다.주석의 하위 유형에는 내장된 외관 합성기가 없습니다 (예: Text 또는 Popup).직접 appearance_normal 바이트를 제공하거나 뷰어의 기본 렌더링을 수락하십시오.
Document.generate_appearances에 대한 두 번째 호출은 0를 반환합니다.이 호출은 멱등합니다 — 이미 has_appearance == True가 있는 주석은 건너뛰어집니다.예상되는 동작이며, 오류가 아닙니다.

FAQ

일상적인 문서 처리를 위해 aspose_pdf.engine에서 가져와야 하나요?

아니요. Document, Page, Annotation 클래스는 표준 문서 워크플로를 포괄합니다. 엔진 레이어는 해당 클래스들의 동작이 구현되는 곳이며, 맞춤 도구를 만들거나 PDF 내부를 직접 검사할 때 가장 유용합니다.

Annotation.generate_appearance와 AnnotationCollection.generate_appearances의 차이는 무엇인가요?

첫 번째는 단일 주석에 대한 appearance 스트림을 합성하고 bool를 반환합니다. 두 번째는 컬렉션(페이지의 주석 또는 Document.generate_appearances을 통해 문서의 모든 페이지) 내의 모든 해당 주석에 대해 동일하게 수행하고 생성한 appearance 수를 반환합니다.

키 파생 메서드가 revision 인수를 받는 이유는 무엇인가요?

PDF 표준 보안 핸들러는 ISO 32000 개정판을 거치며 진화해 왔습니다 — Revision 2는 40비트 RC4를 사용하고, Revision 3/4는 128비트 RC4 또는 AES를 지원하며, Revision 5/6(AES-256에 사용됨)은 완전히 다른 해싱 알고리즘(compute_hash_v5)을 사용합니다. revision 인수는 EncryptionUtils 메서드가 수행할 파생 방식을 선택합니다.

원시 PDF 객체를 직접 검사하거나 만들 수 있나요?

예. aspose_pdf.engine.cos는 COS 객체 모델 — PdfObject, PdfDictionary, PdfArray, PdfStream, PdfName 및 관련 타입 —을 노출하며, 이들 PdfCosWriter와 PdfCosParser는 PDF 바이트로 직렬화하고 파싱합니다.

페이지를 이미지로 렌더링하는 과정은 어디에서 이루어지나요?

Document.render_page은(는) RasterizedPage을(를) 반환합니다, 이는 렌더링된 페이지를 이미지 파일로 변환하기 위한 to_png(), to_tiff(), 및 save() 메서드를 가진 엔진 수준 객체입니다.


API Reference 요약

클래스 / 메서드설명
Annotation.generate_appearance(force) -> bool요청 시 하나의 주석에 대한 일반 외관 스트림을 합성합니다
AnnotationCollection.generate_appearances(force) -> int페이지 내 모든 해당 주석에 대한 외관을 일괄 생성합니다
Document.generate_appearances(force) -> int문서 내 모든 해당 주석에 대한 외관을 일괄 생성합니다
Document.flatten() -> Document주석 외관을 페이지 콘텐츠에 인라인으로 삽입하고 주석을 제거합니다
Document.render_page(page_index, dpi, scale, background, antialias) -> RasterizedPage엔진의 렌더링 파이프라인을 통해 페이지를 래스터화합니다
RasterizedPage압축된 RGB 포맷의 렌더링된 페이지, to_png(), to_tiff(), 및 save()와 함께
GeneratedAppearance외관 합성의 내부 결과: 콘텐츠 바이트와 필요한 ExtGState/폰트 리소스
EncryptionUtilsAES-CBC/RC4 암호화 및 PDF 표준 보안 핸들러 키 파생(리비전 2–6)
PdfObject모든 COS (Carousel Object Structure) 객체에 대한 추상 기본 클래스
PdfDictionary / PdfArray / PdfStream저수준 문서 트리를 구성하는 구체적인 COS 컨테이너 유형
PdfName / PdfNumber / PdfString / PdfBoolean / PdfNull원시 COS 값 유형
PdfIndirectReference다른 객체에 대한 COS 간접 참조(n g R)
PdfCosWriter인메모리 COS PdfDocument를 PDF 바이트로 직렬화합니다
PdfCosParser / LazyPdfObjectStorePDF 바이트를 COS 객체로 파싱하고, 필요에 따라 실체화합니다
IncrementalUpdate / IncrementalWriterPDF를 다시 쓰는 대신 기존 PDF에 증분 업데이트 섹션을 추가합니다
SimplePdf고수준 Document API이 구축되는 native-Python 저수준 문서 표현
TextFragmentAbsorber / TextFragmentCollection저수준 텍스트 조각 추출을 SimplePdf 인스턴스에서 수행
ImagePlacementAbsorber / ImagePlacement페이지에 배치된 래스터 이미지를 찾고, 저장하고, 교체하거나 숨깁니다
SigningUtils디지털 서명을 위해 자체 서명 인증서와 PKCS#7/CAdES 서명을 생성합니다
DssMaterial / ChainResult / RevocationResult / TimestampInfo서명 검증 지원: DSS 자료, 인증서 체인 결과, 폐기 검사 및 RFC 3161 타임스탬프 검증
StandardFonts14가지 PDF 표준 글꼴에 대한 메트릭 및 인코딩
CidTextCodec복합 (Type0) 글꼴에 대한 show-strings를 인코딩하고 디코딩합니다
Shading축방향, 방사형 및 함수 기반 셰이딩에 걸친 RGB 색상 샘플링
Color / Matrix엔진 전반에 걸쳐 사용되는 저수준 색상 및 2-D 어핀 변환 프리미티브

참조

 한국어