콘텐츠로 이동
getnextpdf.com

Pro 에디션

Writer — 심층 참조

Writer 모듈은 PDF 증분 업데이트(incremental-update) 리비전을 작성하고 작은 객체를 Object Stream으로 패킹합니다. 증분 writer는 실패 시 닫힘(fail-closed) 추가 전용(append-only) 규칙을 강제합니다. 즉, 버퍼가 리비전 이전에 보유했던 모든 바이트는 리비전 이후에도 변경되지 않은 채로 남아야 합니다. Object Stream 빌더는 적격 객체들을 제한된 크기 이내의 하나의 FlateDecode로 압축된 /Type /ObjStm 객체로 그룹화합니다.

이 기능은 NextPDF Pro(nextpdf/pro)로 제공되며 Pro 등급 라이선스 봉투(license envelope)로 활성화됩니다. 해당 자격이 없는 배포는 이 기능의 클래스를 로드하지 않습니다. 에디션을 비교하고 라이선스를 받으십시오. 기능별 라이선스 플래그는 없으며, 코드는 Pro 에디션과 함께 제공됩니다.

이 모듈은 NextPDF\Pro\Writer 네임스페이스 아래에 있습니다. 모든 공개 심볼은 아래에 나열되어 있습니다. 값 객체는 불변(immutable) final readonly 클래스입니다.

심볼매개변수기본 동작반환예외 또는 실패비고
IncrementalUpdateWriter::writeRevisionBinaryBuffer $buffer, ObjectRegistry $registry, int $prevXrefOffset, int $catalogObject, array $catalogEntries, array $catalogUpdates, array $newObjectNumbers, string $fileId정적. 병합된 항목으로 카탈로그를 다시 작성하고, 새 객체와 수정된 객체에 대한 전통적 상호 참조 테이블을 추가하며, /Size, /Root, /Prev, /ID가 있는 트레일러를 작성합니다. 이후 리비전 이전 접두사(prefix)가 바이트 동일한지 검증합니다.int — 새 상호 참조 테이블의 바이트 오프셋추가 전용 접두사 검사가 실패하면 \NextPDF\Exception\WriterException; getWriterState()dss-append-only-invariant를 반환합니다정적 진입점. 위반 시 사용 가능한 출력 없음.
ObjectStreamWriter::addObjectint $objectNumber, string $content크기 검사 후 대기 중인 스트림에 하나의 객체를 추가합니다.void결합된 인덱스와 본문이 65,536바이트를 초과할 때 OverflowException$contentN 0 obj / endobj 래퍼를 제외합니다.
ObjectStreamWriter::canAcceptstring $content인덱스 오버헤드를 추정하고 누적 합계를 최대값과 비교하여 검사합니다.bool예외를 던지지 않음순수 술어(predicate); 상태 변경 없음.
ObjectStreamWriter::build없음인덱스를 만들고, 본문을 연결하며, FlateDecode로 압축하고, /Type /ObjStm 딕셔너리로 래핑합니다.string — 원시 Object Stream 콘텐츠추가된 객체가 없거나 zlib 압축 실패 시 ObjectStreamWriteException호출자가 객체 번호를 할당하고 마커를 래핑합니다.
ObjectStreamWriter::getEntries없음누적된 객체들에 대해 본문 상대 오프셋을 다시 계산합니다.list<ObjectStreamEntry>예외를 던지지 않음오프셋은 본문 섹션에 대해 상대적입니다.
ObjectStreamWriter::count없음누적된 객체 수를 보고합니다.int예외를 던지지 않음
ObjStmCompressor::__constructint $maxStreamSize = 65536, int $maxObjectsPerStream = 200그룹화에 사용되는 크기 및 객체 수 한계를 저장합니다.예외를 던지지 않음기본값은 모듈의 Object Stream 튜닝과 일치합니다.
ObjStmCompressor::groupObjectslist<array{number: int, generation?: int, content: string}> $objects부적격 객체를 필터링한 후, 나머지를 크기 및 개수 한계 이내의 writer들로 패킹합니다.list<ObjectStreamWriter>예외를 던지지 않음; 부적격 객체는 건너뜀0이 아닌 세대(generation) 객체는 일반 직렬화로 넘어갑니다.
ObjStmCompressor::isEligiblestring $content, int $generation = 0스트림 객체, /Encrypt, /XRef, /Catalog, 그리고 0이 아닌 모든 세대를 거부합니다.bool예외를 던지지 않음/Type 매칭은 공백 및 #xx 이스케이프에 관용적입니다.
ObjStmCompressor::writeToBufferlist<ObjectStreamWriter> $streams, BinaryBuffer $buffer, ObjectRegistry $registry스트림당 캐리어 객체를 할당하고, type-2 압축 항목을 등록하며, 각 ObjStm 블록을 작성합니다.list<int> — 캐리어 객체 번호드문 압축 실패 시 build()ObjectStreamWriteException를 전파합니다비적격 객체가 작성된 후, 상호 참조가 방출되기 전에 실행합니다.
ObjStmCompressor::estimateSavingslist<ObjectStreamWriter> $streams, int $originalSize각 스트림을 빌드하여 압축 크기를 원본과 비교 측정합니다.ObjStmCompressionResult드문 압축 실패 시 build()ObjectStreamWriteException를 전파합니다읽기 전용 측정 헬퍼.
ObjectStreamEntry::__constructint $objectNumber, string $content, int $offset패킹된 하나의 객체와 그 본문 오프셋의 불변 레코드입니다.예외를 던지지 않음final readonly; 공개 속성.
ObjStmCompressionResult::__constructint $originalObjectCount, int $streamCount, int $estimatedOriginalSize, int $estimatedCompressedSize불변 메트릭 컨테이너입니다.예외를 던지지 않음final readonly; 공개 속성.
ObjStmCompressionResult::savedBytes없음원본에서 압축 크기를 뺀 값을 반환합니다.int예외를 던지지 않음패킹이 데이터를 확장한 경우 음수일 수 있습니다.
ObjStmCompressionResult::savedPercent없음감소 백분율을 반환합니다.float예외를 던지지 않음원본 크기가 0이면 0.0을 반환합니다.
ObjStmCompressionResult::compressionRatio없음원본 대비 압축 크기를 반환합니다.float예외를 던지지 않음원본 크기가 0이면 1.0을 반환합니다.
ObjectStreamWriteExceptionObject Stream 빌드 실패를 알립니다.RuntimeException을 확장build()가 던집니다; 하위 호환성을 위해 RuntimeException로 캐치 가능합니다.
final class IncrementalUpdateWriter
{
public static function writeRevision(
BinaryBuffer $buffer,
ObjectRegistry $registry,
int $prevXrefOffset,
int $catalogObject,
array $catalogEntries,
array $catalogUpdates,
array $newObjectNumbers,
string $fileId,
): int;
}
final class ObjectStreamWriter
{
public function addObject(int $objectNumber, string $content): void;
public function canAccept(string $content): bool;
public function build(): string;
/** @return list<ObjectStreamEntry> */
public function getEntries(): array;
public function count(): int;
}
final class ObjStmCompressor
{
public function __construct(
int $maxStreamSize = 65536,
int $maxObjectsPerStream = 200,
);
/**
* @param list<array{number: int, generation?: int, content: string}> $objects
* @return list<ObjectStreamWriter>
*/
public function groupObjects(array $objects): array;
public function isEligible(string $content, int $generation = 0): bool;
/**
* @param list<ObjectStreamWriter> $streams
* @return list<int>
*/
public function writeToBuffer(array $streams, BinaryBuffer $buffer, ObjectRegistry $registry): array;
/** @param list<ObjectStreamWriter> $streams */
public function estimateSavings(array $streams, int $originalSize): ObjStmCompressionResult;
}

