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.
- JavaScript
 - Python
 - Node.js
 - C++
 - Rust
 
That JavaScript library is being extensively revised so the APIs used here may change in the near future.
The example below shows how to get resources from manifest data using the JavaScript library.
const version = '0.27.1';
const sampleImage = 'my_image.jpg'
import { createC2pa, selectProducer } from 'c2pa';
import wasmSrc from 'c2pa/dist/assets/wasm/toolkit_bg.wasm?url';
import workerSrc from 'c2pa/dist/c2pa.worker.js?url';
import { parseISO } from 'date-fns';
import { createC2pa } from 'https://cdn.jsdelivr.net/npm/c2pa@${version}/+esm';
(async () => {
  // Initialize the c2pa-js SDK
  const c2pa = await createC2pa({
    wasmSrc:
      'https://cdn.jsdelivr.net/npm/c2pa@${version}/dist/assets/wasm/toolkit_bg.wasm',
    workerSrc:
      'https://cdn.jsdelivr.net/npm/c2pa@${version}/dist/c2pa.worker.min.js',
  });
  
  let output: string[] = [];
  const c2pa = await createC2pa({
    wasmSrc,
    workerSrc,
  });
  const { manifestStore, source } = await c2pa.read(sampleImage);
  const activeManifest = manifestStore?.activeManifest;
  if (activeManifest) {
    // Get thumbnail
    // Note: You would normally call `dispose()` when working with a
    // component-based UI library (e.g. on component un-mount)
    // @ts-expect-error noUnusedLocals
    const { url, dispose } = source.thumbnail.getUrl();
    // Get properties
    const properties: Record<string, string | undefined> = {
      title: activeManifest.title,
      format: activeManifest.format,
      claimGenerator: activeManifest.claimGenerator.split('(')[0]?.trim(),
      producer: selectProducer(activeManifest)?.name ?? 'Unknown',
      thumbnail: `<img src="${url}" class="thumbnail" />`,
      ingredients: (activeManifest.ingredients ?? [])
        .map((i) => i.title)
        .join(', '),
      signatureIssuer: activeManifest.signatureInfo?.issuer,
      signatureDate: activeManifest.signatureInfo?.time
        ? parseISO(activeManifest.signatureInfo.time).toString()
        : 'No date available',
    };
    output = Object.keys(properties).map((key) => {
      return `
        <tr>
          <td>${key}</td>
          <td>${properties[key]}</td>
        </tr>
      `;
    });
  } else {
    output.push(`
      <tr>
        <td colspan="2">No provenance data found</td>
      </tr>
    `);
  }
  document.querySelector('#results tbody')!.innerHTML = output.join('');
  
})();
With an HTML page like this:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="../../favicon.svg" />
    <link rel="stylesheet" href="../../styles.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>active-manifest</title>
  </head>
  <body>
    <table id="results">
      <thead>
        <th>Property</th>
        <th>Value</th>
      </thead>
      <tbody>
        <td colspan="3">Loading…</td>
      </tbody>
    </table>
    <script type="module" src="./main.ts"></script>
  </body>
</html>
The example below shows how to get resources from manifest data using the Python library.
Retrieve binary resources such as thumbnails from the manifest data, use the resource_to_stream or resource_to_file methods using the associated identifier field values and a uri.
NOTE: Need to add example of using reader.resource_to_stream().
# Import the C2PA Python package.
from c2pa import *
# Import standard general-purpose packages.
import os
import io
import logging
import json
try:
  # Create a reader from a file path.
  reader = c2pa.Reader.from_file("path/to/media_file.jpg")
  # Get the active manifest.
  manifest = reader.get_active_manifest()
  if manifest != None:
    # get the uri to the manifest's thumbnail and write it to a file.
    uri = manifest["thumbnail"]["identifier"]
    reader.resource_to_file(uri, "thumbnail_v2.jpg") 
except Exception as err:
    print(err)
The Node.js library is being revised. The documentation will be updated as soon as possible with the latest changes.
This is how to get resources from a manifest using C++.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdexcept>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include "c2pa.hpp"
#include "test_signer.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;
string read_text_file(const fs::path &path)
{
    ifstream file(path);
    if (!file.is_open())
    {
        throw runtime_error("Could not open file " + string(path));
    }
    string contents((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
    file.close();
    return contents.data();
}
int main()
{
  fs::path manifest_path = current_dir / "../tests/fixtures/training.json";
  //fs::path certs_path = current_dir / "../tests/fixtures/es256_certs.pem";
  //fs::path image_path = current_dir / "../tests/fixtures/A.jpg";
  fs::path output_path = current_dir / "../target/example/training.jpg";
  fs::path thumbnail_path = current_dir / "../target/example/thumbnail.jpg";
  try
      {
          // read the new manifest and display the JSON
          auto reader = Reader(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 identifer = manifest["thumbnail"]["identifier"];
              reader.get_resource(identifer, thumbnail_path);
              cout << "thumbnail written to" << thumbnail_path << endl;
          }
      }
      
      catch (c2pa::Exception const &e)
      {
          cout << "C2PA Error: " << e.what() << endl;
      }
      catch (runtime_error const &e)
      {
          cout << "setup error" << e.what() << endl;
      }
      catch (json::parse_error const &e)
      {
          cout << "parse error " << e.what() << endl;
      }
}
The example below shows how to get resources from manifest data using the Rust library.
NOTE: Need to clarify if/how these two code examples work together.
This is from resource_to_stream API doc:
use c2pa::Reader;
#[cfg(feature = "file_io")]
{
    let stream = std::io::Cursor::new(Vec::new());
    let reader = Reader::from_file("path/to/file.jpg").unwrap();
    let manifest = reader.active_manifest().unwrap();
    let uri = &manifest.thumbnail_ref().unwrap().identifier;
    let bytes_written = reader.resource_to_stream(uri, stream).unwrap();
}
This is from c2pa-rs/examples/v2api.rs:
use std::io::{Cursor, Seek};
use anyhow::Result;
use c2pa::{
    crypto::raw_signature::SigningAlg, settings::Settings, validation_results::ValidationState,
    Builder, CallbackSigner, Reader,
};
use serde_json::json;
let reader = Reader::from_stream(format, &mut dest)?;
// extract a thumbnail image from the ManifestStore
let mut thumbnail = Cursor::new(Vec::new());
if let Some(manifest) = reader.active_manifest() {
    if let Some(thumbnail_ref) = manifest.thumbnail_ref() {
        reader.resource_to_stream(&thumbnail_ref.identifier, &mut thumbnail)?;
        println!(
            "wrote thumbnail {} of size {}",
            thumbnail_ref.format,
            thumbnail.get_ref().len()
        );
    }
}