Ga naar inhoud
getnextpdf.com

Pro editiestabiliteit: Experimenteel

C2PA-preview — Diepe referentie

Deze pagina is de reference op contractniveau voor het C2PA-preview-oppervlak (Content Credentials) in NextPDF Pro. Ze behandelt vijf publieke symbolen in NextPDF\Pro\Compliance\C2pa: de C2paManifestEmbedder SPI, het ManifestStore-waardeobject, de JumbfBoxParser, de C2paCapabilityStatus-descriptor en de gated Experimental\ExperimentalC2paEmbedder. Ook documenteert ze de Feature::PREVIEW_C2PA_DRAFT-gate en de bijbehorende omgevingsvariabele NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT.

Het oppervlak is experimenteel en gesplitst in twee lagen. De stabiele naad — ManifestStore, C2paManifestEmbedder, JumbfBoxParser — is altijd bereikbaar en draagt Manifest Store-bytes in beide richtingen. Draft-manifestsynthese leeft alleen in ExperimentalC2paEmbedder en is standaard uitgeschakeld. Het C2PA-PDF-profiel is niet gefinaliseerd door de werkgroep; het gesynthetiseerde wire-formaat is vastgepind op een draft-commit. Er wordt geen conformiteitsclaim gedaan, er is geen verificatiepad, en het inschakelen van de preview-vlag kan geen van beide creëren. De taakgerichte weergave staat op de capability-pagina.

Deze mogelijkheid wordt geleverd in NextPDF Pro (nextpdf/pro) en activeert met een Pro-tier-licentie-envelope. Een deployment zonder die entitlement laadt de klassen van de mogelijkheid niet. Vergelijk edities en verkrijg een licentie.

De licentie activeert het Pro-compliance-oppervlak als geheel. Het C2PA-oppervlak daarbinnen blijft een preview, ongeacht de licentie-tier. Draft-synthese vereist bovendien de proces-gate die hier gedocumenteerd staat; een Pro-licentie alleen schakelt die nooit in.

