Using builder intents
Intents tell the Builder what kind of manifest you are creating. They enable validation, add required default actions, and help prevent invalid operations.
Intent types
There are three types of intents, shown here:
| Intent | Use when... | Parent ingredient | Auto-generated action |
|---|---|---|---|
Create | Creating brand-new content | Must NOT have one | c2pa.created |
Edit | Modifying existing content | Auto-created from source if not provided | c2pa.opened (linked to parent) |
Update | Making metadata-only changes | Auto-created from source if not provided | c2pa.opened (linked to parent) |
- Rust
- C++
- Python
Setting the intent
Set the intent through Context settings or by calling set_intent on the Builder. Using Context keeps intent configuration alongside other builder settings:
use c2pa::{Context, Builder, Result};
fn main() -> Result<()> {
let context = Context::new()
.with_settings(r#"{
"builder": {
"intent": {"Create": "digitalCapture"},
"claim_generator_info": {"name": "My App", "version": "1.0"}
}
}"#)?;
let mut builder = Builder::from_context(context)
.with_definition(r#"{"title": "New Image"}"#)?;
let mut source = std::fs::File::open("source.jpg")?;
let mut dest = std::fs::File::create("signed.jpg")?;
builder.save_to_stream("image/jpeg", &mut source, &mut dest)?;
Ok(())
}
Alternatively, call set_intent directly on the Builder:
use c2pa::{Builder, BuilderIntent, DigitalSourceType};
builder.set_intent(BuilderIntent::Create(DigitalSourceType::DigitalCapture));
Create intent
Use BuilderIntent::Create(DigitalSourceType) for new digital creations without a parent ingredient. A DigitalSourceType is required; common values include Empty, DigitalCapture, TrainedAlgorithmicMedia, and DigitalCreation.
builder.set_intent(BuilderIntent::Create(DigitalSourceType::TrainedAlgorithmicMedia));
Edit intent
Use BuilderIntent::Edit for editing an existing asset. If no parent ingredient has been added, the Builder automatically derives one from the source stream:
use serde_json::json;
builder.set_intent(BuilderIntent::Edit);
builder.add_ingredient_from_stream(
json!({"title": "Original", "relationship": "parentOf"}).to_string(),
"image/jpeg",
&mut source_stream,
)?;
Update intent
Use BuilderIntent::Update for non-editorial, metadata-only changes. It allows exactly one ingredient (the parent) and does not allow changes to the parent's hashed content:
builder.set_intent(BuilderIntent::Update);
Setting the intent
Set the intent through Context settings or by calling set_intent on the Builder. Using Context keeps intent configuration alongside other builder settings:
#include "c2pa.hpp"
c2pa::Context context(R"({
"version": 1,
"builder": {
"intent": {"Create": "digitalCapture"},
"claim_generator_info": {"name": "My App", "version": "1.0"}
}
})");
c2pa::Builder builder(context, R"({})");
builder.sign(source_path, output_path, signer);
Alternatively, call set_intent directly on the Builder:
c2pa::Context context;
c2pa::Builder builder(context, R"({})");
builder.set_intent(Create, DigitalCapture);
builder.sign(source_path, output_path, signer);
Create intent
Use the Create intent for new digital creations without a parent ingredient. A C2paDigitalSourceType is required; common values include Empty, DigitalCapture, TrainedAlgorithmicMedia, and DigitalCreation.
c2pa::Context context(R"({
"version": 1,
"builder": {"intent": {"Create": "trainedAlgorithmicMedia"}}
})");
c2pa::Builder builder(context, R"({})");
builder.sign(source_path, output_path, signer);
Edit intent
Use the Edit intent for editing an existing asset. If no parent ingredient has been added, the Builder automatically creates one from the source stream passed to sign():
c2pa::Context context(R"({
"version": 1,
"builder": {"intent": "edit"}
})");
c2pa::Builder builder(context, R"({})");
builder.sign("original.jpg", "edited.jpg", signer);
To manually provide the parent ingredient:
c2pa::Context context(R"({
"version": 1,
"builder": {"intent": "edit"}
})");
c2pa::Builder builder(context, R"({})");
std::ifstream original("original.jpg", std::ios::binary);
builder.add_ingredient(
R"({"title": "Original Photo", "relationship": "parentOf"})",
"image/jpeg",
original
);
builder.sign("canvas.jpg", "edited.jpg", signer);
Update intent
Use the Update intent for non-editorial, metadata-only changes. It allows exactly one ingredient (the parent) and does not allow changes to the parent's hashed content:
c2pa::Context context(R"({
"version": 1,
"builder": {"intent": "update"}
})");
c2pa::Builder builder(context, R"({})");
builder.sign("signed_asset.jpg", "updated_asset.jpg", signer);
Setting the intent
Set the intent through Context settings. Using Context keeps intent configuration alongside other builder settings:
from c2pa import Context, Builder
ctx = Context.from_dict({
"builder": {
"intent": {"Create": "digitalCapture"},
"claim_generator_info": {"name": "My App", "version": "1.0"}
}
})
builder = Builder(manifest_json, context=ctx)
with open("source.jpg", "rb") as src, open("signed.jpg", "w+b") as dst:
builder.sign(signer, "image/jpeg", src, dst)
Alternatively, you can call set_intent directly on a Builder instance for one-off operations or when the intent is determined at runtime. For example:
with Builder({}) as builder:
builder.set_intent(
C2paBuilderIntent.CREATE,
C2paDigitalSourceType.TRAINED_ALGORITHMIC_MEDIA,
)
with open("source.jpg", "rb") as source, open("output.jpg", "wb") as dest:
builder.sign(signer, "image/jpeg", source, dest)
Create intent
Use the Create intent for new digital creations without a parent ingredient. A digital source type is required; common values include "digitalCapture", "trainedAlgorithmicMedia", and "digitalCreation".
ctx = Context.from_dict({
"builder": {"intent": {"Create": "trainedAlgorithmicMedia"}}
})
builder = Builder(manifest_json, context=ctx)
with open("source.jpg", "rb") as src, open("signed.jpg", "w+b") as dst:
builder.sign(signer, "image/jpeg", src, dst)
Edit intent
Use the Edit intent for editing an existing asset. If no parent ingredient has been added, the Builder automatically creates one from the source stream passed to sign():
ctx = Context.from_dict({
"builder": {"intent": "edit"}
})
builder = Builder(manifest_json, context=ctx)
with open("original.jpg", "rb") as src, open("edited.jpg", "w+b") as dst:
builder.sign(signer, "image/jpeg", src, dst)
To manually provide the parent ingredient:
import json
ctx = Context.from_dict({
"builder": {"intent": "edit"}
})
builder = Builder(manifest_json, context=ctx)
ingredient_json = json.dumps({
"title": "Original Photo",
"relationship": "parentOf"
})
with open("original.jpg", "rb") as ingredient:
builder.add_ingredient(ingredient_json, "image/jpeg", ingredient)
with open("canvas.jpg", "rb") as src, open("edited.jpg", "w+b") as dst:
builder.sign(signer, "image/jpeg", src, dst)
Update intent
Use the Update intent for non-editorial, metadata-only changes. It allows exactly one ingredient (the parent) and does not allow changes to the parent's hashed content:
ctx = Context.from_dict({
"builder": {"intent": "update"}
})
builder = Builder(manifest_json, context=ctx)
with open("signed_asset.jpg", "rb") as src, open("updated.jpg", "w+b") as dst:
builder.sign(signer, "image/jpeg", src, dst)