writeRevision은 하나의 증분 업데이트 리비전을 작성합니다. 작성하기 전에 기존 버퍼 접두사를 스냅샷합니다. 병합된 항목으로 카탈로그를 다시 작성하고, 새 객체 오프셋을 등록하며, 인접한 하위 섹션으로 그룹화된 전통적 상호 참조 테이블을 작성하고, /Size, /Root, /Prev, /ID가 있는 트레일러를 작성합니다. 작성 후 접두사를 다시 비교합니다. 더 앞선 바이트가 하나라도 변경되었다면, 추가 전용 위반(append-only-violation) 상태를 담은 WriterException을 발생시키며 사용 가능한 출력을 반환하지 않습니다. 성공 시 추가 리비전을 체이닝하기 위한 새 상호 참조 테이블의 바이트 오프셋을 반환합니다. 리비전 간에 상호 참조 테이블과 스트림을 혼합하는 것은 허용됩니다.

ObjectStreamWriter는 객체를 누적합니다. addObject는 결합된 인덱스와 본문이 최대값인 비압축 65,536바이트를 초과할 때 오버플로 오류를 발생시킵니다. build는 빈 스트림에서 오류를 발생시킵니다. 그렇지 않으면 인덱스와 본문을 압축하여 /Type /ObjStm, /N, /First, /Length, /Filter /FlateDecode 항목이 있는 Object Stream 콘텐츠를 반환합니다. 호출자가 객체 번호를 할당하고 N 0 obj / endobj 마커를 래핑합니다.