SymboolParametersStandaardgedragRetourneertGooit of faalt metOpmerkingen
C2paManifestEmbedderBytes-only embed/extract SPI; geen I/O; geen claim-syntheseBevroren, vendor-neutrale naad-interface.
C2paManifestEmbedder::embed()string $pdfBytes, ManifestStore $storeEmbedt $store->toBytes() op de door het profiel gedeclareerde locatie; een lege Store MAG als no-op round-trippenstring nieuwe PDF-bytesC2paException bij elke embed-fout (te grote Store, ongeldige PDF, botsing van profiellocatie)Implementaties muteren of behouden de invoerbytes nooit.
C2paManifestEmbedder::extract()string $pdfBytesGoedkope detectieprobe; het geval zonder Store alloceert vrijwel niets?ManifestStore (null bij miss)C2paException-subklasse wanneer een Store aanwezig is maar een hardening-invariant schendtEen niet-null Store is al door de JumbfBoxParser-hardening gekomen.
ManifestStore::fromBoxes()array $boxes (list<JumbfBox>)Wikkelt een door de parser gevalideerde geordende box-lijstselfGooit zelf niet; handmatig geconstrueerde JumbfBox dwingt dezelfde hardening afDe constructor is private; de box-volgorde is dragend voor round-trip-gelijkheid.
ManifestStore::empty()geenStore met nul root-boxesselfGooit niettoBytes() van een lege Store is de lege string.
ManifestStore::isEmpty()geenTest op nul root-boxesboolGooit niet
ManifestStore::toBytes()geenConcateneert de serialisaties van de root-boxesstringGooit nietDeze byte-reeks is wat een embedder wegschrijft.
ManifestStore::size()geenByte-lengte van toBytes()int (>= 0)Gooit niet
JumbfBoxParser::__construct()drie optionele cap-overridesProductie-caps: 64 MiB per box, 128 MiB totaal, 4096 children per superboxJumbfBoxParserGooit nietDe diepte-cap ligt vast op MAX_DEPTH (8) en is niet instelbaar via de constructor.
JumbfBoxParser::parse()string $bytesValideert en materialiseert de root-boxes; lege invoer levert []list<JumbfBox>JumbfBombException, JumbfCycleDetectedException, JumbfDepthExceededException, MalformedJumbfExceptionStateless; retourneert nooit een gedeeltelijke graph; gelijktijdige aanroepen op één instance zijn veilig.
C2paCapabilityStatus::__construct()zes benoemde readonly-veldenBouwt een willekeurige descriptor-instanceC2paCapabilityStatusGooit nietcurrent() is de canonieke constructor.
C2paCapabilityStatus::current()geenLeest de gate live; hardcodeert de claim-booleansC2paCapabilityStatusGooit nietgenerallyAvailable en conformanceClaimed zijn altijd false.
C2paCapabilityStatus::summary()geenStatustekst van één regelstringGooit nietZo geformuleerd dat ze geen GA- of conformiteitsclaim draagt.
Featurestring-backed enum, 1 caseEnkele case PREVIEW_C2PA_DRAFT; constante ENV_PREVIEW_C2PA_DRAFTenum-caseNiets bij case-toegangGescopete stabiliteits-gate; los van licentie-entitlement.
Feature::isEnabled()geenLeest getenv() live; strikte vergelijking met de string 1boolGooit nietAfwezige variabele of elke andere waarde, inclusief 0, true, yes, staat uit.
ExperimentalC2paEmbedder::__construct()geenFail-closed gate-check bij constructietijdExperimentalC2paEmbedderLogicException wanneer Feature::PREVIEW_C2PA_DRAFT uit staatEr bestaat geen stille fallback.
ExperimentalC2paEmbedder::buildManifestStore()string $sourceBytes, string $producer (non-empty)Bouwt een draft-vormige Store die $sourceBytes bindt via SHA-256ManifestStore\JsonException bij falen van payload-encode; C2paException-subklassen bij box-constructieLaat de c2cs Claim Signature box weg; de output is door constructie ongesigneerd.
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
  • Splitsing in twee lagen. De stabiele naad (ManifestStore, C2paManifestEmbedder, JumbfBoxParser) is altijd bereikbaar. Draft-synthese bestaat alleen in NextPDF\Pro\Compliance\C2pa\Experimental\ExperimentalC2paEmbedder achter de standaard uitgeschakelde gate. Extractie en byte-carry vereisen de gate nooit; synthese altijd wel.
  • Naad-invarianten. Het C2paManifestEmbedder-contract is bytes-only: er kruisen geen in-memory PDF-objecten de naad, implementaties voeren geen netwerk- of filesystem-I/O uit, en de naad stelt zelf nooit claim-assertions samen. extract() retourneert null om afwezigheid te signaleren; het gooit nooit voor afwezigheid.
  • Store-semantiek. ManifestStore is een onveranderbare geordende lijst van root-JumbfBox-instances, conform het Manifest Store-model van C2PA 2.1 §11.1.1: één JUMBF-container die een of meer manifests aggregeert, adresseerbaar per URI. Het legt geen claim-niveau-accessors bloot. De box-volgorde blijft behouden en is dragend voor round-trip-gelijkheid.
  • Hardening-caps. JumbfBoxParser weigert onvoorwaardelijk invoer die een cap overschrijdt: per-box-grootte boven 64 MiB, cumulatieve store boven 128 MiB, nesting dieper dan 8 niveaus, of meer dan 4096 children in één superbox. Geen enkele policy-vlag schakelt deze caps uit. Strakkere caps zijn via de constructor injecteerbaar voor geheugen-beperkte processen.
  • Structurele afwijzing. De parser weigert ook, fail-closed: LBox = 0 (BMFF tot-EOF), LBox = 1 (XLBox 64-bit lengte), een LBox kleiner dan de 8-byte header, truncatie voorbij de resterende invoer, TBox-bytes buiten printbare ASCII (0x20–0x7E), offset-heringang (cycli), en niet-exacte child-tiling van een superbox-payload. Het retourneert nooit een gedeeltelijk geconstrueerde graph.
  • Superbox-routing. TBox-waarden in SUPERBOX_TBOXES parsen recursief als child-sequenties; elke andere TBox is een leaf met een opaque payload. cbor wordt bewust als leaf behandeld voor parser-veiligheid; hogere lagen herparsen de payload ervan wanneer nodig.
  • Proces-gate. Feature::PREVIEW_C2PA_DRAFT staat standaard uit. isEnabled() retourneert alleen true wanneer NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT exact gelijk is aan de string 1. De lezing gebeurt live bij elke aanroep; niets wordt gememoïseerd.
  • Fail-closed constructie. new ExperimentalC2paEmbedder() gooit LogicException terwijl de gate uit staat. Het bericht noemt de vlag, de omgevingsvariabele en de vastgepinde draft-SHA en -datum. Een caller kan draft-synthese niet per ongeluk bereiken.
  • Synthese-vorm. buildManifestStore() emitteert een c2pa-superbox met daarin één c2ma-manifest, dat een c2as-assertion-store (één c2pa.hash.data-assertion) en een c2cl-claim bevat. De assertion registreert een SHA-256-hash-assertion over $sourceBytes; omdat de c2cs Claim Signature box wordt weggelaten en de output ongesigneerd is, is dit GEEN C2PA hard binding of provenance-verdict — het volgt alleen de structurele vorm die §9.1 beschrijft. Description-box-payloads dragen een type-UUID, toggles 0x03 en een null-terminated UTF-8-label, conform C2PA 2.1 §11.1.4.1.1–11.1.4.1.2.
  • Geen Claim Signature. De c2cs-box — conform C2PA 2.1 §11.1.4.4 een enkele CBOR content box met label c2pa.signature — wordt opzettelijk weggelaten uit de gesynthetiseerde Store. De output is door constructie ongesigneerd. Dit is de profielregio waarvan geoordeeld is dat die het meest waarschijnlijk drift vóór de bevriezing door de werkgroep.
  • Draft-pin, geen BC-garantie. Het gesynthetiseerde wire-formaat is vastgepind op SPEC_PIN_SHA (4e2afed8…, gedateerd 2026-04-26) van c2pa-org/specifications. Het kan zonder aankondiging veranderen en draagt geen backwards-compatibiliteitsgarantie.
  • Eerlijkheids-invariant. C2paCapabilityStatus::current() hardcodeert generallyAvailable en conformanceClaimed op false. Geen configuratie- of omgevingsvlag draait een van beide booleans om. Alleen previewEnabled weerspiegelt de gate; maturity is de niet-claimende token preview-draft.
  • Het instellen van de gate-variabele op 0, true, yes, on of een lege string laat de gate uit. Alleen de exacte string 1 schakelt hem in.
  • Wijzigingen via putenv() worden van kracht bij de volgende isEnabled()-aanroep omdat de lezing live is. Een gate die midden in het proces wordt omgeschakeld, wordt onmiddellijk waargenomen.
  • extract() onderscheidt twee uitkomsten: null wanneer geen Store aanwezig is (goedkoop, exceptie-vrij), en een geworpen C2paException-subklasse wanneer een Store aanwezig maar vijandig of malformed is. Afwezigheid is nooit een fout; aanwezigheid plus malformatie altijd wel.
  • JumbfBoxParser::parse('') retourneert de lege lijst. Een lege maar aanwezige ManifestStore round-tript naar zichzelf; de naad reduceert die niet tot null.
  • Het embedden van een lege Store MAG de invoer ongewijzigd retourneren. Het naad-contract staat deze no-op toe maar verplicht die niet.
  • Handmatig geconstrueerde JumbfBox-graphs draaien dezelfde hardening bij constructietijd: TBox-lengte- en ASCII-checks, de diepte-cap, de child-diepte-invariant, de payload-of-children-exclusiviteitsregel, en de per-box-grootte-cap. Een handmatig geconstrueerde bom faalt bij constructie, niet bij embed-tijd.
  • Elke parser-exceptie draagt gestructureerde velden — capKind/observed/cap, offset of kind — zodat telemetrie geen berichtstrings hoeft te scrapen. Alle subklassen breiden C2paException uit (zelf een RuntimeException), wat het overkoepelende catch-type is.
  • Het parser-docblock verbiedt het stil inslikken van deze excepties; consumers laten ze doorkomen of remappen ze met opzet.
  • buildManifestStore() encodeert JSON-payloads met JSON_THROW_ON_ERROR; een $producer-string die geen geldige UTF-8 is, faalt met \JsonException voordat er ook maar één box gebouwd wordt.
  • Een welgevormd extract()-resultaat is louter een structurele uitspraak. Er is nergens op dit oppervlak claim-validatie, handtekening-verificatie of trust-evaluatie. Herkenning is geen provenance-verdict.
  • Er wordt geen ondertekeningssleutel, certificaat of COSE-structuur door dit oppervlak verwerkt. De enige cryptografische operatie is een SHA-256-content-hash binnen het gated synthese-pad.
