콘텐츠로 이동
getnextpdf.com

Pro 에디션안정성: 실험적

C2PA 프리뷰 — 심층 참조

이 페이지는 NextPDF Pro의 C2PA(Content Credentials) 프리뷰 표면에 대한 계약 수준의 레퍼런스입니다. NextPDF\Pro\Compliance\C2pa에 있는 다섯 개의 공개 심볼을 다룹니다: C2paManifestEmbedder SPI, ManifestStore 값 객체, JumbfBoxParser, C2paCapabilityStatus 디스크립터, 그리고 게이트가 걸린 Experimental\ExperimentalC2paEmbedder입니다. 또한 Feature::PREVIEW_C2PA_DRAFT 게이트와 그 환경 변수 NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT를 문서화합니다.

이 표면은 experimental 이며 두 계층으로 나뉩니다. 안정적인 심 — ManifestStore, C2paManifestEmbedder, JumbfBoxParser — 은 항상 도달 가능하며 Manifest Store 바이트를 양방향으로 운반합니다. 드래프트 매니페스트 합성 은 오직 ExperimentalC2paEmbedder에만 존재하며 기본 비활성화 되어 있습니다. C2PA-PDF 프로파일은 워킹 그룹에 의해 아직 확정되지 않았습니다. 합성된 와이어 포맷은 특정 드래프트 커밋에 고정되어 있습니다. 적합성 주장은 이루어지지 않으며, 검증 경로가 없고, 프리뷰 플래그를 켜도 둘 중 어느 것도 생성할 수 없습니다. 작업 지향적인 관점은 역량 페이지에 있습니다.

이 역량은 NextPDF Pro(nextpdf/pro)에 포함되어 출하되며 Pro 등급 라이선스 엔벨로프로 활성화됩니다. 해당 자격이 없는 배포는 이 역량의 클래스를 로드하지 않습니다. 에디션을 비교하고 라이선스를 받으세요.

라이선스는 Pro 컴플라이언스 표면 전체를 활성화합니다. 그 안의 C2PA 표면은 라이선스 등급과 무관하게 프리뷰로 남습니다. 드래프트 합성은 추가로 여기에 문서화된 프로세스 게이트를 요구합니다. Pro 라이선스만으로는 결코 그것을 활성화하지 못합니다.

