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
Copy file name to clipboardExpand all lines: docs/selective-manifests.md
+184Lines changed: 184 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -557,6 +557,45 @@ with Reader("application/c2pa", archive_stream, context=ctx) as reader:
557
557
new_builder.sign("image/jpeg", source, dest)
558
558
```
559
559
560
+
### Identifying ingredients in archives
561
+
562
+
When building an ingredient archive, you can set `instance_id` on the ingredient to give it a stable, caller-controlled identifier. This field survives archiving and signing unchanged, so it can be used to look up a specific ingredient from a catalog archive. The `description` and `informational_URI` fields also survive and can carry additional metadata about the ingredient's origin.
563
+
564
+
`instance_id` is only for identification and catalog lookups. It cannot be used as a linking key in `ingredientIds` when linking ingredient archives to actions — use `label` for that (see [Linking an archived ingredient to an action](#linking-an-archived-ingredient-to-an-action)).
565
+
566
+
```py
567
+
# Set instance_id when adding the ingredient to the archive builder.
568
+
builder = Builder.from_json(manifest_json)
569
+
withopen("photo-A.jpg", "rb") as f:
570
+
builder.add_ingredient(
571
+
{
572
+
"title": "photo-A.jpg",
573
+
"relationship": "componentOf",
574
+
"instance_id": "catalog:photo-A",
575
+
},
576
+
"image/jpeg",
577
+
f,
578
+
)
579
+
580
+
archive = io.BytesIO()
581
+
builder.to_archive(archive)
582
+
```
583
+
584
+
Later, when reading the archive, select ingredients by their `instance_id`:
When adding an ingredient from an archive or from a file, the JSON passed to `add_ingredient()` can override properties like `title` and `relationship`. This is useful when reusing archived ingredients in a different context:
@@ -731,6 +770,111 @@ with Reader("application/c2pa", archive_stream, context=ctx) as reader:
731
770
new_builder.sign("image/jpeg", source, dest)
732
771
```
733
772
773
+
### Reading ingredient details from an ingredient archive
774
+
775
+
An ingredient archive is a serialized `Builder` containing exactly 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.
776
+
777
+
```py
778
+
# Open the ingredient archive.
779
+
withopen("ingredient_archive.c2pa", "rb") as archive_file:
After reading the ingredient details from an ingredient archive, the ingredient can be added to a new `Builder` and linked to an action. You must assign a `label` in the `add_ingredient()` call on the signing builder and use that label as the linking key in `ingredientIds`. Labels baked into the archive ingredient are not carried through, and `instance_id` does not work as a linking key for ingredient archives.
820
+
821
+
Labels are only used as build-time linking keys. The SDK may reassign the actual label in the signed manifest.
822
+
823
+
Assign a `label` in the `add_ingredient()` call and reference that same label in `ingredientIds` to link an ingredient to an action.
with Builder(manifest_json, context=ctx) as builder:
860
+
# The label on the ingredient must match the entry in ingredientIds on the action.
861
+
archive_file.seek(0)
862
+
builder.add_ingredient(
863
+
{
864
+
"title": ingredient["title"],
865
+
"relationship": "parentOf",
866
+
"label": "archived-ingredient",
867
+
},
868
+
"application/c2pa",
869
+
archive_file,
870
+
)
871
+
872
+
withopen("source.jpg", "rb") as source, open("output.jpg", "w+b") as dest:
873
+
builder.sign("image/jpeg", source, dest)
874
+
875
+
reader.close()
876
+
```
877
+
734
878
### Merging multiple working stores
735
879
736
880
> [!NOTE]
@@ -802,3 +946,43 @@ with Builder({
802
946
# configure a dedicated Signer explicitly.
803
947
builder.sign("image/jpeg", source, dest)
804
948
```
949
+
950
+
## Controlling manifest embedding
951
+
952
+
By default, `sign()` embeds the manifest directly inside the output asset file.
953
+
954
+
### Not embedding a manifest store into an asset
955
+
956
+
Use `set_no_embed()` so the signed asset contains no embedded manifest store. The manifest store bytes are returned from `sign()` and can be stored separately (e.g. as a sidecar file).
# manifest_bytes contains the full manifest store.
970
+
# Upload manifest_bytes to the remote URL.
971
+
# The output asset has no embedded manifest.
972
+
```
973
+
974
+
### Checking manifest location on a Reader
975
+
976
+
After opening an asset with `Reader`, use `is_embedded()` to check whether the manifest is embedded in the asset or stored remotely. If the manifest is remote, `get_remote_url()` returns the URL it was fetched from (the URL set via `set_remote_url()` at signing time).
Copy file name to clipboardExpand all lines: docs/working-stores.md
+130Lines changed: 130 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -435,6 +435,136 @@ with open("new_asset.jpg", "rb") as src, open("signed_asset.jpg", "w+b") as dst:
435
435
builder.sign("image/jpeg", src, dst)
436
436
```
437
437
438
+
### Linking an ingredient archive to an action
439
+
440
+
To link an ingredient archive to an action via `ingredientIds`, you must use a `label` set in the `add_ingredient()` call on the signing builder. Labels baked into the archive ingredient are not carried through, and `instance_id` does not work as a linking key for ingredient archives regardless of where it is set.
withopen("source.jpg", "rb") as src, open("signed.jpg", "w+b") as dst:
492
+
builder.sign("image/jpeg", src, dst)
493
+
```
494
+
495
+
When linking multiple ingredient archives, give each a distinct label and reference it in the appropriate action's `ingredientIds` array.
496
+
497
+
If each ingredient has its own action (e.g., one `c2pa.opened` for the parent and one `c2pa.placed` for a composited element), set up two actions with separate `ingredientIds`:
0 commit comments