From bfd76c4615f5f3ba2c7d661808616c557fc1c9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milio=20Gonzalez?= Date: Tue, 30 Dec 2025 18:02:09 -0500 Subject: [PATCH 1/4] Expose `load_settings()` and `version()` for import to allow specifying custom settings (like a certificate trust list). --- src/c2pa/__init__.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/c2pa/__init__.py b/src/c2pa/__init__.py index c2a89d73..2edc4a3e 100644 --- a/src/c2pa/__init__.py +++ b/src/c2pa/__init__.py @@ -12,8 +12,8 @@ # each license. try: - from importlib.metadata import version - __version__ = version("c2pa-python") + from importlib.metadata import version as get_version + __version__ = get_version("c2pa-python") except ImportError: # pragma: no cover __version__ = "unknown" @@ -26,7 +26,9 @@ Signer, Stream, sdk_version, - read_ingredient_file + read_ingredient_file, + load_settings, + version ) # NOQA # Re-export C2paError and its subclasses @@ -39,5 +41,7 @@ 'Signer', 'Stream', 'sdk_version', - 'read_ingredient_file' + 'read_ingredient_file', + 'load_settings', + 'version' ] From 832ebc3713f0b9bcc22347b706af026f4321bd98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milio=20Gonzalez?= Date: Tue, 30 Dec 2025 18:03:28 -0500 Subject: [PATCH 2/4] Add an example read.py script to show how to read a file's C2PA manifest and verify it. --- README.md | 1 + examples/read.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 examples/read.py diff --git a/README.md b/README.md index d33472ee..c03f7553 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ import c2pa See the [`examples` directory](https://github.com/contentauth/c2pa-python/tree/main/examples) for some helpful examples: +- `examples/read.py` shows how to read and verify an asset with a C2PA manifest. - `examples/sign.py` shows how to sign and verify an asset with a C2PA manifest. - `examples/training.py` demonstrates how to add a "Do Not Train" assertion to an asset and verify it. diff --git a/examples/read.py b/examples/read.py new file mode 100644 index 00000000..f88ae263 --- /dev/null +++ b/examples/read.py @@ -0,0 +1,43 @@ +import sys +import c2pa +import urllib.request + + +# This example shows how to read a C2PA manifest embedded in a media file, and validate +# that it is trusted according to the official trust anchor certificate list. +# The output is printed as prettified JSON. + +TRUST_ANCHORS_URL = "https://contentcredentials.org/trust/anchors.pem" + + +def load_trust_anchors(): + try: + with urllib.request.urlopen(TRUST_ANCHORS_URL) as response: + anchors = response.read().decode('utf-8') + settings = { + "verify": { + "verify_cert_anchors": True + }, + "trust": { + "trust_anchors": anchors + } + } + c2pa.load_settings(settings) + except Exception as e: + print(f"Warning: Could not load trust anchors from {TRUST_ANCHORS_URL}: {e}") + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print(f"Usage: python {sys.argv[0]} ") + sys.exit(1) + + load_trust_anchors() + + image_path = sys.argv[1] + try: + with c2pa.Reader(image_path) as reader: + print(reader.detailed_json()) + except Exception as e: + print(f"Error reading C2PA data from {image_path}: {e}") + sys.exit(1) From 2e10912a41235c883c8caa6ad00ab06b9b26e829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milio=20Gonzalez?= Date: Sun, 4 Jan 2026 15:22:38 -0500 Subject: [PATCH 3/4] Address PR comments --- examples/README.md | 8 +++++++- examples/read.py | 24 ++++++++++++++---------- src/c2pa/__init__.py | 3 ++- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/examples/README.md b/examples/README.md index ce8003b9..983fc6a8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -75,7 +75,13 @@ except Exception as err: To run the examples, make sure you have the c2pa-python package installed (`pip install c2pa-python`) and you're in the root directory of the project. We recommend working using virtual environments (venv). Then run the examples as shown below. -Run the "do not train" assertion example: +### Run the reading C2PA data example + +```bash +python examples/read.py +``` + +### Run the "do not train" assertion example: ```bash python examples/training.py diff --git a/examples/read.py b/examples/read.py index f88ae263..ea30126b 100644 --- a/examples/read.py +++ b/examples/read.py @@ -27,17 +27,21 @@ def load_trust_anchors(): print(f"Warning: Could not load trust anchors from {TRUST_ANCHORS_URL}: {e}") -if __name__ == '__main__': - if len(sys.argv) < 2: - print(f"Usage: python {sys.argv[0]} ") - sys.exit(1) - - load_trust_anchors() - - image_path = sys.argv[1] +def read_c2pa_data(media_path: str): + print(f"Reading {media_path}") try: - with c2pa.Reader(image_path) as reader: + with c2pa.Reader(media_path) as reader: print(reader.detailed_json()) except Exception as e: - print(f"Error reading C2PA data from {image_path}: {e}") + print(f"Error reading C2PA data from {media_path}: {e}") sys.exit(1) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + media_path = "tests/fixtures/cloud.jpg" + else: + media_path = sys.argv[1] + + load_trust_anchors() + read_c2pa_data(media_path) diff --git a/src/c2pa/__init__.py b/src/c2pa/__init__.py index 2edc4a3e..6eefeb40 100644 --- a/src/c2pa/__init__.py +++ b/src/c2pa/__init__.py @@ -32,6 +32,7 @@ ) # NOQA # Re-export C2paError and its subclasses + __all__ = [ 'Builder', 'C2paError', @@ -41,7 +42,7 @@ 'Signer', 'Stream', 'sdk_version', + 'version', 'read_ingredient_file', 'load_settings', - 'version' ] From fb0d06acaa14a21d649b4664bae348a55a2a52b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milio=20Gonzalez?= Date: Fri, 9 Jan 2026 22:05:06 -0500 Subject: [PATCH 4/4] Remove __init__.py changes --- src/c2pa/__init__.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/c2pa/__init__.py b/src/c2pa/__init__.py index 6eefeb40..c2a89d73 100644 --- a/src/c2pa/__init__.py +++ b/src/c2pa/__init__.py @@ -12,8 +12,8 @@ # each license. try: - from importlib.metadata import version as get_version - __version__ = get_version("c2pa-python") + from importlib.metadata import version + __version__ = version("c2pa-python") except ImportError: # pragma: no cover __version__ = "unknown" @@ -26,13 +26,10 @@ Signer, Stream, sdk_version, - read_ingredient_file, - load_settings, - version + read_ingredient_file ) # NOQA # Re-export C2paError and its subclasses - __all__ = [ 'Builder', 'C2paError', @@ -42,7 +39,5 @@ 'Signer', 'Stream', 'sdk_version', - 'version', - 'read_ingredient_file', - 'load_settings', + 'read_ingredient_file' ]