심볼매개변수기본 동작반환던지거나 실패하는 경우비고
C2paManifestEmbedder바이트 전용 임베드/추출 SPI; I/O 없음; 클레임 합성 없음동결된 벤더 중립 심 인터페이스.
C2paManifestEmbedder::embed()string $pdfBytes, ManifestStore $store프로파일이 선언한 위치에 $store->toBytes()를 임베드; 비어 있는 Store는 no-op로 왕복(round-trip)될 수 있음(MAY)string 새로운 PDF 바이트임베드 실패 시 C2paException(과도하게 큰 Store, 유효하지 않은 PDF, 프로파일 위치 충돌)구현체는 입력 바이트를 변형하거나 보관하지 않습니다.
C2paManifestEmbedder::extract()string $pdfBytes저렴한 탐지 프로브; Store가 없는 경우 거의 아무것도 할당하지 않음?ManifestStore(누락 시 null)Store가 존재하지만 강화 불변식을 위반할 때 C2paException 서브클래스non-null Store는 이미 JumbfBoxParser 강화를 통과했습니다.
ManifestStore::fromBoxes()array $boxes(list<JumbfBox>)파서가 검증한 순서 있는 박스 목록을 래핑self스스로 던지지 않음; 손으로 만든 JumbfBox 생성은 동일한 강화를 강제함생성자는 private이며, 왕복 동등성을 위해 박스 순서가 핵심(load-bearing)입니다.
ManifestStore::empty()없음루트 박스가 0개인 Storeself던지지 않음비어 있는 Store의 toBytes()는 빈 문자열입니다.
ManifestStore::isEmpty()없음루트 박스가 0개인지 검사bool던지지 않음
ManifestStore::toBytes()없음루트 박스 직렬화들을 연결string던지지 않음이 바이트 시퀀스가 임베더가 기록하는 것입니다.
ManifestStore::size()없음toBytes()의 바이트 길이int(>= 0)던지지 않음
JumbfBoxParser::__construct()세 개의 선택적 캡 재정의프로덕션 캡: 박스당 64 MiB, 전체 128 MiB, 슈퍼박스당 자식 4096개JumbfBoxParser던지지 않음깊이 캡은 MAX_DEPTH(8)로 고정되며 생성자로 조정할 수 없습니다.
JumbfBoxParser::parse()string $bytes루트 박스를 검증하고 구체화; 빈 입력은 []를 산출list<JumbfBox>JumbfBombException, JumbfCycleDetectedException, JumbfDepthExceededException, MalformedJumbfException무상태(stateless); 부분 그래프를 결코 반환하지 않음; 한 인스턴스에 대한 동시 호출은 안전함.
C2paCapabilityStatus::__construct()이름 있는 readonly 필드 여섯 개임의의 디스크립터 인스턴스를 생성C2paCapabilityStatus던지지 않음current()가 정규(canonical) 생성자입니다.
C2paCapabilityStatus::current()없음게이트를 실시간으로 읽음; 클레임 불리언을 하드코딩C2paCapabilityStatus던지지 않음generallyAvailableconformanceClaimed는 항상 false입니다.
C2paCapabilityStatus::summary()없음한 줄짜리 상태 텍스트string던지지 않음GA나 적합성 주장을 담지 않도록 표현됨.
Feature문자열 기반 enum, 케이스 1개단일 케이스 PREVIEW_C2PA_DRAFT; 상수 ENV_PREVIEW_C2PA_DRAFTenum 케이스케이스 접근 시 아무것도 던지지 않음범위가 한정된 안정성 게이트; 라이선스 자격과는 별개.
Feature::isEnabled()없음getenv()를 실시간으로 읽음; 문자열 1과 엄격 비교bool던지지 않음변수가 없거나 0, true, yes를 포함한 다른 어떤 값이든 off입니다.
ExperimentalC2paEmbedder::__construct()없음생성 시점에 fail-closed 게이트 검사ExperimentalC2paEmbedderFeature::PREVIEW_C2PA_DRAFT가 off일 때 LogicException조용한 폴백은 존재하지 않습니다.
ExperimentalC2paEmbedder::buildManifestStore()string $sourceBytes, string $producer(non-empty)SHA-256으로 $sourceBytes를 바인딩한 드래프트 형태의 Store를 생성ManifestStore페이로드 인코딩 실패 시 \JsonException; 박스 생성에서 C2paException 서브클래스c2cs Claim Signature 박스를 생략함; 출력은 구성상(by construction) 서명되지 않음.
interface C2paManifestEmbedder
public function embed(string $pdfBytes, ManifestStore $store): string;
public function extract(string $pdfBytes): ?ManifestStore;
final readonly class ManifestStore
public static function fromBoxes(array $boxes): self
public static function empty(): self
public function isEmpty(): bool
public function toBytes(): string
public function size(): int
final class JumbfBoxParser
public const int MAX_DEPTH = 8;
public const int MAX_PER_BOX_BYTES = 64 * 1024 * 1024;
public const int MAX_TOTAL_BYTES = 128 * 1024 * 1024;
public const int MAX_CHILDREN_PER_SUPERBOX = 4096;
public const array SUPERBOX_TBOXES = ['jumb', 'c2pa', 'c2ma', 'c2as', 'c2cl', 'c2cs', 'c2vc'];
public function __construct(
private readonly int $maxPerBoxBytes = self::MAX_PER_BOX_BYTES,
private readonly int $maxTotalBytes = self::MAX_TOTAL_BYTES,
private readonly int $maxChildrenPerSuperbox = self::MAX_CHILDREN_PER_SUPERBOX,
)
public function parse(string $bytes): array
final readonly class C2paCapabilityStatus
public const string MATURITY_PREVIEW_DRAFT = 'preview-draft';
public function __construct(
public bool $previewEnabled,
public bool $generallyAvailable,
public bool $conformanceClaimed,
public string $maturity,
public string $specPin,
public string $envGate,
)
public static function current(): self
public function summary(): string
enum Feature: string
case PREVIEW_C2PA_DRAFT = 'preview_c2pa_draft';
public const string ENV_PREVIEW_C2PA_DRAFT = 'NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT';
public function isEnabled(): bool
final class ExperimentalC2paEmbedder
public const string SPEC_PIN_SHA = '4e2afed8f3ace20d41317e2e386c9340d2959d55';
public const string SPEC_PIN_DATE = '2026-04-26';
public function __construct()
public function buildManifestStore(string $sourceBytes, string $producer): ManifestStore
  • 두 계층 분리. 안정적인 심(ManifestStore, C2paManifestEmbedder, JumbfBoxParser)은 항상 도달 가능합니다. 드래프트 합성은 오직 기본 비활성화된 게이트 뒤의 NextPDF\Pro\Compliance\C2pa\Experimental\ExperimentalC2paEmbedder에만 존재합니다. 추출과 바이트 운반은 결코 게이트를 요구하지 않으며, 합성은 항상 요구합니다.
  • 심 불변식. C2paManifestEmbedder 계약은 바이트 전용입니다: 메모리 내 PDF 객체가 심을 넘나들지 않고, 구현체는 어떤 네트워크나 파일시스템 I/O도 수행하지 않으며, 심은 결코 스스로 클레임 어서션을 조립하지 않습니다. extract()는 부재를 알리기 위해 null을 반환하며, 부재에 대해 결코 던지지 않습니다.
  • Store 의미론. ManifestStore는 C2PA 2.1 §11.1.1의 Manifest Store 모델에 따른, 루트 JumbfBox 인스턴스들의 불변 순서 목록입니다: 하나 이상의 매니페스트를 집약하고 URI로 주소 지정 가능한 하나의 JUMBF 컨테이너입니다. 클레임 수준 접근자는 노출하지 않습니다. 박스 순서는 보존되며 왕복 동등성을 위해 핵심(load-bearing)입니다.
  • 강화 캡. JumbfBoxParser는 어떤 캡이든 초과하는 입력을 무조건 거부합니다: 박스당 크기 64 MiB 초과, 누적 store 128 MiB 초과, 8단계보다 깊은 중첩, 또는 한 슈퍼박스에 4096개를 초과하는 자식. 어떤 정책 플래그도 이 캡을 비활성화하지 못합니다. 메모리가 제한된 프로세스를 위해 더 엄격한 캡을 생성자로 주입할 수 있습니다.
  • 구조적 거부. 파서는 또한 다음을 fail-closed로 거부합니다: LBox = 0(BMFF의 EOF까지), LBox = 1(XLBox 64비트 길이), 8바이트 헤더보다 작은 LBox, 남은 입력을 넘어가는 절단, 인쇄 가능 ASCII(0x20–0x7E) 밖의 TBox 바이트, 오프셋 재진입(사이클), 그리고 슈퍼박스 페이로드의 비정확한(non-exact) 자식 타일링. 부분적으로 구성된 그래프를 결코 반환하지 않습니다.
  • 슈퍼박스 라우팅. SUPERBOX_TBOXES에 속하는 TBox 값은 자식 시퀀스로 재귀적으로 파싱되며, 그 밖의 모든 TBox는 불투명 페이로드를 가진 리프(leaf)입니다. cbor는 파서 안전을 위해 의도적으로 리프로 취급되며, 필요할 때 상위 계층이 그 페이로드를 다시 파싱합니다.
  • 프로세스 게이트. Feature::PREVIEW_C2PA_DRAFT는 기본적으로 off입니다. isEnabled()NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT가 정확히 문자열 1과 같을 때에만 true를 반환합니다. 읽기는 매 호출마다 실시간이며, 아무것도 메모이즈되지 않습니다.
  • Fail-closed 생성. 게이트가 off인 동안 new ExperimentalC2paEmbedder()LogicException을 던집니다. 메시지는 플래그, 환경 변수, 그리고 고정된 드래프트 SHA와 날짜를 명시합니다. 호출자는 우발적으로 드래프트 합성에 도달할 수 없습니다.
  • 합성 형태. buildManifestStore()는 하나의 c2ma 매니페스트를 담은 c2pa 슈퍼박스를 방출하며, 이 매니페스트는 c2as 어서션 스토어(하나의 c2pa.hash.data 어서션)와 c2cl 클레임을 보유합니다. 이 어서션은 $sourceBytes에 대한 SHA-256 해시 어서션을 기록합니다. c2cs Claim Signature 박스가 생략되고 출력이 서명되지 않으므로, 이것은 C2PA 하드 바인딩이나 출처(provenance) 판정이 아닙니다 — §9.1이 기술하는 구조적 형태만 따를 뿐입니다. Description 박스 페이로드는 타입 UUID, 토글 0x03, 그리고 null 종료 UTF-8 레이블을 운반하며, 이는 C2PA 2.1 §11.1.4.1.1–11.1.4.1.2를 따릅니다.
  • Claim Signature 없음. c2cs 박스 — C2PA 2.1 §11.1.4.4에 따라 c2pa.signature로 레이블된 단일 CBOR 콘텐츠 박스 — 는 합성된 Store에서 의도적으로 생략됩니다. 출력은 구성상 서명되지 않습니다. 이는 워킹 그룹 동결 전에 가장 드리프트할 가능성이 높다고 판단되는 프로파일 영역입니다.
  • 드래프트 고정, BC 보장 없음. 합성된 와이어 포맷은 c2pa-org/specificationsSPEC_PIN_SHA(4e2afed8…, 날짜 2026-04-26)에 고정됩니다. 이것은 예고 없이 변경될 수 있으며 하위 호환성 보장을 담지 않습니다.
  • 정직성 불변식. C2paCapabilityStatus::current()generallyAvailableconformanceClaimedfalse로 하드코딩합니다. 어떤 구성이나 환경 플래그도 두 불리언 중 어느 것도 뒤집지 못합니다. 오직 previewEnabled만 게이트를 반영하며, maturity는 주장을 담지 않는 토큰 preview-draft입니다.
  • 게이트 변수를 0, true, yes, on, 또는 빈 문자열로 설정하면 게이트는 off 상태로 남습니다. 오직 정확한 문자열 1만 그것을 활성화합니다.
  • putenv() 변경은 읽기가 실시간이므로 다음 isEnabled() 호출에서 효력을 발휘합니다. 프로세스 도중에 토글된 게이트는 즉시 관찰됩니다.
  • extract()는 두 결과를 구분합니다: Store가 없을 때의 null(저렴하고 예외 없음), 그리고 Store가 존재하지만 적대적이거나 잘못된 형식일 때 던져지는 C2paException 서브클래스입니다. 부재는 결코 오류가 아니며, 존재와 잘못된 형식은 항상 오류입니다.
  • JumbfBoxParser::parse('')는 빈 목록을 반환합니다. 비어 있지만 존재하는 ManifestStore는 자기 자신으로 왕복하며, 심은 그것을 null로 축소하지 않습니다.
  • 비어 있는 Store를 임베드하면 입력을 변경 없이 반환할 수 있습니다(MAY). 심 계약은 이 no-op를 허용하지만 의무화하지는 않습니다.
  • 손으로 만든 JumbfBox 그래프는 생성 시점에 동일한 강화를 실행합니다: TBox 길이 및 ASCII 검사, 깊이 캡, 자식 깊이 불변식, 페이로드-또는-자식 배타성 규칙, 그리고 박스당 크기 캡입니다. 손으로 만든 폭탄은 임베드 시점이 아니라 생성 시점에 실패합니다.
  • 모든 파서 예외는 구조화된 필드 — capKind/observed/cap, offset, 또는 kind — 를 운반하므로 텔레메트리가 메시지 문자열을 스크레이핑하지 않습니다. 모든 서브클래스는 C2paException(그 자체가 RuntimeException)을 확장하며, 이것이 우산 캐치 타입입니다.
  • 파서 docblock은 이 예외들을 조용히 삼키는 것을 금지합니다. 소비자는 그것들을 표면화하거나 의도를 가지고 재매핑합니다.
  • buildManifestStore()는 JSON 페이로드를 JSON_THROW_ON_ERROR로 인코딩합니다. 유효한 UTF-8이 아닌 $producer 문자열은 어떤 박스가 만들어지기 전에 \JsonException으로 실패합니다.
  • 잘 형성된 extract() 결과는 구조적 진술일 뿐입니다. 이 표면 어디에도 클레임 검증, 서명 검증, 또는 신뢰 평가가 없습니다. 인식(recognition)은 출처 판정이 아닙니다.
  • 이 표면은 어떤 서명 키, 인증서, 또는 COSE 구조도 처리하지 않습니다. 유일한 암호화 연산은 게이트가 걸린 합성 경로 내부의 SHA-256 콘텐츠 해시입니다.
