Aller au contenu
getnextpdf.com

Pro éditionstabilité: Expérimental

Aperçu C2PA — Référence approfondie

Cette page constitue la référence de niveau contrat pour la surface d’aperçu C2PA (Content Credentials) de NextPDF Pro. Elle couvre cinq symboles publics de NextPDF\Pro\Compliance\C2pa : le SPI C2paManifestEmbedder, l’objet-valeur ManifestStore, le JumbfBoxParser, le descripteur C2paCapabilityStatus et l’Experimental\ExperimentalC2paEmbedder sous portail. Elle documente aussi le portail Feature::PREVIEW_C2PA_DRAFT et sa variable d’environnement, NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT.

La surface est expérimentale et scindée en deux couches. La jointure stable — ManifestStore, C2paManifestEmbedder, JumbfBoxParser — est toujours accessible et transporte les octets du Manifest Store dans les deux sens. La synthèse de manifeste-brouillon vit uniquement dans ExperimentalC2paEmbedder et est désactivée par défaut. Le profil C2PA-PDF n’est pas finalisé par le groupe de travail ; le format de fil synthétisé est épinglé à un commit de brouillon. Aucune affirmation de conformité n’est faite, il n’existe aucun chemin de vérification, et activer le drapeau d’aperçu ne peut en créer aucun. La vue orientée tâches se trouve sur la page de capacité.

Cette capacité est livrée dans NextPDF Pro (nextpdf/pro) et s’active avec une enveloppe de licence de niveau Pro. Un déploiement dépourvu de ce droit ne charge pas les classes de la capacité. Comparez les éditions et obtenez une licence.

La licence active la surface de conformité Pro dans son ensemble. La surface C2PA qu’elle contient reste un aperçu quel que soit le niveau de licence. La synthèse de brouillon exige en outre le portail de processus documenté ici ; une licence Pro seule ne l’active jamais.

