Getting resources from a manifest
Manifest data can include binary resources such as thumbnail and icon images which are referenced by JUMBF URIs in manifest data.
- Rust
- C++
- Python
- Node.js
The example below shows how to get resources from manifest data using the Rust library.
Use Reader::from_context to read a manifest and then use resource_to_stream to extract binary resources such as thumbnails:
use c2pa::{Context, Reader, Result};
use std::{fs::File, io::Cursor};
fn main() -> Result<()> {
let context = Context::new();
let stream = File::open("path/to/file.jpg")?;
let reader = Reader::from_context(context)
.with_stream("image/jpeg", stream)?;
if let Some(manifest) = reader.active_manifest() {
if let Some(thumbnail_ref) = manifest.thumbnail_ref() {
let mut thumbnail = Cursor::new(Vec::new());
reader.resource_to_stream(&thumbnail_ref.identifier, &mut thumbnail)?;
println!(
"wrote thumbnail {} of size {}",
thumbnail_ref.format,
thumbnail.get_ref().len()
);
}
}
Ok(())
}
This is how to get resources from a manifest using C++.
#include <iostream>
#include <fstream>
#include <string>
#include "c2pa.hpp"
#include <nlohmann/json.hpp>
// this example uses nlohmann json for parsing the manifest
using json = nlohmann::json;
using namespace std;
namespace fs = std::filesystem;
using namespace c2pa;
int main()
{
fs::path output_path = current_dir / "../target/example/training.jpg";
fs::path thumbnail_path = current_dir / "../target/example/thumbnail.jpg";
try
{
c2pa::Context context;
auto reader = Reader(context, output_path);
auto manifest_store_json = reader.json();
cout << "The new manifest is " << manifest_store_json << endl;
// get the active manifest
json manifest_store = json::parse(manifest_store_json);
if (manifest_store.contains("active_manifest"))
{
string active_manifest = manifest_store["active_manifest"];
json &manifest = manifest_store["manifests"][active_manifest];
string identifier = manifest["thumbnail"]["identifier"];
std::ofstream ofs(thumbnail_path, std::ios::binary);
reader.get_resource(identifier, ofs);
cout << "thumbnail written to " << thumbnail_path << endl;
}
}
catch (c2pa::C2paException const &e)
{
cout << "C2PA Error: " << e.what() << endl;
}
}
The example below shows how to get resources from manifest data using the Python library.
To retrieve binary resources such as thumbnails from the manifest data, use the resource_to_stream method with the associated identifier field value as the URI.
import json
from c2pa import Context, Reader
try:
with Context() as ctx:
with Reader("path/to/media_file.jpg", context=ctx) as reader:
manifest_store = json.loads(reader.json())
active_manifest_label = manifest_store.get("active_manifest")
if active_manifest_label:
manifest = manifest_store["manifests"][active_manifest_label]
# Get the URI to the manifest's thumbnail and write it to a file.
uri = manifest["thumbnail"]["identifier"]
with open("thumbnail_v2.jpg", "w+b") as thumb_file:
reader.resource_to_stream(uri, thumb_file)
except Exception as err:
print(err)
Binary resources (thumbnails, icons, linked manifest blobs) are referenced by URI strings in the active manifest. Use Reader.resourceToAsset to copy a resource to a file path or to a buffer.
Write a resource to a file
import { Reader } from '@contentauth/c2pa-node';
import path from 'node:path';
async function writeThumbnail(
assetPath: string,
outputPath: string,
): Promise<void> {
const reader = await Reader.fromAsset({ path: assetPath });
if (!reader) {
throw new Error('No C2PA manifest found for this asset.');
}
const manifest = reader.getActive();
const uri = manifest?.thumbnail?.identifier;
if (!uri) {
throw new Error('Active manifest has no thumbnail.');
}
await reader.resourceToAsset(uri, { path: path.resolve(outputPath) });
}
Read a resource into a buffer
Pass a destination object with buffer: null. The implementation fills buffer after the call.
import { Reader } from '@contentauth/c2pa-node';
async function readResourceToBuffer(
assetPath: string,
uri: string,
): Promise<Buffer> {
const reader = await Reader.fromAsset({ path: assetPath });
if (!reader) {
throw new Error('No C2PA manifest found.');
}
const dest: { buffer: Buffer | null } = { buffer: null };
await reader.resourceToAsset(uri, dest);
if (!dest.buffer) {
throw new Error('Resource could not be read.');
}
return dest.buffer;
}
Discover URIs from JSON
You can inspect reader.json() for the full manifest store, or use getActive() for the active manifest only. Ingredient thumbnails use the same identifier pattern as the claim thumbnail.
import { Reader } from '@contentauth/c2pa-node';
const reader = await Reader.fromAsset({ path: 'signed.jpg' });
if (!reader) {
process.exit(0);
}
const store = reader.json();
console.log(JSON.stringify(store, null, 2));
const active = reader.getActive();
for (const ing of active?.ingredients ?? []) {
if (ing.thumbnail?.identifier) {
console.log('Ingredient thumbnail URI:', ing.thumbnail.identifier);
}
}