주장표준
매니페스트는 여러 매니페스트를 담고 URI로 주소 지정 가능한 하나의 JUMBF store로 직렬화된다.C2PA 2.1§11.1.1 (p63.b)
Description 박스 레이블은 제외 범위가 있는 null 종료 UTF-8이며, 토글은 모든 Description 박스에 대해 정의된다.C2PA 2.1§11.1.4.1.1–11.1.4.1.2 (p63.a)
Claim Signature 박스는 c2pa.signature로 레이블되고, c2cs로 타입 지정되며, 단일 CBOR 콘텐츠 박스를 보유한다.C2PA 2.1§11.1.4.4 (p63.c)
하드 바인딩은 매니페스트를 그 에셋에 암호학적으로 묶고 변경을 노출한다 — 프리뷰의 서명되지 않은 해시 어서션은 이 기준을 충족하지 못한다(NOT).C2PA 2.1§9.1 (p57)

모든 절은 의역되었습니다. NextPDF는 규범적 텍스트를 재현하지 않습니다. NextPDF는 어떤 인증도 보유하지 않으며 어떤 인증도 부여하지 않습니다. 위의 진술들은 박스 레이아웃, 레이블, 바인딩에 관한 구조적 정렬(structural-alignment) 진술입니다 — 적합성 테스트 결과도, 제3자 증명도, C2PA나 ISO 적합성 주장도 아닙니다. C2PA-PDF 프로파일은 확정되지 않았습니다. 합성된 와이어 포맷은 고정된 드래프트 커밋을 추적합니다. C2paCapabilityStatus는 이 자세를 코드로 인코딩합니다: generallyAvailableconformanceClaimed는 모든 구성에서 false입니다. 이 표면의 출력은 검증 가능한 Content Credential이 아니며, NextPDF에는 검증 경로가 존재하지 않습니다.

  • 파서가 구현하는 JUMBF 박스 문법(4바이트 빅엔디언 LBox, 4바이트 ASCII TBox, 페이로드; 슈퍼박스는 자식 박스를 중첩)은 ISO 19566-5를 따릅니다. 그 표준은 인용된 코퍼스 밖에 있으므로, 파서 동작은 스펙 인용이 아니라 제품 소스에서 근거합니다.

  • 프로덕션에서는 게이트를 off로 유지하세요. 드래프트 합성은 지속적인 역량을 더하지 않습니다. 방출된 바이트는 일시적이며, 안정적인 어댑터가 출하되면 다시 임베드되어야 합니다.

  • 파이프라인이 기대하는 드래프트 커밋에 대해 ExperimentalC2paEmbedder::SPEC_PIN_SHA를 어설션하세요. 고정 노후화(pin staleness)를 감지하려면 CI에서 composer c2pa:draft-status를 실행하세요(신선하면 exit 0, 소프트 경고 1, 하드 실패 2).

  • 툴링이나 UI에서 C2PA 상태를 표면화할 때는 C2paCapabilityStatus::current()를 유일한 진실 공급원으로 취급하세요. 그 불리언들을 손으로 다시 진술하지 마세요. summary()는 로그와 상태 엔드포인트에 안전합니다.

  • extract()parse()를 소비할 때는 우산 타입으로 C2paException을 캐치하세요. 네 개의 서브클래스를 그들의 구조화된 필드를 사용해 별개의 텔레메트리 카운터로 매핑하세요.

  • 메모리가 제한된 검증기 프로세스를 위해 JumbfBoxParser 생성자를 통해 더 엄격한 캡을 주입하세요. 기본값은 넉넉한 프로덕션 캡입니다.

  • C2paCapabilityStatus::__construct()는 public이므로, 손으로 만든 인스턴스는 임의의 불리언을 운반할 수 있습니다. 그런 인스턴스는 값 객체일 뿐이며, 어떤 동작도 바꾸지 않습니다.

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