Pro 에디션
Document — 심층 참조
한눈에 보기
섹션 제목: “한눈에 보기”Document 모듈은 세 가지 Pro 조립 기본 요소를 제공합니다: 페이지 범위 분할, 다중 문서 병합, 그리고 PDF Portfolio(Collection) 딕셔너리 구성입니다. PdfSplitter는 페이지 범위를 독립형의 구조적으로 적합한 PDF로 추출하고, 전체 문서를 하나의 재번호가 매겨진 파일로 병합합니다. PdfPortfolio는 정렬 가능한 스키마 열과 함께 임베디드 파일을 표시하는 Collection 딕셔너리를 구성합니다. 모든 진입점은 악의적 입력에 대비하여 입력 크기와 객체 개수를 제한합니다.
가용성 및 라이선싱
섹션 제목: “가용성 및 라이선싱”이 기능은 NextPDF Pro(nextpdf/pro)로 제공되며 Pro 등급 라이선스 엔벨로프로 활성화됩니다. 해당 사용 권한이 없는 배포 환경은 이 기능의 클래스를 로드하지 않습니다. 에디션을 비교하고 라이선스를 받으십시오.
공개 API 표면
섹션 제목: “공개 API 표면”모든 모듈 타입은 NextPDF\Pro\Document 네임스페이스에 있습니다. PageRange와 MergeResult는 NextPDF\Document의 Core 값 객체입니다.
| 심볼 | 매개변수 | 기본 동작 | 반환 | 예외 또는 실패 조건 | 비고 |
|---|---|---|---|---|---|
PdfSplitter::split() | string $pdfData, list<PageRange> $ranges, int $maxBytes = 100_000_000, int $maxRanges = 1000 | 범위마다 독립형 PDF 세그먼트를 하나씩 구성 | SplitResult | %PDF 헤더 누락 시 InvalidArgumentException; 크기, 범위 개수, 클로저 가드 위반 시 OverflowException | 가드는 모든 파싱 이전에 실행됨 |
PdfSplitter::splitEvery() | string $pdfData, int $pagesPerSegment | 연속하는 N-페이지 범위를 도출하며 마지막 세그먼트는 더 짧을 수 있음 | SplitResult | $pagesPerSegment < 1이거나 헤더가 없을 때 InvalidArgumentException | 기본 상한으로 split()에 위임 |
PdfSplitter::extractPages() | string $pdfData, PageRange $range | 단일 범위를 독립형 PDF 바이트로 반환 | string | 헤더 누락 시 InvalidArgumentException; 클로저 가드 위반 시 OverflowException | 이 경로에는 상한 매개변수가 없음 |
PdfSplitter::mergeDocuments() | list<string> $pdfs, int $maxInputs = 100, int $maxBytesEach = 100_000_000 | 입력을 순서대로 하나의 재번호가 매겨진 PDF로 병합 | MergeResult | 빈 목록이거나 비-PDF 입력 시 InvalidArgumentException; 개수, 입력별 크기, 클로저 가드 위반 시 OverflowException | 3.1.0부터; 가장 높은 입력 버전이 출력 헤더를 결정 |
SplitResult | readonly $segments, $ranges, $totalPages | 원시 세그먼트 바이트와 소스 메타데이터를 담음 | — | — | final readonly 값 객체 |
SplitResult::count() | — | 생성된 세그먼트 수를 셈 | int | — | — |
SplitResult::segment() | int $index | 단일 세그먼트의 바이트를 반환 | string | 범위를 벗어난 인덱스 시 OutOfRangeException | 0부터 시작하는 인덱스 |
PdfPortfolio::__construct() | string $viewMode = 'tile' | 생성 시점에 보기 모드를 검증 | — | tile, detail, hidden 이외의 모드 시 InvalidArgumentException | — |
PdfPortfolio::addSchema() | PortfolioField $field | 스키마 열을 추가 | self | — | 플루언트 |
PdfPortfolio::addEntry() | PortfolioEntry $entry | 파일 항목을 추가 | self | — | 플루언트 |
PdfPortfolio::getSchema() | — | 누적된 스키마 필드를 반환 | list<PortfolioField> | — | — |
PdfPortfolio::getEntries() | — | 누적된 파일 항목을 반환 | list<PortfolioEntry> | — | — |
PdfPortfolio::count() | — | 파일 항목 수를 셈 | int | — | — |
PdfPortfolio::generateCollectionDictionary() | — | Collection 딕셔너리 문자열을 방출 | string | — | 스키마 및 정렬 블록은 필드가 있을 때만 나타남 |
PortfolioEntry | $filename, $data, $description = '', $mimeType = 'application/octet-stream', $customFields = [] | 불변 파일 항목 값 객체 | — | — | size()는 데이터 바이트 길이를 반환 |
PortfolioField | $name, PortfolioFieldType $type, $displayName = '', $order = 0, $visible = true | 불변 스키마 열 값 객체 | — | — | effectiveDisplayName()은 $name으로 대체됨 |
PortfolioFieldType | 문자열 열거형: Text, Date, Number, FileName, Description, Size, ModDate, CreationDate | pdfSubtype()를 통해 각 케이스를 PDF /Subtype에 매핑 | string (S, D, N, F, Desc) | — | 날짜 계열 케이스는 서브타입 D를 공유; 숫자 케이스는 N을 공유 |
진입점 시그니처:
public function split(string $pdfData, array $ranges, int $maxBytes = 100_000_000, int $maxRanges = 1000): SplitResult
public function mergeDocuments( array $pdfs, int $maxInputs = 100, int $maxBytesEach = 100_000_000,): MergeResultpublic function __construct( private readonly string $viewMode = 'tile',)
public function generateCollectionDictionary(): string동작 계약
섹션 제목: “동작 계약”분할과 병합은 하나의 객체 그래프 파이프라인을 공유합니다:
- 입력은
%PDF헤더로 시작해야 합니다. 크기와 개수 가드는 파싱 이전에 실행되며 위반 시OverflowException을 발생시킵니다. - 리프 페이지는 페이지 객체 마커를 스캔하여 탐지되며, 페이지 트리 노드는 개수에서 제외됩니다.
- 파서는 스트림을 인식하는 종결자 스캔으로 모든 비압축 간접 객체를 인덱싱합니다. 객체 id의 첫 번째 출현이 우선하므로, 증분 업데이트 재정의는 적용되지 않습니다.
- 상속 가능한 페이지 트리 속성(
/Resources,/MediaBox,/CropBox,/Rotate)은/Parent체인을 따라가며 추출된 각 페이지에 실체화되므로, 세그먼트는 독립형입니다. - 각 페이지의 전이적 간접 참조 클로저는
/Parent역방향 간선을 제외하고 수집되며, 새로운 연속 id 공간으로 재번호가 매겨집니다. - 직렬화기는 헤더, Catalog, Pages 트리, 페이지 객체, 클로저 객체를 방출한 뒤, 바이트 단위로 정확한 오프셋을 갖춘 상호 참조 테이블과
xref키워드를 가리키는startxref를 방출합니다. mergeDocuments는 이 파이프라인을 입력마다 하나의 공유 id 공간으로 반복합니다. 가장 높은 입력 PDF 버전이 출력 헤더를 결정합니다. 이것은 비활성화된 Core 병합기의 적합한 대체물이며, Core 병합기는 fail-closed 상태로 유지됩니다.- 출력은 결정론적입니다. 타임스탬프나 무작위 식별자가 방출되지 않으므로, 동일한 입력은 동일한 바이트를 산출합니다.
Portfolio 조립:
- 생성자는 보기 모드를 검증합니다. 방출되는
/View토큰은 tile, detail, hidden에 대해 각각/T,/D,/H입니다. generateCollectionDictionary()는/Type /Collection,/View토큰, 필드가 있을 때/Schema블록, 그리고 첫 번째 스키마 필드에 대한 오름차순/Sort지시문을 방출합니다.- 각 스키마 필드는
/Subtype(pdfSubtype()에서),/N(이스케이프된 표시 이름),/O(순서),/V(가시성)를 방출합니다. - 필드 이름은 유효한 PDF name 토큰으로 살균되며, 단어가 아닌 문자는 밑줄이 됩니다. 문자열 값은 PDF 리터럴 문자열로 이스케이프됩니다.
- 파일 항목은 작성 계층의 임베딩을 위해
getEntries()를 통해 노출됩니다. Collection 딕셔너리 자체는 보기, 스키마, 정렬만 담습니다.
엣지 케이스 및 실패 모드
섹션 제목: “엣지 케이스 및 실패 모드”- 어떤 페이지와도 일치하지 않는 범위는 오류가 아니라 최소 단일 페이지 세그먼트(612 x 792 MediaBox)를 산출합니다.
- 탐지 가능한 페이지 마커가 없는 문서는 한 페이지로 계산됩니다.
- 객체 스트림 내부에 저장된 페이지는 탐지되지 않습니다. 비압축 간접 객체만 추출에 참여합니다.
- 중복 객체 id가 존재하면 가장 낮은 오프셋의 리비전이 사용되며, 이후 증분 업데이트 리비전은 무시됩니다.
- 세그먼트별 참조 클로저는 50,000개 객체로 제한됩니다. 악의적으로 자기 참조하거나 팬아웃하는 그래프는
OverflowException을 발생시킵니다. - 기본 상한: 입력 100 MB, 범위 1,000개, 병합 입력 100개. 모두 호출마다 호출자가 조정할 수 있습니다.
splitEvery()는 1 미만의 세그먼트 크기를InvalidArgumentException으로 거부합니다.SplitResult::segment()는 범위를 벗어난 인덱스를OutOfRangeException으로 거부합니다.- 구두점에서만 차이가 나는 두 스키마 필드 이름은 동일한 딕셔너리 키로 살균되며, 방출된 스키마에서 나중 필드가 이전 필드를 조용히 가립니다.
- 이 모듈은 어떠한 암호화 연산도 수행하지 않습니다. FIPS 모드는 이 모듈의 동작을 변경하지 않습니다.
적합성
섹션 제목: “적합성”세그먼트 및 병합 출력은 ISO 32000-2의 페이지 객체 모델을 따르며, 소스가 관련 절을 주석으로 표기합니다. 외부에서 검증 가능한 주장:
- 트레일러 레이아웃,
startxref바이트 오프셋,%%EOF종결자는 ISO 32000-2:2020, §7.5.5를 따릅니다 — 참조ef0f2a4b563b84f81b3e6428612bc47c510d94fc8096849d339abf0f3247d845. - Collection 딕셔너리
/View값(/T,/D,/H)은 ISO 32000-2:2020, §12.3.5를 따릅니다 — 참조5cefaaeb40f3ff98e3aba135ac57c9424a05c43144c1b9b5156bfd4295e08ddd. - Collection 필드
/Subtype,/N,/O,/V항목은 ISO 32000-2:2020, §12.3.5(collection field dictionary)를 따릅니다 — 참조6300fbfdc8a913a8dc6f6ae34eff99f2bd03c4313a77777cdd5a8dd856d9537a.
이 진술들은 모듈의 테스트로 검증된 구현된 기능을 설명합니다. 어떤 구조에 대한 지원이 적합성 주장은 아니며, 적합성은 인증이 아닙니다. NextPDF는 이 모듈에 대해 제3자 인증을 보유하지 않습니다.
개발 노트
섹션 제목: “개발 노트”- 모든 모듈 클래스는
final이며, 결과 및 값 객체 타입은readonly입니다. splitter와 Portfolio 타입은 1.9.0부터이며,mergeDocuments()는 3.1.0에 추가되었습니다. PageRange와MergeResult는 Core 타입이므로, 호출 지점은 에디션 이식성을 유지합니다.- 세그먼트 트레일러는
/Size와/Root만 담습니다./ID파일 식별자나/Info딕셔너리는 방출되지 않습니다. - 증분 업데이트 또는 서명 워크플로의 경우, 세그먼트 바이트를 제자리에서 후편집하지 말고 Writer 모듈에 넘기십시오.
- 이 모듈은 문서 내용을 로깅하지 않습니다.
게시 경계
섹션 제목: “게시 경계”이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 테이블, 런북 파일명, 티켓 접두사는 범위를 벗어납니다.