SymboleParamètresComportement par défautRenvoieLève ou échoue avecNotes
C2paManifestEmbedderSPI d’intégration/extraction purement binaire ; aucune E/S ; aucune synthèse de revendicationInterface de jointure figée, neutre vis-à-vis du fournisseur.
C2paManifestEmbedder::embed()string $pdfBytes, ManifestStore $storeIntègre $store->toBytes() à l’emplacement déclaré par le profil ; un Store vide PEUT faire un aller-retour sans effetstring nouveaux octets PDFC2paException en cas d’échec d’intégration (Store surdimensionné, PDF invalide, collision d’emplacement de profil)Les implémentations ne mutent ni ne conservent jamais les octets d’entrée.
C2paManifestEmbedder::extract()string $pdfBytesSonde de détection peu coûteuse ; le cas sans Store n’alloue presque rien?ManifestStore (null si absent)Sous-classe de C2paException lorsqu’un Store est présent mais viole un invariant de durcissementUn Store non nul a déjà passé le durcissement de JumbfBoxParser.
ManifestStore::fromBoxes()array $boxes (list<JumbfBox>)Enveloppe une liste ordonnée de boîtes validée par l’analyseurselfNe lève pas d’elle-même ; la construction manuelle de JumbfBox applique le même durcissementLe constructeur est privé ; l’ordre des boîtes porte du sens pour l’égalité d’aller-retour.
ManifestStore::empty()aucunStore à zéro boîte racineselfNe lève pasLe toBytes() d’un Store vide est la chaîne vide.
ManifestStore::isEmpty()aucunTeste l’absence de boîte racineboolNe lève pas
ManifestStore::toBytes()aucunConcatène les sérialisations des boîtes racinesstringNe lève pasCette séquence d’octets est ce qu’un intégrateur écrit.
ManifestStore::size()aucunLongueur en octets de toBytes()int (>= 0)Ne lève pas
JumbfBoxParser::__construct()trois surcharges de plafond optionnellesPlafonds de production : 64 Mio par boîte, 128 Mio au total, 4096 enfants par superboîteJumbfBoxParserNe lève pasLe plafond de profondeur est fixé à MAX_DEPTH (8) et n’est pas réglable par le constructeur.
JumbfBoxParser::parse()string $bytesValide et matérialise les boîtes racines ; une entrée vide produit []list<JumbfBox>JumbfBombException, JumbfCycleDetectedException, JumbfDepthExceededException, MalformedJumbfExceptionSans état ; ne renvoie jamais de graphe partiel ; les appels concurrents sur une instance sont sûrs.
C2paCapabilityStatus::__construct()six champs readonly nommésConstruit une instance de descripteur arbitraireC2paCapabilityStatusNe lève pascurrent() est le constructeur canonique.
C2paCapabilityStatus::current()aucunLit le portail en direct ; code en dur les booléens de revendicationC2paCapabilityStatusNe lève pasgenerallyAvailable et conformanceClaimed valent toujours false.
C2paCapabilityStatus::summary()aucunTexte de statut sur une lignestringNe lève pasFormulé pour ne porter aucune affirmation de GA ni de conformité.
Featureénumération à support string, 1 casCas unique PREVIEW_C2PA_DRAFT ; constante ENV_PREVIEW_C2PA_DRAFTcas d’énumérationRien à l’accès du casPortail de stabilité ciblé ; distinct du droit de licence.
Feature::isEnabled()aucunLit getenv() en direct ; comparaison stricte à la chaîne 1boolNe lève pasVariable absente ou toute autre valeur, y compris 0, true, yes, est désactivé.
ExperimentalC2paEmbedder::__construct()aucunVérification du portail en fail-closed à la constructionExperimentalC2paEmbedderLogicException lorsque Feature::PREVIEW_C2PA_DRAFT est désactivéAucun repli silencieux n’existe.
ExperimentalC2paEmbedder::buildManifestStore()string $sourceBytes, string $producer (non vide)Construit un Store en forme de brouillon liant $sourceBytes via SHA-256ManifestStore\JsonException en cas d’échec d’encodage de la charge utile ; sous-classes de C2paException issues de la construction des boîtesOmet la boîte de signature de revendication c2cs ; la sortie est non signée par 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
  • Scission en deux couches. La jointure stable (ManifestStore, C2paManifestEmbedder, JumbfBoxParser) est toujours accessible. La synthèse de brouillon n’existe que dans NextPDF\Pro\Compliance\C2pa\Experimental\ExperimentalC2paEmbedder, derrière le portail désactivé par défaut. L’extraction et le transport d’octets n’exigent jamais le portail ; la synthèse l’exige toujours.
  • Invariants de la jointure. Le contrat C2paManifestEmbedder est purement binaire : aucun objet PDF en mémoire ne traverse la jointure, les implémentations n’effectuent aucune E/S réseau ou fichier, et la jointure n’assemble jamais elle-même les assertions de revendication. extract() renvoie null pour signaler l’absence ; elle ne lève jamais pour une absence.
  • Sémantique du Store. ManifestStore est une liste ordonnée immuable de JumbfBox racines, conformément au modèle Manifest Store de C2PA 2.1 §11.1.1 : un conteneur JUMBF agrégeant un ou plusieurs manifestes, adressables par URI. Il n’expose aucun accesseur de niveau revendication. L’ordre des boîtes est préservé et porte du sens pour l’égalité d’aller-retour.
  • Plafonds de durcissement. JumbfBoxParser rejette inconditionnellement toute entrée qui dépasse un plafond : taille par boîte au-delà de 64 Mio, store cumulé au-delà de 128 Mio, imbrication plus profonde que 8 niveaux, ou plus de 4096 enfants dans une superboîte. Aucun drapeau de politique ne désactive ces plafonds. Des plafonds plus stricts sont injectables par le constructeur pour les processus à mémoire contrainte.
  • Rejet structurel. L’analyseur rejette également, en fail-closed : LBox = 0 (BMFF jusqu’à EOF), LBox = 1 (longueur XLBox 64 bits), un LBox inférieur à l’en-tête de 8 octets, la troncature au-delà de l’entrée restante, des octets TBox hors ASCII imprimable (0x20–0x7E), la ré-entrée par décalage (cycles) et le pavage non exact des enfants d’une charge utile de superboîte. Il ne renvoie jamais de graphe partiellement construit.
  • Routage des superboîtes. Les valeurs TBox de SUPERBOX_TBOXES s’analysent récursivement en séquences d’enfants ; toute autre TBox est une feuille à charge utile opaque. cbor est délibérément traité comme une feuille pour la sûreté de l’analyseur ; les couches en amont réanalysent sa charge utile au besoin.
  • Portail de processus. Feature::PREVIEW_C2PA_DRAFT est désactivé par défaut. isEnabled() renvoie true uniquement lorsque NEXTPDF_FEATURE_PREVIEW_C2PA_DRAFT vaut exactement la chaîne 1. La lecture est en direct à chaque appel ; rien n’est mémoïsé.
  • Construction en fail-closed. new ExperimentalC2paEmbedder() lève LogicException tant que le portail est désactivé. Le message nomme le drapeau, la variable d’environnement, ainsi que le SHA et la date du brouillon épinglé. Un appelant ne peut atteindre la synthèse de brouillon par accident.
  • Forme de la synthèse. buildManifestStore() émet une superboîte c2pa contenant un manifeste c2ma, qui détient un magasin d’assertions c2as (une assertion c2pa.hash.data) et une revendication c2cl. L’assertion enregistre une assertion de hachage SHA-256 sur $sourceBytes ; parce que la boîte de signature de revendication c2cs est omise et que la sortie est non signée, ce n’est PAS une liaison forte C2PA ni un verdict de provenance — elle suit seulement la forme structurelle décrite au §9.1. Les charges utiles des boîtes de description portent un type UUID, les bascules 0x03 et une étiquette UTF-8 à terminaison nulle, conformément à C2PA 2.1 §11.1.4.1.1–11.1.4.1.2.
  • Aucune signature de revendication. La boîte c2cs — d’après C2PA 2.1 §11.1.4.4, une unique boîte de contenu CBOR étiquetée c2pa.signature — est intentionnellement omise du Store synthétisé. La sortie est non signée par construction. C’est la région du profil jugée la plus susceptible de dériver avant le gel du groupe de travail.
  • Épingle de brouillon, aucune garantie de BC. Le format de fil synthétisé est épinglé à SPEC_PIN_SHA (4e2afed8…, daté du 2026-04-26) de c2pa-org/specifications. Il peut changer sans préavis et ne porte aucune garantie de rétrocompatibilité.
  • Invariant d’honnêteté. C2paCapabilityStatus::current() code en dur generallyAvailable et conformanceClaimed à false. Aucune configuration ni drapeau d’environnement ne bascule l’un ou l’autre booléen. Seul previewEnabled reflète le portail ; maturity est le jeton sans revendication preview-draft.
  • Définir la variable de portail à 0, true, yes, on ou à une chaîne vide laisse le portail désactivé. Seule la chaîne exacte 1 l’active.
  • Les changements de putenv() prennent effet au prochain appel de isEnabled() car la lecture est en direct. Un portail basculé en cours de processus est observé immédiatement.
  • extract() distingue deux issues : null quand aucun Store n’est présent (peu coûteux, sans exception), et une sous-classe de C2paException levée quand un Store est présent mais hostile ou malformé. L’absence n’est jamais une erreur ; la présence conjuguée à la malformation l’est toujours.
  • JumbfBoxParser::parse('') renvoie la liste vide. Un ManifestStore vide mais présent fait un aller-retour vers lui-même ; la jointure ne le réduit pas à null.
  • Intégrer un Store vide PEUT renvoyer l’entrée inchangée. Le contrat de jointure autorise cette absence d’effet mais ne l’impose pas.
  • Les graphes JumbfBox construits à la main exécutent le même durcissement à la construction : contrôles de longueur et d’ASCII des TBox, plafond de profondeur, invariant de profondeur des enfants, règle d’exclusivité charge-utile-ou-enfants, et plafond de taille par boîte. Une bombe construite à la main échoue à la construction, pas au moment de l’intégration.
  • Chaque exception de l’analyseur porte des champs structurés — capKind/observed/cap, offset ou kind — de sorte que la télémétrie ne racle pas les chaînes de message. Toutes les sous-classes étendent C2paException (elle-même une RuntimeException), qui est le type de capture parapluie.
  • Le docblock de l’analyseur interdit d’avaler silencieusement ces exceptions ; les consommateurs les font remonter ou les remappent à dessein.
  • buildManifestStore() encode les charges utiles JSON avec JSON_THROW_ON_ERROR ; une chaîne $producer qui n’est pas de l’UTF-8 valide échoue avec \JsonException avant qu’aucune boîte ne soit construite.
  • Un résultat extract() bien formé n’est qu’un énoncé structurel. Il n’y a aucune validation de revendication, aucune vérification de signature ni aucune évaluation de confiance nulle part sur cette surface. La reconnaissance n’est pas un verdict de provenance.
  • Aucune clé de signature, aucun certificat ni aucune structure COSE n’est traité par cette surface. La seule opération cryptographique est un hachage de contenu SHA-256 au sein du chemin de synthèse sous portail.