ClaimStandaardClausule
Manifests serialiseren in één JUMBF-store die meerdere manifests bevat, adresseerbaar per URI.C2PA 2.1§11.1.1 (p63.b)
Description-box-labels zijn null-terminated UTF-8 met uitgesloten ranges; toggles zijn gedefinieerd voor alle Description boxes.C2PA 2.1§11.1.4.1.1–11.1.4.1.2 (p63.a)
De Claim Signature box heeft label c2pa.signature, type c2cs, en bevat een enkele CBOR content box.C2PA 2.1§11.1.4.4 (p63.c)
Een hard binding bindt een manifest cryptografisch aan zijn asset en legt modificatie bloot — de ongesigneerde hash-assertion van de preview voldoet NIET aan deze lat.C2PA 2.1§9.1 (p57)

Alle clausules zijn geparafraseerd. NextPDF reproduceert geen normatieve tekst. NextPDF houdt geen certificering en verleent er geen. De bovenstaande uitspraken zijn structurele-uitlijningsuitspraken over box-layout, labels en bindings — het zijn geen conformiteitstest-resultaten, geen attestaties van derden, en geen C2PA- of ISO-conformiteitsclaim. Het C2PA-PDF-profiel is niet gefinaliseerd; het gesynthetiseerde wire-formaat volgt een vastgepinde draft-commit. C2paCapabilityStatus codeert deze houding in code: generallyAvailable en conformanceClaimed zijn false in elke configuratie. Output van dit oppervlak is geen verifieerbaar Content Credential, en er bestaat geen verificatiepad in NextPDF.

  • De JUMBF-box-grammatica die de parser implementeert (4-byte big-endian LBox, 4-byte ASCII TBox, payload; superboxes nesten child-boxes) volgt ISO 19566-5; die standaard valt buiten het geciteerde corpus, dus het parser-gedrag is gegrond in de productbron, niet in een spec-citatie.

  • Houd de gate uit in productie. Draft-synthese voegt geen duurzame mogelijkheid toe; de geëmitteerde bytes zijn kortstondig en moeten opnieuw geëmbed worden zodra een stabiele adapter beschikbaar komt.

  • Assert ExperimentalC2paEmbedder::SPEC_PIN_SHA tegen de draft-commit die je pipeline verwacht. Draai composer c2pa:draft-status in CI (exit 0 vers, 1 soft-warn, 2 hard-fail) om pin-veroudering te detecteren.

  • Behandel C2paCapabilityStatus::current() als de enige bron van waarheid bij het tonen van C2PA-status in tooling of UI. Herformuleer de booleans ervan niet met de hand; summary() is veilig voor logs en status-endpoints.

  • Vang C2paException als overkoepelend type bij het consumeren van extract() of parse(). Map de vier subklassen naar afzonderlijke telemetrie-counters met hun gestructureerde velden.

  • Injecteer strakkere caps via de JumbfBoxParser-constructor voor geheugen-beperkte verifier-processen; de defaults zijn ruime productie-caps.

  • C2paCapabilityStatus::__construct() is public, dus een handmatig geconstrueerde instance kan willekeurige booleans dragen. Zo’n instance is slechts een waardeobject; het verandert geen enkel gedrag.

Deze pagina documenteert alleen extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helper-klassen, mechanisme-tabellen, runbook-bestandsnamen en ticket-prefixes vallen buiten scope.