문서 관리

문서 관리

The Document 클래스는 Aspose.PDF FOSS for Python에서 거의 모든 작업의 진입점입니다: 새로운 PDF 생성, 기존 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()는 대상 경로가 이미 존재할 경우, overwrite=True를 전달하지 않으면 FileExistsError을 발생시킵니다. close()는 dispose()의 별칭이며; 두 함수 모두 멱등성이 있으므로 여러 번 호출해도 안전합니다.

저장 대상은 PDF만 구현되어 있습니다 — 이는 라이브러리의 핵심이며 완전하게 작동하는 기능입니다. save()에 SaveFormat.PPTX 또는 DocFormat.HTML과 같은 내보내기 값을 전달하면 잘못된 파일명을 쓰는 대신 UnsupportedFeatureException이 발생하므로, 내보내기 실패가 조용히 넘어가지 않고 항상 명확히 알려집니다.


페이지 컬렉션 관리

doc.pages은(는) PageCollection입니다. len(), 반복, 그리고 0 기반 인덱싱(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 플러그인은 FileDataSource 입력 및 출력으로 만든 MergeOptions/SplitOptions 객체를 받아들입니다:

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 헤더 버전과 트레일러 파일 식별자를 노출합니다. 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을 발생시킵니다.
  • 생성된 PDF를 배포하기 전에 doc.optimize()을 사용하는 것이 좋습니다 — 이는 사용되지 않은 객체를 제거하고 스트림을 압축하는 단일 호출이며, 일반적으로 출력 크기를 눈에 띄게 감소시킵니다.
  • 신뢰할 수 없는 소스(업로드, 이메일 첨부 파일, 웹 스크래핑)에서 PDF를 로드할 때마다 PdfLoadLimits 정책을 명시적으로 설정하십시오; 기본값은 관대하지만 유한하며, 맹목적으로 의존해서는 안 되는 보안 경계가 아닙니다.
  • 로드/저장 호출 주변에서 AsposePdfException(또는 PdfSecurityException과 같은 특정 하위 클래스)를 잡아 처리하십시오, 단순히 Exception만 잡는 것이 아니라 — 이는 라이브러리가 발생시키는 모든 오류의 공통 기반입니다.

일반적인 문제

문제원인수정
FileExistsError save()에대상 경로가 이미 존재하고 overwrite는 기본 False으로 유지되었습니다.통과 save(path, overwrite=True)
UnsupportedFeatureException save()에PDF가 아닌 save_format(예: 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 사이의 페이지 번호가 1씩 차이납니다doc.pages[i]은 0부터 시작합니다; PdfFileEditor.extract()/.insert() 페이지 인자는 1부터 시작합니다두 API 간 변환할 때 1을 더하거나 빼십시오
pages.delete()에서 IndexError: Page index out of range.delete()에 전달된 인덱스가 컬렉션에 존재하지 않습니다삭제하기 전에 doc.page_count(또는 len(doc.pages))를 확인하십시오

FAQ

내게 Aspose.PDF FOSS를 Python에 사용하려면 라이선스가 필요합니까?

아니요. 이것은 오픈소스(MIT-licensed) 에디션이며, 설정할 라이선스 파일이나 활성화 단계가 없습니다.

PDF 외의 형식으로 Document를 내보낼 수 있나요?

이번 릴리스에서는 지원되지 않습니다. save()는 PDF 출력만 구현합니다 — 다른 SaveFormat/DocFormat 값을 전달하면 잘못된 파일명을 만드는 대신 UnsupportedFeatureException이(가) 발생합니다.

Document.merge()와 Merger 플러그인의 차이점은 무엇인가요?

Document.merge()는 메모리에서 이미 열려 있는 Document 인스턴스를 결합합니다. Merger(with MergeOptions and FileDataSource)는 파일-대-파일 편리함을 제공하는 래퍼로, 한 번의 호출로 열고, 병합하고, 저장합니다 — 중간 Document 객체가 필요 없는 간단한 배치 스크립트에 유용합니다.

왜 pages.insert()는 범위를 벗어난 인덱스에 대해 예외를 발생시키지 않나요?

PageCollection.insert()는 인덱스를 유효 범위로 클램프합니다(음수 값은 0이 되고, 끝을 초과하는 값은 len(doc.pages)가 됩니다) — 예외를 발생시키는 대신, 따라서 삽입은 인덱스 값 때문에 실패하지 않습니다.

신뢰할 수 없는 출처의 PDF를 안전하게 로드하려면 어떻게 해야 하나요?

명시적인 상한값(max_input_bytes, max_pages, max_objects 등)을 포함하는 PdfLoadLimits를 구성하고 이를 Document(...) 또는 load_from()에 대한 limits= 인수로 전달하십시오. 모든 필드는 이미 유한한 값으로 기본 설정되어 있지만, 이를 예상 입력 크기에 맞게 제한하면 손상된 파일이 소비할 수 있는 리소스를 줄일 수 있습니다.


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()구조적 페이지 컬렉션 편집 (0 기반)
Page.rect / Page.rotation / Page.index페이지별 기하학 및 위치
OptimizationOptionsDocument.optimize가 사용하는 세밀한 플래그
MergeOptions / Merger파일 간 병합 플러그인
SplitOptions / Splitter파일 간 일 페이지당 출력 분할 플러그인
FileDataSource플러그인 API를 위한 파일 기반 입출력
PdfFileEditorFacade for concatenate(), extract(), insert(), delete(), append() (1 기반 페이지)
PdfLoadLimits신뢰할 수 없는 입력에 대한 불변 리소스 제한 정책
AsposePdfException라이브러리에서 발생시키는 모든 예외의 기본 클래스
PdfSecurityException누락되었거나 잘못된 비밀번호 및 권한 오류가 있을 때 발생
PdfIOExceptionPDF 처리 중 I/O 오류가 발생했을 때 발생

참조

 한국어