### Complete C2PA Asset Signing and Reading Example Source: https://github.com/contentauth/c2pa-python/blob/main/docs/working-stores.md A comprehensive example demonstrating the creation of a C2PA manifest, loading credentials, setting up a signer and context, signing an asset, and then reading the manifest back. ```python import json from c2pa import Builder, Reader, Context, Signer, C2paSignerInfo, C2paSigningAlg try: # 1. Define manifest manifest_json = json.dumps({ "claim_generator_info": [{"name": "demo-app", "version": "0.1.0"}], "title": "Signed image", "assertions": [] }) # 2. Load credentials and create signer with open("certs.pem", "rb") as f: certs = f.read() with open("private_key.pem", "rb") as f: private_key = f.read() signer_info = C2paSignerInfo( alg=C2paSigningAlg.ES256, sign_cert=certs, private_key=private_key, ta_url=b"http://timestamp.digicert.com" ) signer = Signer.from_info(signer_info) # 3. Create context with settings and signer ctx = Context.from_dict({ "builder": {"thumbnail": {"enabled": True}} }, signer=signer) # 4. Create Builder with context and sign builder = Builder(manifest_json, context=ctx) with open("source.jpg", "rb") as src, open("signed.jpg", "w+b") as dst: builder.sign("image/jpeg", src, dst) print("Asset signed with context settings") # 5. Read back the manifest store reader = Reader("signed.jpg", context=ctx) print(reader.json()) except Exception as e: print(f"Error: {e}") ``` -------------------------------- ### Install development dependencies for API docs Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Install the necessary development dependencies, including those for generating API documentation. ```bash cd c2pa-python python3 -m pip install -r requirements-dev.txt ``` -------------------------------- ### Run Signing and Verification Example with SignerInfo Source: https://github.com/contentauth/c2pa-python/blob/main/examples/README.md Execute this command to run the Python script that utilizes SignerInfo to create a Signer object for manifest signing and verification. ```bash python examples/sign_info.py ``` -------------------------------- ### Create and Link Ingredient Archive Source: https://github.com/contentauth/c2pa-python/blob/main/docs/working-stores.md This example demonstrates creating an ingredient archive and then building a manifest that references this archive via `ingredientIds`. Ensure the label used when adding the archive to the builder matches the `ingredientIds` value. ```python import io, json # Step 1: Create the ingredient archive. archive_builder = Builder.from_json({ "claim_generator_info": [{"name": "an-application", "version": "0.1.0"}], "assertions": [], }) with open("photo.jpg", "rb") as f: archive_builder.add_ingredient( {"title": "photo.jpg", "relationship": "componentOf"}, "image/jpeg", f, ) archive = io.BytesIO() archive_builder.to_archive(archive) archive.seek(0) # Step 2: Build a manifest with an action that references the ingredient. manifest_json = { "claim_generator_info": [{"name": "an-application", "version": "0.1.0"}], "assertions": [ { "label": "c2pa.actions.v2", "data": { "actions": [ { "action": "c2pa.placed", "parameters": { "ingredientIds": ["my-ingredient"] }, } ] }, } ], } ctx = Context.from_dict({"signer": signer}) builder = Builder(manifest_json, context=ctx) # Step 3: Add the ingredient archive with a label matching the ingredientIds value. ``` -------------------------------- ### Run Callback Signing and Verification Example Source: https://github.com/contentauth/c2pa-python/blob/main/examples/README.md Execute this command to run the Python script that uses a callback signer for signing and verification operations. ```bash python examples/sign.py ``` -------------------------------- ### Install project dependencies Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Load project dependencies using pip. Ensure you have both general and development requirements installed. ```bash pip install -r requirements.txt ``` ```bash pip install -r requirements-dev.txt ``` -------------------------------- ### Build wheel for your platform Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Build the Python wheel package for your current platform. This requires activating the virtual environment and installing build tools. ```bash source .venv/bin/activate pip install -r requirements.txt python3 -m pip install build pip install -U pytest python3 -m build --wheel ``` -------------------------------- ### Install c2pa-python Package Source: https://github.com/contentauth/c2pa-python/blob/main/README.md Install the c2pa-python package from PyPI. This command is used in your terminal or command prompt. ```bash pip install c2pa-python ``` -------------------------------- ### Run C2PA Reading Example Source: https://github.com/contentauth/c2pa-python/blob/main/examples/README.md Execute this command in your terminal to run the Python script that reads C2PA data from an asset. ```bash python examples/read.py ``` -------------------------------- ### Add Signed Manifest to Stream Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md This example shows how to add a signed manifest to a stream, including adding ingredients and signing the final output. It also demonstrates how to verify the signed file. Note: Accessing private keys directly from the file system is insecure for production environments. ```python try: with open("path/to/cert.pem", "rb") as cert_file, open("path/to/key.pem", "rb") as key_file: cert_data = cert_file.read() key_data = key_file.read() signer_info = C2paSignerInfo( alg=C2paSigningAlg.PS256, sign_cert=cert_data, private_key=key_data, ta_url=b"http://timestamp.digicert.com" ) with Context() as ctx: with Signer.from_info(signer_info) as signer: with Builder(manifest_json, ctx) as builder: with open("path/to/ingredient.jpg", "rb") as ingredient_file: ingredient_json = json.dumps({"title": "Ingredient Image"}) builder.add_ingredient(ingredient_json, "image/jpeg", ingredient_file) with open("path/to/source.jpg", "rb") as source, open("path/to/output.jpg", "w+b") as dest: builder.sign(signer, "image/jpeg", source, dest) # Verify the signed file with the same context with open("path/to/output.jpg", "rb") as stream: with Reader("image/jpeg", stream, context=ctx) as reader: manifest_store = json.loads(reader.json()) active_manifest = manifest_store["manifests"][manifest_store["active_manifest"]] print("Signed manifest:", active_manifest) except Exception as e: print("Failed to sign manifest store: " + str(e)) ``` -------------------------------- ### Run tests with PyTest Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Alternatively, run tests directly using PyTest after installing it. Be cautious when switching virtual environments. ```bash pip install pytest pytest ``` -------------------------------- ### Add Signed Manifest to File Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Sign a source file and create an output file with an added C2PA manifest. This example shows how to add an ingredient and sign the file using explicit certificate and key data. For production, use a KMS or HSM instead of direct file access for security. ```python try: with open("path/to/cert.pem", "rb") as cert_file, open("path/to/key.pem", "rb") as key_file: cert_data = cert_file.read() key_data = key_file.read() signer_info = C2paSignerInfo( alg=C2paSigningAlg.PS256, sign_cert=cert_data, private_key=key_data, ta_url=b"http://timestamp.digicert.com" ) with Context() as ctx: with Signer.from_info(signer_info) as signer: with Builder(manifest_json, ctx) as builder: with open("path/to/ingredient.jpg", "rb") as ingredient_file: ingredient_json = json.dumps({"title": "Ingredient Image"}) builder.add_ingredient(ingredient_json, "image/jpeg", ingredient_file) # Sign using file paths builder.sign_file("path/to/source.jpg", "path/to/output.jpg", signer) # Verify the signed file with the same context with Reader("path/to/output.jpg", context=ctx) as reader: manifest_store = json.loads(reader.json()) active_manifest = manifest_store["manifests"][manifest_store["active_manifest"]] print("Signed manifest:", active_manifest) except Exception as e: print("Failed to sign manifest store: " + str(e)) ``` -------------------------------- ### Create Intent: New Digital Creation Source: https://github.com/contentauth/c2pa-python/blob/main/docs/intents.md Use the `Create` intent when the asset has no prior history. This example shows how to specify `C2paDigitalSourceType.DIGITAL_CREATION` using the `Context` object. ```python ctx = Context.from_dict({ "builder": {"intent": {"Create": "digitalCreation"}} }) with Builder({}, context=ctx) as builder: with open("source.jpg", "rb") as source, open("output.jpg", "wb") as dest: builder.sign(signer, "image/jpeg", source, dest) ``` -------------------------------- ### End-to-End Signing with 'Do Not Train' Assertion Source: https://context7.com/contentauth/c2pa-python/llms.txt Demonstrates a full workflow for creating a C2PA manifest with AI training restrictions, signing it using a callback signer, extracting resources, and verifying assertions. This example mirrors the `examples/training.py` pattern. ```python import json import io from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.backends import default_backend import c2pa from c2pa import Builder, Reader, Signer, Context, Settings, C2paSigningAlg, C2paError # Load credentials with open("tests/fixtures/es256_certs.pem", "rb") as f: certs = f.read() with open("tests/fixtures/es256_private.key", "rb") as f: key_pem = f.read() def es256_sign(data: bytes) -> bytes: pk = serialization.load_pem_private_key(key_pem, password=None, backend=default_backend()) return pk.sign(data, ec.ECDSA(hashes.SHA256())) manifest_def = { "claim_generator_info": [{"name": "my_pipeline", "version": "1.0"}], "title": "Protected Image", "assertions": [ { "label": "c2pa.actions", "data": {"actions": [{"action": "c2pa.created", "digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCreation"}]} }, { "label": "cawg.training-mining", "data": {"entries": { "cawg.ai_generative_training": {"use": "notAllowed"}, "cawg.ai_inference": {"use": "notAllowed"} }} } ] } ``` -------------------------------- ### Consume-and-Return Pattern Example Source: https://github.com/contentauth/c2pa-python/blob/main/docs/native-resources-management.md Demonstrates the consume-and-return pattern where a native pointer is replaced within an existing object. This is used when the native library must update its internal state without discarding the Python-side object, such as when feeding new data fragments to a Reader. ```mermaid stateDiagram-v2 state "ACTIVE (ptr A)" as A state "ACTIVE (ptr B)" as B A --> B : C FFI call consumes ptr A, returns ptr B note right of B Same Python object, new native pointer end note ``` -------------------------------- ### Set up a virtual environment Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Create and activate a virtual environment for development. This isolates project dependencies. ```bash python -m venv .venv ``` ```bash .venv\Scripts\activate ``` ```bash source .venv/bin/activate ``` -------------------------------- ### Install package in development mode Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Install the package in editable mode. This allows changes to Python code to take effect without reinstallation. ```bash pip install -e . ``` -------------------------------- ### Initialize Context with SDK Defaults Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Use SDK default settings for quick prototyping when defaults are acceptable. ```python from c2pa import Context ctx = Context() # Uses SDK defaults ``` -------------------------------- ### Create New Builder with Selected Ingredients and Sign Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Filters ingredients to select 'A.jpg', initializes a new builder with these selected ingredients, transfers resources, and signs a source image to create a signed output. ```python sign_ctx = Context.from_dict({ "builder": { "thumbnail": {"enabled": False}, "claim_generator_info": {"name": "an-application", "version": "0.1.0"} }, "signer": signer, }) selected = [ing for ing in ingredients if ing["title"] == "A.jpg"] with Builder({ "claim_generator_info": [{"name": "an-application", "version": "0.1.0"}], "ingredients": selected, }, context=sign_ctx) as new_builder: transfer_ingredient_resources(reader, new_builder, selected) with open("source.jpg", "rb") as source, open("output.jpg", "wb") as dest: # In this example, the Signer is on the context. # A Signer can also be passed as first argument to # configure a dedicated Signer explicitly. new_builder.sign("image/jpeg", source, dest) ``` -------------------------------- ### Initialize Builder with Context for Manifest Creation Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Demonstrates creating a `Context` with specific builder configurations, such as claim generator information and intent, and passing it to the `Builder` for manifest creation and signing. ```python ctx = Context.from_dict({ "builder": { "claim_generator_info": {"name": "An app", "version": "0.1.0"}, "intent": {"Create": "digitalCapture"} } }) builder = Builder(manifest_json, context=ctx) with open("source.jpg", "rb") as src, open("output.jpg", "w+b") as dst: builder.sign(signer, "image/jpeg", src, dst) ``` -------------------------------- ### Define and Sign a Manifest (V2 Claims Format) Source: https://context7.com/contentauth/c2pa-python/llms.txt This snippet demonstrates defining a manifest structure, adding resources and ingredients, and signing a JPEG file. Ensure necessary certificates and keys are available. ```python manifest_def = { "claim_generator_info": [{"name": "my_app", "version": "1.0"}], "title": "Signed Asset", "format": "image/jpeg", "assertions": [ { "label": "c2pa.actions", "data": { "actions": [{ "action": "c2pa.created", "digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture" }] } }, { "label": "cawg.training-mining", "data": { "entries": { "cawg.ai_generative_training": {"use": "notAllowed"}, "cawg.ai_inference": {"use": "notAllowed"} } } } ] } ingredient_def = {"title": "source.jpg", "relationship": "parentOf"} with open("tests/fixtures/es256_certs.pem", "rb") as f: certs = f.read() with open("tests/fixtures/es256_private.key", "rb") as f: key = f.read() signer_info = C2paSignerInfo(C2paSigningAlg.ES256, certs, key, b"http://timestamp.digicert.com") with Context() as ctx: with Signer.from_info(signer_info) as signer: with Builder(manifest_def, ctx) as builder: # Add a thumbnail resource (referenced by URI in manifest) with open("tests/fixtures/A_thumbnail.jpg", "rb") as thumb: builder.add_resource("thumbnail", thumb) # Add a parent ingredient with open("tests/fixtures/A.jpg", "rb") as ingredient: builder.add_ingredient(json.dumps(ingredient_def), "image/jpeg", ingredient) # Add an action assertion directly builder.add_action({"action": "c2pa.opened"}) # Set remote URL (for sidecar/cloud manifests) # builder.set_remote_url("https://example.com/manifest.c2pa") # builder.set_no_embed() # don't embed manifest in asset # Sign using file paths (auto-detects MIME type) manifest_bytes = builder.sign_file( "tests/fixtures/A.jpg", # source "output/A_signed.jpg", # destination signer ) # OR sign with explicit streams # with open("tests/fixtures/A.jpg", "rb") as src, \ # open("output/A_signed.jpg", "w+b") as dst: # manifest_bytes = builder.sign(signer, "image/jpeg", src, dst) print(f"Manifest bytes length: {len(manifest_bytes)}") ``` -------------------------------- ### Define manifest JSON Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Create a JSON string that defines the C2PA manifest to be embedded in an asset. This example includes claim generator information and assertions. ```python import json manifest_json = json.dumps({ "claim_generator": "python_test/0.1", "assertions": [ { "label": "cawg.training-mining", "data": { "entries": { "cawg.ai_inference": { "use": "notAllowed" }, "cawg.ai_generative_training": { "use": "notAllowed" } } } } ] }) ``` -------------------------------- ### Import Context and Settings objects Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Import classes for per-instance configuration, enabling granular control over reader and builder behavior. ```python from c2pa import Settings, Context, ContextBuilder, ContextProvider ``` -------------------------------- ### Run 'Do Not Train' Assertion Example Source: https://github.com/contentauth/c2pa-python/blob/main/examples/README.md Execute this command to run the Python script that adds and verifies a 'do not train' assertion in a C2PA manifest. ```bash python examples/training.py ``` -------------------------------- ### Initialize Reader from Stream with Context Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Illustrates reading from a file stream and initializing the `Reader` with a pre-configured `Context` to manage manifest validation and remote resource handling. ```python with open("image.jpg", "rb") as stream: reader = Reader("image/jpeg", stream, context=ctx) print(reader.json()) ``` -------------------------------- ### Initialize Reader with Context for Verification Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Shows how to create a `Context` from a dictionary and pass it to the `Reader` constructor to control verification behavior and trust configuration. ```python ctx = Context.from_dict({"verify": {"remote_manifest_fetch": False}}) reader = Reader("image.jpg", context=ctx) print(reader.json()) ``` -------------------------------- ### Load Archived Manifest with Context Settings Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Shows how to initialize a `Builder` with a `Context` and then load an archived manifest definition using `with_archive()`, preserving context settings like thumbnails and claim generator info. ```python ctx = Context.from_dict({ "builder": { "thumbnail": {"enabled": False}, "claim_generator_info": {"name": "My App", "version": "0.1.0"} } }) with open("manifest.c2pa", "rb") as archive: builder = Builder({}, context=ctx) builder.with_archive(archive) # builder now has the archived definition + context settings ``` -------------------------------- ### Conventional Commit Message Example Source: https://github.com/contentauth/c2pa-python/blob/main/CONTRIBUTING.md Follows conventional commits for pull request titles targeting long-lived branches. Includes an optional scope and a detailed body. ```text feat(api): Introduce a new API to validate 1.0 claims Repurpose existing v2 API for 0.8 compatibility (read: no validation) mode. ``` -------------------------------- ### Configuration from Environment Variables Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Applies context settings based on an environment variable, switching between production and development configurations. Allows dynamic configuration based on deployment environment. ```python import os env = os.environ.get("ENVIRONMENT", "dev") settings = Settings() if env == "production": settings.update({"verify": {"strict_v1_validation": True}}) else: settings.update({"verify": {"remote_manifest_fetch": False}}) ctx = Context(settings) ``` -------------------------------- ### Query Supported MIME Types for Reading and Signing Source: https://context7.com/contentauth/c2pa-python/llms.txt Get a list of MIME types that the C2PA library can read or sign. Results are cached after the first call. ```python from c2pa import Reader, Builder read_formats = Reader.get_supported_mime_types() print("Readable formats:", read_formats) # e.g. ['image/jpeg', 'image/png', 'video/mp4', 'application/pdf', ...] build_formats = Builder.get_supported_mime_types() print("Signable formats:", build_formats) ``` -------------------------------- ### Get c2pa-python SDK Version Source: https://context7.com/contentauth/c2pa-python/llms.txt Retrieve the semantic version string of the underlying native c2pa-rs / c2pa-c library. This is useful for diagnostics and ensuring version compatibility. ```python import c2pa version = c2pa.sdk_version() print(version) # Example output: "0.80.0" ``` -------------------------------- ### Build and Archive C2PA Store with Ingredients Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Initializes a builder, adds ingredients (A.jpg, B.jpg) with specified relationships, and archives the working store to a byte stream. ```python ctx = Context.from_dict({ "builder": {"claim_generator_info": {"name": "an-application", "version": "0.1.0"}}, }) with Builder({ "claim_generator_info": [{"name": "an-application", "version": "0.1.0"}], }, context=ctx) as builder: # Add ingredients to the working store with open("A.jpg", "rb") as ing_a: builder.add_ingredient( {"title": "A.jpg", "relationship": "componentOf"}, "image/jpeg", ing_a, ) with open("B.jpg", "rb") as ing_b: builder.add_ingredient( {"title": "B.jpg", "relationship": "componentOf"}, "image/jpeg", ing_b, ) # Save the working store as an archive archive_stream = io.BytesIO() builder.to_archive(archive_stream) ``` -------------------------------- ### Multiple Contexts for Different Purposes Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Create distinct Context objects when different configurations are needed simultaneously. This allows for isolated settings for development and production environments, for example. ```python dev_ctx = Context(dev_settings) prod_ctx = Context(prod_settings) dev_builder = Builder(manifest, dev_ctx) prod_builder = Builder(manifest, prod_ctx) ``` -------------------------------- ### Filter Actions Using Custom Vendor Parameters Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Custom vendor parameters can be used to filter actions. This example shows how to find actions related to a specific layer ID. ```python layer_actions = [ action for action in actions if action.get("parameters", {}).get("com.mycompany.layer_id") == "layer-42" ] ``` -------------------------------- ### Layered Configuration with Runtime Updates Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Demonstrates loading a base configuration from a JSON file and applying runtime overrides using the `Settings.update` method. Useful for managing complex configurations. ```python import json with open("config/base.json", "r") as f: base_config = json.load(f) settings = Settings.from_dict(base_config) settings.update({"builder": {"claim_generator_info": {"version": app_version}}}) ctx = Context(settings) ``` -------------------------------- ### Run project tests Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Execute the project's test suite using the provided Makefile target. This is the recommended way to run tests. ```bash make test ``` -------------------------------- ### Create a Working Store (Builder) Source: https://github.com/contentauth/c2pa-python/blob/main/docs/working-stores.md A working store is represented by a `Builder` object, initialized with manifest data. A `Context` can be provided for configuration, such as enabling thumbnails. ```python import json from c2pa import Builder, Context manifest_json = json.dumps({ "claim_generator_info": [{ "name": "example-app", "version": "0.1.0" }], "title": "Example asset", "assertions": [] }) ctx = Context.from_dict({ "builder": { "thumbnail": {"enabled": True} } }) builder = Builder(manifest_json, context=ctx) ``` -------------------------------- ### Read and Validate C2PA Data from Stream Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Read and validate C2PA data from a stream, similar to file-based operations. This example demonstrates reading from a JPEG image stream with custom settings applied via a Context. ```python try: settings = Settings.from_dict({"verify": {"verify_cert_anchors": True}}) with Context(settings) as ctx: with open("path/to/media_file.jpg", "rb") as stream: with Reader("image/jpeg", stream, context=ctx) as reader: print("Manifest store:", reader.json()) except Exception as err: print(err) ``` -------------------------------- ### Extracting Binary Resources from Reader Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Extract binary data like thumbnails or ingredient manifest stores referenced by JUMBF URIs in the manifest JSON. Use `resource_to_stream()` to get the content into an in-memory stream or a file. ```python # Extract a thumbnail to an in-memory stream thumb_stream = io.BytesIO() reader.resource_to_stream(thumbnail_id, thumb_stream) # Or extract to a file with open("thumbnail.jpg", "wb") as f: reader.resource_to_stream(thumbnail_id, f) ``` -------------------------------- ### Add Ingredient and Sign Manifest Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md This snippet demonstrates how to add an ingredient to a manifest and then sign the manifest. It uses `instance_id` for linking and shows the process of signing an image. ```python instance_id = "xmp:iid:939a4c48-0dff-44ec-8f95-61f52b11618f" manifest_json = { "claim_generator_info": [{"name": "an-application", "version": "0.1.0"}], "assertions": [ { "label": "c2pa.actions", "data": { "actions": [ { "action": "c2pa.opened", "parameters": { "ingredientIds": [instance_id] }, } ] }, } ], } with Builder(manifest_json, context=ctx) as builder: # No label set: instance_id is used as the linking key with open("source_photo.jpg", "rb") as photo: builder.add_ingredient( { "title": "source_photo.jpg", "relationship": "parentOf", "instance_id": instance_id, }, "image/jpeg", photo, ) with open("source.jpg", "rb") as source, open("output.jpg", "wb") as dest: # In this example, the Signer is on the context. # A Signer can also be passed as first argument to # configure a dedicated Signer explicitly. builder.sign("image/jpeg", source, dest) ``` -------------------------------- ### Do Not Embed Manifest Store Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Use `set_no_embed()` to prevent the signed asset from containing an embedded manifest store. The manifest store bytes are returned from `sign()` and can be stored separately, for example, as a sidecar file. A remote URL for storage can be specified using `set_remote_url()`. ```python ctx = Context.from_dict({ "builder": {"claim_generator_info": {"name": "an-application", "version": "0.1.0"}}, "signer": signer, }) builder = Builder(manifest_json, context=ctx) builder.set_no_embed() builder.set_remote_url("<>") with open("source.jpg", "rb") as source, open("output.jpg", "w+b") as dest: manifest_bytes = builder.sign("image/jpeg", source, dest) # manifest_bytes contains the full manifest store. # Upload manifest_bytes to the remote URL. # The output asset has no embedded manifest. ``` -------------------------------- ### Initialize Context from JSON String Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Configure the Context using a JSON string for simple, non-shared configurations. ```python ctx = Context.from_json('''{ "verify": {"verify_after_sign": true}, "builder": { "thumbnail": {"enabled": false}, "claim_generator_info": {"name": "An app", "version": "0.1.0"} } }''') ``` -------------------------------- ### Configure Settings with Chained Set and Update Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Demonstrates chaining `set()` calls for individual configurations and using `update()` to merge dictionary-based settings. Later calls override earlier ones. ```python from c2pa import Settings settings = Settings() settings.set("builder.thumbnail.enabled", "false").set("verify.verify_after_sign", "true") settings.update({"verify": {"remote_manifest_fetch": True}}) ``` -------------------------------- ### Read and Validate C2PA Data from File Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Use the Reader to examine a media file for C2PA data and generate a report. Pass a Context to apply custom settings like trust anchors or verification flags. This example demonstrates reading from a JPG file. ```python try: settings = Settings.from_dict({ "verify": {"verify_cert_anchors": True}, "trust": {"trust_anchors": anchors_pem} }) with Context(settings) as ctx: with Reader("path/to/media_file.jpg", context=ctx) as reader: print("Manifest store:", reader.json()) except Exception as err: print(err) ``` -------------------------------- ### Initialize Context from Dictionary Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Build Context configuration programmatically using native Python dictionaries. ```python ctx = Context.from_dict({ "verify": {"verify_after_sign": True}, "builder": { "thumbnail": {"enabled": False}, "claim_generator_info": {"name": "An app", "version": "0.1.0"} } }) ``` -------------------------------- ### Configure SDK with Settings Source: https://context7.com/contentauth/c2pa-python/llms.txt The `Settings` object encapsulates all SDK configuration options, including verification behavior, trust anchors, and builder settings. Methods are chainable, and `Settings` can be created with defaults, mutated, or initialized from JSON strings or dictionaries. Recommended for programmatic configuration. ```python from c2pa import Settings, Context # Create with defaults, then mutate settings = Settings() settings.set("builder.thumbnail.enabled", "false") # dot-notation; value must be a string settings.set("verify.verify_after_sign", "true") settings.update({"verify": {"remote_manifest_fetch": False}}) # merge dict # Create from JSON string settings2 = Settings.from_json('{"builder": {"thumbnail": {"enabled": false, "long_edge": 512}}}') # Create from dict (recommended for programmatic config) settings3 = Settings.from_dict({ "verify": { "verify_after_reading": True, "verify_trust": True, "ocsp_fetch": False, "remote_manifest_fetch": False }, "builder": { "claim_generator_info": {"name": "My App", "version": "1.0.0"}, "thumbnail": {"enabled": True, "long_edge": 1024, "quality": "medium"} }, "trust": { "trust_anchors": open("trust-anchors.pem").read() } }) ctx = Context(settings3) ``` -------------------------------- ### Settings Class Methods Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Demonstrates the creation and manipulation of settings using the Settings class. ```APIDOC ## Settings() ### Description Create default settings with SDK defaults. ### Method Settings() ### Parameters None ### Response - **self** (Settings) - The newly created Settings object. ## Settings.from_json(json_str) ### Description Create settings from a JSON string. Raises `C2paError` on parse error. ### Method Settings.from_json(json_str: str) ### Parameters - **json_str** (str) - A JSON string representing the settings. ### Response - **self** (Settings) - The newly created Settings object. ## Settings.from_dict(config) ### Description Create settings from a Python dictionary. ### Method Settings.from_dict(config: dict) ### Parameters - **config** (dict) - A dictionary representing the settings. ### Response - **self** (Settings) - The newly created Settings object. ## Settings.set(path, value) ### Description Set a single value by dot-separated path. Value must be a string. Returns `self` for chaining. ### Method set(path: str, value: str) ### Parameters - **path** (str) - The dot-separated path to the setting (e.g., "verify.verify_after_sign"). - **value** (str) - The string value to set. ### Response - **self** (Settings) - The Settings object for chaining. ## Settings.update(data) ### Description Merge configuration into existing settings. `data` can be a JSON string or a dict. Later keys override earlier ones. ### Method update(data: Union[str, dict]) ### Parameters - **data** (Union[str, dict]) - A JSON string or a dictionary containing the configuration to merge. ### Response - **self** (Settings) - The Settings object for chaining. ### Request Example ```python from c2pa import Settings settings = Settings() settings.set("builder.thumbnail.enabled", "false").set("verify.verify_after_sign", "true") settings.update({"verify": {"remote_manifest_fetch": True}}) ``` ``` -------------------------------- ### Initialize Context from Settings Object Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Configure Context with runtime logic or layered settings using a Settings object. ```python from c2pa import Settings, Context settings = Settings() settings.set("builder.thumbnail.enabled", "false") settings.set("verify.verify_after_sign", "true") settings.update({ "builder": { "claim_generator_info": {"name": "An app", "version": "0.1.0"} } }) ctx = Context(settings) ``` -------------------------------- ### Load Settings from JSON File Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Load C2PA SDK settings from a JSON file into a Settings object, then use it to initialize a Context. ```python import json with open("config/settings.json", "r") as f: settings = Settings.from_json(f.read()) ctx = Context(settings) ``` -------------------------------- ### Sign a file with C2PA manifest Source: https://context7.com/contentauth/c2pa-python/llms.txt Use Builder to add resources and sign a file with a C2PA manifest. Requires a signer callback, context settings, and manifest definition. ```python ctx_settings = Settings.from_dict({"builder": {"thumbnail": {"enabled": True, "long_edge": 512}}}) with Context(ctx_settings) as ctx: with Signer.from_callback(es256_sign, C2paSigningAlg.ES256, certs.decode("utf-8"), "http://timestamp.digicert.com") as signer: with Builder(manifest_def, ctx) as builder: with open("tests/fixtures/A_thumbnail.jpg", "rb") as thumb: builder.add_resource("thumbnail", thumb) builder.sign_file("tests/fixtures/A.jpg", "output/protected.jpg", signer) print("Signed successfully -> output/protected.jpg") ``` -------------------------------- ### Merge multiple configurations with ContextBuilder Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Demonstrates merging multiple configurations by updating a Settings object before passing it to ContextBuilder. This ensures all desired settings are applied to the Context. ```python settings = Settings.from_dict({"builder": {"thumbnail": {"enabled": False}}}) settings.update({"verify": {"remote_manifest_fetch": True}}) ctx = Context.builder().with_settings(settings).build() ``` -------------------------------- ### Initialize C2pa Context Source: https://context7.com/contentauth/c2pa-python/llms.txt Demonstrates various ways to initialize the C2pa Context object, including from settings, JSON/dictionaries, and using a fluent builder pattern. ```python from c2pa import Context, Settings # From Settings object settings = Settings.from_dict({"verify": {"remote_manifest_fetch": False}}) ctx = Context(settings) # From JSON / dict ctx = Context.from_json('{"builder": {"thumbnail": {"enabled": false}}}') ctx = Context.from_dict({"builder": {"thumbnail": {"enabled": False}}}) ``` ```python from c2pa import Context, Settings, Signer, Builder # Fluent builder pattern settings = Settings.from_dict({"verify": {"remote_manifest_fetch": False}}) signer = None # Assume signer is initialized elsewhere ctx = ( Context.builder() .with_settings(settings) .with_signer(signer) # signer is consumed; do not use signer directly after this .build() ) ``` -------------------------------- ### Build Manifest with Selected Ingredients Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Constructs a new manifest by selecting specific ingredients from an existing manifest store. Use this when you need to create a subset of a manifest with only the essential components. ```python ctx = Context.from_dict({ "builder": { "thumbnail": {"enabled": False}, "claim_generator_info": {"name": "an-application", "version": "0.1.0"} }, "signer": signer, }) archive_stream.seek(0) with Reader("application/c2pa", archive_stream, context=ctx) as reader: manifest_store = json.loads(reader.json()) active = manifest_store["manifests"][manifest_store["active_manifest"]] selected = [ ing for ing in active["ingredients"] if ing["title"] in {"photo_1.jpg", "logo.png"} ] with Builder({ "claim_generator_info": [{"name": "an-application", "version": "0.1.0"}], "ingredients": selected, }, context=ctx) as new_builder: transfer_ingredient_resources(reader, new_builder, selected) with open("source.jpg", "rb") as source, open("output.jpg", "wb") as dest: # In this example, the Signer is on the context. # A Signer can also be passed as first argument to # configure a dedicated Signer explicitly. new_builder.sign("image/jpeg", source, dest) ``` -------------------------------- ### Minimal C2PA Context Configuration Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Sets up a basic context with claim generator information and intent. Useful for simple C2PA generation tasks. ```python ctx = Context.from_dict({ "builder": { "claim_generator_info": {"name": "My app", "version": "0.1"}, "intent": {"Create": "digitalCapture"} } }) ``` -------------------------------- ### Migrate from load_settings to Context API Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Use `Context.from_dict` to create a context and pass it to the `Reader` for isolated configuration. This replaces the global state management of `load_settings`. ```python from c2pa import load_settings, Reader load_settings({"builder": {"thumbnail": {"enabled": False}}}) reader = Reader("image.jpg") # uses global settings ``` ```python from c2pa import Settings, Context, Reader ctx = Context.from_dict({"builder": {"thumbnail": {"enabled": False}}}) reader = Reader("image.jpg", context=ctx) ``` -------------------------------- ### Generate API reference documentation Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Generate the API reference documentation using Sphinx. This can be done via the Makefile or by directly running the script. ```bash make -C docs ``` ```bash python3 scripts/generate_api_docs.py ``` -------------------------------- ### Create and configure Context for C2PA operations Source: https://github.com/contentauth/c2pa-python/blob/main/docs/usage.md Instantiate a Context object, optionally passing Settings and a Signer. The Context carries configuration to Reader or Builder instances. It can be created from default settings, custom settings, JSON, or dictionaries. ```python from c2pa import Context, Settings ctx = Context() # SDK defaults ctx = Context(settings) ctx = Context.from_json('{"builder": {"thumbnail": {"enabled": false}}}') ctx = Context.from_dict({"builder": {"thumbnail": {"enabled": False}}}) reader = Reader("path/to/media_file.jpg", context=ctx) builder = Builder(manifest_json, ctx) ``` -------------------------------- ### Verify wheel builds Source: https://github.com/contentauth/c2pa-python/blob/main/docs/project-contributions.md Perform verification checks on the built wheel packages. ```bash make verify-wheel-build ``` -------------------------------- ### Signer.from_info() with PEM Certificate and Key Source: https://context7.com/contentauth/c2pa-python/llms.txt Initializes a Signer object using direct PEM-encoded certificate and private key. Requires `cryptography` library. The TSA URL is optional. ```python import os from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, padding from cryptography.hazmat.backends import default_backend import c2pa from c2pa import Signer, C2paSigningAlg, C2paSignerInfo # --- from_info(): direct PEM certificate + private key --- with open("tests/fixtures/es256_certs.pem", "rb") as f: certs = f.read() with open("tests/fixtures/es256_private.key", "rb") as f: key = f.read() signer_info = C2paSignerInfo( alg=C2paSigningAlg.ES256, # or b"es256" / "es256" sign_cert=certs, # PEM bytes private_key=key, # PEM bytes ta_url=b"http://timestamp.digicert.com" # RFC 3161 TSA URL ) signer = Signer.from_info(signer_info) print("Reserve size:", signer.reserve_size(), "bytes") signer.close() ``` -------------------------------- ### Settings Source: https://context7.com/contentauth/c2pa-python/llms.txt Encapsulates all SDK configuration options using a JSON-based schema. Methods are chainable and `Settings` is passed to `Context` to propagate configuration. ```APIDOC ## `Settings` — Per-instance SDK configuration `Settings` encapsulates all SDK configuration options — verification behavior, trust anchors, thumbnail generation, action tracking, and builder behavior — using a JSON-based schema. Methods are chainable. `Settings` is passed to `Context`, which then propagates the configuration to `Reader` and `Builder`. ```python from c2pa import Settings, Context # Create with defaults, then mutate settings = Settings() settings.set("builder.thumbnail.enabled", "false") # dot-notation; value must be a string settings.set("verify.verify_after_sign", "true") settings.update({"verify": {"remote_manifest_fetch": False}}) # merge dict # Create from JSON string settings2 = Settings.from_json('{"builder": {"thumbnail": {"enabled": false, "long_edge": 512}}}') # Create from dict (recommended for programmatic config) settings3 = Settings.from_dict({ "verify": { "verify_after_reading": True, "verify_trust": True, "ocsp_fetch": False, "remote_manifest_fetch": False }, "builder": { "claim_generator_info": {"name": "My App", "version": "1.0.0"}, "thumbnail": {"enabled": True, "long_edge": 1024, "quality": "medium"} }, "trust": { "trust_anchors": open("trust-anchors.pem").read() } }) ctx = Context(settings3) ``` ``` -------------------------------- ### Select Ingredient by Instance ID Source: https://github.com/contentauth/c2pa-python/blob/main/docs/selective-manifests.md Retrieves ingredients from a manifest by their `instance_id`. This allows for precise selection of archived ingredients. ```python archive.seek(0) reader = Reader("application/c2pa", archive) manifest_data = json.loads(reader.json()) active = manifest_data["active_manifest"] ingredients = manifest_data["manifests"][active]["ingredients"] for ing in ingredients: if ing.get("instance_id") == "catalog:photo-A": # Do something with the found ingredient... pass ``` -------------------------------- ### Two-Phase Workflow: Prepare Manifest Source: https://github.com/contentauth/c2pa-python/blob/main/docs/working-stores.md Phase 1 of the two-phase workflow. Prepares the manifest on a Builder and archives it for later reuse. Ensure the `claim_generator_info` is set in the context. ```python import io import json ctx = Context.from_dict({"builder": {"claim_generator_info": {"name": "my-app", "version": "0.1.0"}}}) manifest_json = json.dumps({ "title": "Artwork draft", "assertions": [] }) builder = Builder(manifest_json, context=ctx) with open("thumb.jpg", "rb") as thumb: builder.add_resource("thumbnail", thumb) with open("sketch.png", "rb") as sketch: builder.add_ingredient( json.dumps({"title": "Sketch"}), "image/png", sketch ) with open("artwork_manifest.c2pa", "wb") as f: builder.to_archive(f) print("Working store saved to artwork_manifest.c2pa") ``` -------------------------------- ### Context and Archives with Builder Source: https://github.com/contentauth/c2pa-python/blob/main/docs/context-settings.md Explains how to use archives with the Builder, differentiating between `from_archive` and `with_archive` methods concerning context preservation. ```APIDOC ## Context and archives Archives (`.c2pa` files) store only the manifest definition. They do **not** store settings or context. ### Builder.from_archive(stream) Creates a context-free builder. All settings revert to SDK defaults regardless of what context the original builder had. ### Builder({}, ctx).with_archive(stream) Creates a builder with a context first, then loads the archived manifest definition into it. The context settings are preserved. Use `with_archive()` when your workflow depends on specific settings (thumbnails, claim generator, intent, and so on). Use `from_archive()` only for quick prototyping where SDK defaults are acceptable. ### Request Example ```python from c2pa import Builder, Context ctx = Context.from_dict({ "builder": { "thumbnail": {"enabled": False}, "claim_generator_info": {"name": "My App", "version": "0.1.0"} } }) with open("manifest.c2pa", "rb") as archive: builder = Builder({}, context=ctx) builder.with_archive(archive) # builder now has the archived definition + context settings ``` ```