commit 039ebf423fc6b587346e3155fb59cf57302715b9
parent 95ee921eab0faf17b0a8cd695ec32f91ebe37785
Author: Gavin Peacock <gpeacock@adobe.com>
Date: Tue, 12 Mar 2024 09:21:50 -0700
Adds a Manifest::composed manifest method (#424)
* Adds ComposableManifest support to c2pa_io
* Adds Manifest::composed_manifest()
Provides a way to pre-format a manifest store for injection into a given file format.
* Remove self from Store::get_composed_manifest
Diffstat:
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/sdk/src/asset_handlers/c2pa_io.rs b/sdk/src/asset_handlers/c2pa_io.rs
@@ -14,7 +14,9 @@
use std::{fs::File, path::Path};
use crate::{
- asset_io::{AssetIO, CAIRead, CAIReader, HashBlockObjectType, HashObjectPositions},
+ asset_io::{
+ AssetIO, CAIRead, CAIReader, ComposedManifestRef, HashBlockObjectType, HashObjectPositions,
+ },
error::{Error, Result},
};
@@ -90,6 +92,17 @@ impl AssetIO for C2paIO {
fn supported_types(&self) -> &[&str] {
&SUPPORTED_TYPES
}
+
+ fn composed_data_ref(&self) -> Option<&dyn ComposedManifestRef> {
+ Some(self)
+ }
+}
+
+impl ComposedManifestRef for C2paIO {
+ // Return entire CAI block as Vec<u8>
+ fn compose_manifest(&self, manifest_data: &[u8], _format: &str) -> Result<Vec<u8>> {
+ Ok(manifest_data.to_vec())
+ }
}
#[cfg(test)]
diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs
@@ -1242,10 +1242,17 @@ impl Manifest {
let mut store = self.to_store()?;
let mut cm = store.get_box_hashed_embeddable_manifest(signer)?;
if let Some(format) = format {
- cm = store.get_composed_manifest(&cm, format)?;
+ cm = Store::get_composed_manifest(&cm, format)?;
}
Ok(cm)
}
+
+ /// Formats a signed manifest for embedding in the given format
+ ///
+ /// For instance, this would return one or JPEG App11 segments containing the manifest
+ pub fn composed_manifest(manifest_bytes: &[u8], format: &str) -> Result<Vec<u8>> {
+ Store::get_composed_manifest(manifest_bytes, format)
+ }
}
impl std::fmt::Display for Manifest {
@@ -2388,12 +2395,15 @@ pub(crate) mod tests {
.data_hash_embeddable_manifest_remote(
&dh,
signer.as_ref(),
- "image/jpeg",
+ "c2pa", // force an uncomposed manifest - you could send this to the cloud
Some(&mut output_file),
)
.await
.unwrap();
+ // test composed manifest here to ensure it works
+ let signed_manifest =
+ Manifest::composed_manifest(&signed_manifest, "image/jpeg").expect("composed_manifest");
use std::io::{Seek, SeekFrom, Write};
// path in new composed manifest
diff --git a/sdk/src/store.rs b/sdk/src/store.rs
@@ -1795,7 +1795,7 @@ impl Store {
let jumbf_bytes = self.to_jumbf_internal(reserve_size)?;
- let composed = self.get_composed_manifest(&jumbf_bytes, format)?;
+ let composed = Self::get_composed_manifest(&jumbf_bytes, format)?;
Ok(composed)
}
@@ -1850,7 +1850,7 @@ impl Store {
patch_bytes(jumbf_bytes, sig_placeholder, sig).map_err(|_| Error::JumbfCreationError)?;
- self.get_composed_manifest(jumbf_bytes, format)
+ Self::get_composed_manifest(jumbf_bytes, format)
}
/// Returns a finalized, signed manifest. The manifest are only supported
@@ -2020,7 +2020,7 @@ impl Store {
/// Returns the supplied manifest composed to be directly compatible with the desired format.
/// For example, if format is JPEG function will return the set of APP11 segments that contains
/// the manifest. Similarly for PNG it would be the PNG chunk complete with header and CRC.
- pub fn get_composed_manifest(&self, manifest_bytes: &[u8], format: &str) -> Result<Vec<u8>> {
+ pub fn get_composed_manifest(manifest_bytes: &[u8], format: &str) -> Result<Vec<u8>> {
if let Some(h) = get_assetio_handler(format) {
if let Some(composed_data_handler) = h.composed_data_ref() {
return composed_data_handler.compose_manifest(manifest_bytes, format);
@@ -4874,7 +4874,7 @@ pub mod tests {
.unwrap();
// get composed version for embedding to JPEG
- let cm = store.get_composed_manifest(&em, "jpg").unwrap();
+ let cm = Store::get_composed_manifest(&em, "jpg").unwrap();
// insert manifest into output asset
let jpeg_io = get_assetio_handler_from_path(&ap).unwrap();
@@ -4955,7 +4955,7 @@ pub mod tests {
.unwrap();
// get composed version for embedding to JPEG
- let cm = store.get_composed_manifest(&em, "jpg").unwrap();
+ let cm = Store::get_composed_manifest(&em, "jpg").unwrap();
// insert manifest into output asset
let jpeg_io = get_assetio_handler_from_path(&ap).unwrap();