ObjStmCompressor는 어떤 객체를 패킹할지 결정합니다. 스트림 객체, 암호화 딕셔너리, 상호 참조 스트림, 문서 카탈로그, 그리고 0이 아닌 세대 번호를 가진 모든 객체를 제외합니다. writeToBuffer는 스트림당 캐리어 객체를 할당하고, 패킹된 각 객체를 type-2 압축 상호 참조 항목으로 등록하며, 현재 버퍼 오프셋에 ObjStm 블록을 작성합니다. estimateSavings는 버퍼를 변형하지 않고 각 스트림을 빌드하여 크기 메트릭을 계산합니다.

  • 추가 전용 검사는 기존 접두사를 복사합니다. 그 비용은 이미 작성된 문서의 크기에 따라 증가합니다. 이 비용은 의도된 것이며 서명된 바이트를 보호합니다.
  • Object Stream 한계는 비압축 인덱스와 본문에 적용됩니다. 암호화 딕셔너리와 기타 제외되는 객체 타입은 직접 간접 객체(direct indirect objects)로 배치하십시오.
  • /Type 제외는 임의의 토큰 간 공백과 #xx 16진 이스케이프에 관용적입니다. /Type /Encrypt, /Type\n/Encrypt, /Type /#45ncrypt 같은 형태는 표준 리터럴 철자뿐 아니라 모두 거부됩니다.
  • 0이 아닌 세대 번호를 가진 모든 객체는 부적격으로 취급되어 일반 N G obj … endobj 직렬화로 넘어갑니다. 압축된 객체의 세대는 암묵적으로 0이기 때문입니다.
  • writeToBuffer는 모든 비적격 객체가 작성된 후, 상호 참조가 방출되기 전에 실행되어야 합니다. 패킹된 객체는 별도로 직렬화되어서도 안 됩니다.

Writer 모듈은 어떤 암호 연산도 수행하지 않습니다. 더 앞선 바이트가 변경될 경우 방출을 거부함으로써 서명된 바이트를 보호하는데, 이는 암호적 검사가 아니라 바이트 동일성 검사입니다. 서명 및 해싱을 위한 FIPS 알고리즘 선택은 이 writer가 아니라 서명 모듈이 관장합니다. FIPS 모드를 활성화하거나 비활성화해도 어떤 Writer 메서드의 동작도 바뀌지 않습니다.

NextPDF는 이 모듈을 ISO 32000-2:2020에 맞추어 구현합니다. 증분 writer는 §7.5.6 증분 업데이트 문법을 따릅니다. 즉, 각 리비전은 새 객체, 변경된 객체, 삭제된 객체만을 다루는 상호 참조 섹션과, /Prev 항목이 이전 상호 참조의 오프셋을 제공하는 트레일러를 추가합니다. Object Stream 빌더는 §7.5.7 Object Stream 모델을 따릅니다. 즉, 객체 번호와 오프셋 쌍의 인덱스—오프셋은 /First 항목으로부터 오름차순으로 측정—가 패킹된 객체 본문 앞에 옵니다. 두 조항 참조 모두 ISO 32000-2:2020 코퍼스에 대해 검증되었습니다. PAdES B-LT 및 B-LTA 워크플로를 위한 리비전 체이닝은 소스에 주석으로 표기된 대로 ETSI EN 319 142-1 §5.4를 따릅니다. 어떤 조항에 대한 지원은 엔지니어링 역량 진술이지 인증이 아닙니다. NextPDF는 어떤 공식 적합성 인증도 보유하고 있지 않습니다.

  • 패키지를 composer require nextpdf/pro:^3으로 설치하십시오. 클래스는 NextPDF\Pro\Writer 아래에서 해석됩니다.
  • IncrementalUpdateWriter::writeRevision은 정적 진입점이며, 리비전 간에 인스턴스 상태를 보유하지 않습니다.
  • ObjectStreamEntry, ObjStmCompressionResult, IncrementalUpdateWriter, 그리고 컴프레서가 함께 모듈의 공개 표면을 이룹니다. 저장소는 이에 대한 실행 가능한 예제를 제공하지 않습니다.
  • writeRevisionWriterException은 추가 전용 위반을 나타냅니다. 이를 하드 실패로 취급하고 버퍼를 폐기하십시오.
  • Object Stream 캐리어는 간접 객체입니다. 호출자가 레지스트리를 통해 그 객체 번호를 할당합니다.

이 페이지는 외부에서 관찰 가능한 동작과 지원되는 공개 API 표면만을 문서화합니다. 내부 네임스페이스 경로, 헬퍼 클래스, 메커니즘 테이블, 런북 파일명, 티켓 접두사는 범위에서 제외됩니다.