c2pa-rs

A fork of https://github.com/contentauth/c2pa-rs/
git clone git://archive.git.mtrnord.blog/mtrnords-photography-manager/c2pa-rs.git
Log | Files | Refs | README

client.rs (5244B)


      1 // Copyright 2022 Adobe. All rights reserved.
      2 // This file is licensed to you under the Apache License,
      3 // Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
      4 // or the MIT license (http://opensource.org/licenses/MIT),
      5 // at your option.
      6 
      7 // Unless required by applicable law or agreed to in writing,
      8 // this software is distributed on an "AS IS" BASIS, WITHOUT
      9 // WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or
     10 // implied. See the LICENSE-MIT and LICENSE-APACHE files for the
     11 // specific language governing permissions and limitations under
     12 // each license.
     13 
     14 //! Example C2PA client application
     15 
     16 use std::path::PathBuf;
     17 
     18 use anyhow::Result;
     19 use c2pa::{
     20     assertions::{c2pa_action, labels, Action, Actions, CreativeWork, Exif, SchemaDotOrgPerson},
     21     create_signer, Ingredient, Manifest, Reader as ManifestStore, SigningAlg,
     22 };
     23 
     24 const GENERATOR: &str = "test_app/0.1";
     25 const INDENT_SPACE: usize = 2;
     26 
     27 // Example for reading the contents of a manifest store, recursively showing nested manifests
     28 fn show_manifest(manifest_store: &ManifestStore, manifest_label: &str, level: usize) -> Result<()> {
     29     let indent = " ".repeat(level * INDENT_SPACE);
     30 
     31     println!("{indent}manifest_label: {manifest_label}");
     32     if let Some(manifest) = manifest_store.get_manifest(manifest_label) {
     33         println!(
     34             "{}title: {} , format: {}, instance_id: {}",
     35             indent,
     36             manifest.title().unwrap_or_default(),
     37             manifest.format(),
     38             manifest.instance_id()
     39         );
     40 
     41         for assertion in manifest.assertions().iter() {
     42             println!("{}", assertion.label_with_instance());
     43             match assertion.label() {
     44                 labels::ACTIONS => {
     45                     let actions: Actions = assertion.to_assertion()?;
     46                     for action in actions.actions {
     47                         println!("{}{}", indent, action.action());
     48                     }
     49                 }
     50                 labels::CREATIVE_WORK => {
     51                     let creative_work: CreativeWork = assertion.to_assertion()?;
     52                     if let Some(authors) = creative_work.author() {
     53                         for author in authors {
     54                             if let Some(name) = author.name() {
     55                                 println!("{indent}author = {name} ");
     56                             }
     57                         }
     58                     }
     59                     if let Some(url) = creative_work.get::<String>("url") {
     60                         println!("{indent}url = {url} ");
     61                     }
     62                 }
     63                 _ => {}
     64             }
     65         }
     66 
     67         for ingredient in manifest.ingredients().iter() {
     68             println!("{}Ingredient title:{}", indent, ingredient.title());
     69             if let Some(label) = ingredient.active_manifest() {
     70                 show_manifest(manifest_store, label, level + 1)?;
     71             }
     72         }
     73     }
     74     Ok(())
     75 }
     76 
     77 pub fn main() -> Result<()> {
     78     let args: Vec<String> = std::env::args().collect();
     79     // allow passing in source and dest paths or use defaults
     80     let (src, dst) = match args.len() >= 3 {
     81         true => (args[1].as_str(), args[2].as_str()),
     82         false => (
     83             "sdk/tests/fixtures/earth_apollo17.jpg",
     84             "target/tmp/client.jpg",
     85         ),
     86     };
     87 
     88     let source = PathBuf::from(src);
     89     let dest = PathBuf::from(dst);
     90     // if a filepath was provided on the command line, read it as a parent file
     91     let parent = Ingredient::from_file(source.as_path())?;
     92 
     93     // create an action assertion stating that we imported this file
     94     let actions = Actions::new().add_action(
     95         Action::new(c2pa_action::PLACED)
     96             .set_parameter("identifier", parent.instance_id().to_owned())?,
     97     );
     98 
     99     // build a creative work assertion
    100     let creative_work =
    101         CreativeWork::new().add_author(SchemaDotOrgPerson::new().set_name("me")?)?;
    102 
    103     let exif = Exif::from_json_str(
    104         r#"{
    105         "@context" : {
    106           "exif": "http://ns.adobe.com/exif/1.0/"
    107         },
    108         "exif:GPSVersionID": "2.2.0.0",
    109         "exif:GPSLatitude": "39,21.102N",
    110         "exif:GPSLongitude": "74,26.5737W",
    111         "exif:GPSAltitudeRef": 0,
    112         "exif:GPSAltitude": "100963/29890",
    113         "exif:GPSTimeStamp": "2019-09-22T18:22:57Z"
    114     }"#,
    115     )?;
    116 
    117     // create a new Manifest
    118     let mut manifest = Manifest::new(GENERATOR.to_owned());
    119     // add parent and assertions
    120     manifest
    121         .set_parent(parent)?
    122         .add_assertion(&actions)?
    123         .add_assertion(&creative_work)?
    124         .add_assertion(&exif)?;
    125 
    126     // sign and embed into the target file
    127     let signcert_path = "sdk/tests/fixtures/certs/es256.pub";
    128     let pkey_path = "sdk/tests/fixtures/certs/es256.pem";
    129     let signer = create_signer::from_files(signcert_path, pkey_path, SigningAlg::Es256, None)?;
    130 
    131     manifest.embed(&source, &dest, &*signer)?;
    132 
    133     let manifest_store = ManifestStore::from_file(&dest)?;
    134 
    135     // example of how to print out the whole manifest as json
    136     println!("{manifest_store}\n");
    137 
    138     // walk through the manifest and access data.
    139 
    140     if let Some(manifest_label) = manifest_store.active_label() {
    141         show_manifest(&manifest_store, manifest_label, 0)?;
    142     }
    143 
    144     Ok(())
    145 }