AffirmationStandardClause
Les manifestes se sérialisent en un seul store JUMBF détenant plusieurs manifestes, adressables par URI.C2PA 2.1§11.1.1 (p63.b)
Les étiquettes des boîtes de description sont en UTF-8 à terminaison nulle avec des plages exclues ; des bascules sont définies pour toutes les boîtes de description.C2PA 2.1§11.1.4.1.1–11.1.4.1.2 (p63.a)
La boîte de signature de revendication est étiquetée c2pa.signature, typée c2cs, et détient une unique boîte de contenu CBOR.C2PA 2.1§11.1.4.4 (p63.c)
Une liaison forte lie cryptographiquement un manifeste à son actif et expose la modification — l’assertion de hachage non signée de l’aperçu n’atteint PAS ce seuil.C2PA 2.1§9.1 (p57)

Toutes les clauses sont paraphrasées. NextPDF ne reproduit pas de texte normatif. NextPDF ne détient aucune certification et n’en accorde aucune. Les énoncés ci-dessus sont des énoncés d’alignement structurel sur la disposition des boîtes, les étiquettes et les liaisons — ce ne sont pas des résultats de test de conformité, ni des attestations tierces, ni une affirmation de conformité C2PA ou ISO. Le profil C2PA-PDF n’est pas finalisé ; le format de fil synthétisé suit un commit de brouillon épinglé. C2paCapabilityStatus encode cette posture dans le code : generallyAvailable et conformanceClaimed valent false dans toute configuration. La sortie de cette surface n’est pas un Content Credential vérifiable, et aucun chemin de vérification n’existe dans NextPDF.

  • La grammaire de boîtes JUMBF que l’analyseur implémente (LBox big-endian de 4 octets, TBox ASCII de 4 octets, charge utile ; les superboîtes imbriquent des boîtes enfants) suit l’ISO 19566-5 ; ce standard est hors du corpus cité, donc le comportement de l’analyseur est fondé sur la source produit, non sur une citation de spécification.

  • Garde le portail désactivé en production. La synthèse de brouillon n’ajoute aucune capacité durable ; les octets émis sont transitoires et devraient être ré-intégrés une fois qu’un adaptateur stable sera livré.

  • Vérifie ExperimentalC2paEmbedder::SPEC_PIN_SHA contre le commit de brouillon que ta chaîne de traitement attend. Exécute composer c2pa:draft-status en CI (sortie 0 frais, 1 avertissement léger, 2 échec dur) pour détecter la péremption de l’épingle.

  • Traite C2paCapabilityStatus::current() comme la source unique de vérité lorsque tu exposes le statut C2PA dans l’outillage ou l’UI. Ne reformule pas ses booléens à la main ; summary() est sûr pour les journaux et les points de terminaison de statut.

  • Capture C2paException comme type parapluie lors de la consommation d’extract() ou de parse(). Fais correspondre les quatre sous-classes à des compteurs de télémétrie distincts en utilisant leurs champs structurés.

  • Injecte des plafonds plus stricts via le constructeur de JumbfBoxParser pour les processus de vérification à mémoire contrainte ; les valeurs par défaut sont des plafonds de production généreux.

  • C2paCapabilityStatus::__construct() est public, si bien qu’une instance construite à la main peut porter des booléens arbitraires. Une telle instance n’est qu’un objet-valeur ; elle n’altère aucun comportement.

Cette page documente uniquement le comportement observable de l’extérieur et la surface d’API publique prise en charge. Les chemins d’espace de noms internes, les classes utilitaires, les tables de mécanismes, les noms de fichiers de runbook et les préfixes de ticket sont hors périmètre.