You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An ingredient archive is a serialized `Builder` containing exactly one and only one ingredient (see [Builder archives vs. ingredient archives](#builder-archives-vs-ingredient-archives)). Reading it with `Reader` allows the caller to inspect the ingredient before deciding whether to use it: its thumbnail, whether it carries provenance (e.g. an active manifest), validation status, relationship, etc.
724
724
725
-
Reading is independent of linking — see [Linking an archived ingredient to an action](#linking-an-archived-ingredient-to-an-action) for how to attach the ingredient to an action without reading it first.
725
+
Reading is independent of linking, see [Linking an archived ingredient to an action](#linking-an-archived-ingredient-to-an-action) for how to attach the ingredient to an action without reading it first.
726
726
727
727
```mermaid
728
728
flowchart LR
@@ -741,7 +741,7 @@ auto parsed = json::parse(reader.json());
741
741
std::string active = parsed["active_manifest"];
742
742
auto manifest = parsed["manifests"][active];
743
743
744
-
// An ingredient archive has exactly one ingredient
744
+
// An ingredient archive must always have exactly one ingredient
745
745
auto& ingredient = manifest["ingredients"][0];
746
746
747
747
// Relationship
@@ -785,18 +785,20 @@ if (ingredient.contains("thumbnail")) {
785
785
786
786
#### Linking an archived ingredient to an action
787
787
788
-
Linking an archived ingredient to an action is **label-driven**. Set a `label` on the ingredient JSON passed to `add_ingredient` on the signing builder, and use that same string in the action's `ingredientIds`. Reading the archive first is *not* required to link it — `Reader` is only useful when the caller wants to preview the ingredient (thumbnail, provenance, validation status) before deciding whether to use it (see [Reading ingredient details from an ingredient archive](#reading-ingredient-details-from-an-ingredient-archive)).
788
+
Linking an **archived** ingredient to an action is **label-driven**: archived ingredients can only be linked to actions using labels.
789
789
790
-
> [!IMPORTANT]
790
+
To do so, set a `label` on the archived ingredient's JSON passed to `add_ingredient` on the builder, and use that same string in the action's `ingredientIds`.
791
+
792
+
Reading the archive first is *not* required to link it. `Reader` is only useful when the caller wants to preview the ingredient (thumbnail, provenance, validation status) before deciding whether to use it (see [Reading ingredient details from an ingredient archive](#reading-ingredient-details-from-an-ingredient-archive)).
793
+
794
+
> [!WARNING]
791
795
> **`instance_id` does not work as a linking key for ingredient archives.** Use `label` instead.
792
796
>
793
-
> **Labels baked into the archive ingredient at archive-creation time do not carry through as linking keys.** The label must be re-asserted on the signing builder's `add_ingredient` call.
794
-
>
795
-
> Both rules apply whether the archive is added by file path or by stream. Attempting to link via `instance_id`, or relying on a baked-in label alone, produces a sign-time error: `Action ingredientId not found: <id>`. See [Troubleshooting linking errors](#troubleshooting-linking-errors).
797
+
> **Labels baked into the archive ingredient at archive-creation time do not carry through as linking keys either.** The label must be re-asserted on the signing builder's `add_ingredient` call so action and archived ingredient properly link.
796
798
797
799
Labels are build-time linking keys only. The SDK may reassign the actual label in the signed manifest.
798
800
799
-
##### Minimal example
801
+
##### Minimal archive to action linking example
800
802
801
803
Build a manifest whose action references a chosen label, then `add_ingredient` with that label on the signing builder. No `Reader`, no parsing of the archive:
// Same string as in ingredientIds above — that is what links the action.
829
+
// Same label string as in ingredientIds above: that is what links the action.
828
830
builder.add_ingredient(
829
831
R"({
830
832
"title": "photo.jpg",
@@ -833,12 +835,11 @@ builder.add_ingredient(
833
835
})",
834
836
archive_path);
835
837
838
+
// Note that a signing, the SDK may reassign the labels
836
839
builder.sign(source_path, output_path, signer);
837
840
```
838
841
839
-
##### Using streams
840
-
841
-
The `add_ingredient` overload that takes a `std::istream` (with `"application/c2pa"` as the format) follows the same rule — the `label` on the ingredient JSON is what links the action:
842
+
The `add_ingredient` overload that takes a `std::istream` (with `"application/c2pa"` as the format) follows the same rules: the `label` on the ingredient JSON is what links the action:
If you want to inspect the archive (e.g. to decide whether to use it, or to copy `title` from it), open it with `Reader` first, then add it as an ingredient. The Reader step is independent of the linking — the link is still established by the `label` on the signing builder's `add_ingredient` call.
862
+
If you want to inspect the archive (e.g. to decide whether to use it, or to copy a `title` from it), open it with `Reader` first, then add it as an ingredient. The Reader step is independent of the linking: the link is still established by the `label` on the signing builder's `add_ingredient` call.
0 commit comments