Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/cute-coins-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@contentauth/c2pa-wasm': patch
'@contentauth/c2pa-web': patch
---

Add Builder method to add ingredient json only
14 changes: 13 additions & 1 deletion packages/c2pa-wasm/src/wasm_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use std::io::Cursor;

use c2pa::{assertions::Action, Builder, BuilderIntent};
use c2pa::{assertions::Action, Builder, BuilderIntent, Ingredient};
use js_sys::{Error as JsError, JsString, Uint8Array};
use serde::{Deserialize, Serialize};
use serde_wasm_bindgen::Serializer;
Expand Down Expand Up @@ -119,6 +119,18 @@ impl WasmBuilder {
Ok(())
}

/// Add an ingredient to the manifest from a JSON ingredient definition without a blob
///
/// # Arguments
/// * `ingredient_json` - A JSON string representing the ingredient.
#[wasm_bindgen(js_name = addIngredient)]
pub fn add_ingredient(&mut self, json: &str) -> Result<(), JsError> {
let ingredient = Ingredient::from_json(json).map_err(WasmError::from)?;
self.builder.add_ingredient(ingredient);

Ok(())
}

/// Add an ingredient to the manifest from a JSON ingredient definition and a [`Blob`].
///
/// # Arguments
Expand Down
60 changes: 59 additions & 1 deletion packages/c2pa-web/src/lib/builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import { test, describe, expect } from 'test/methods.js';
import { ManifestDefinition } from '@contentauth/c2pa-types';
import { ManifestDefinition, Ingredient } from '@contentauth/c2pa-types';

describe('builder', () => {
describe('creation', () => {
Expand Down Expand Up @@ -122,6 +122,64 @@ describe('builder', () => {
});
});
});

describe('addIngredient', () => {
test('should add the provided ingredient', async ({ c2pa }) => {
const builder = await c2pa.builder.new();

const ingredient: Ingredient = {
title: 'source-image.jpg',
format: 'image/jpeg',
instance_id: 'ingredient-instance-123',
document_id: 'ingredient-doc-456',
};

await builder.addIngredient(ingredient);

const definition = await builder.getDefinition();

expect(definition.ingredients).toHaveLength(1);
expect(definition.ingredients[0]).toMatchObject({
title: 'source-image.jpg',
format: 'image/jpeg',
instance_id: 'ingredient-instance-123',
document_id: 'ingredient-doc-456',
});
});

test('should add multiple ingredients', async ({ c2pa }) => {
const builder = await c2pa.builder.new();

const ingredient1: Ingredient = {
title: 'source-image-1.jpg',
format: 'image/jpeg',
instance_id: 'ingredient-instance-1',
};

const ingredient2: Ingredient = {
title: 'source-image-2.jpg',
format: 'image/png',
instance_id: 'ingredient-instance-2',
};

await builder.addIngredient(ingredient1);
await builder.addIngredient(ingredient2);

const definition = await builder.getDefinition();

expect(definition.ingredients).toHaveLength(2);
expect(definition.ingredients[0]).toMatchObject({
title: 'source-image-1.jpg',
format: 'image/jpeg',
instance_id: 'ingredient-instance-1',
});
expect(definition.ingredients[1]).toMatchObject({
title: 'source-image-2.jpg',
format: 'image/png',
instance_id: 'ingredient-instance-2',
});
});
});
});
});
});
12 changes: 12 additions & 0 deletions packages/c2pa-web/src/lib/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@ export interface Builder {
*/
setThumbnailFromBlob: (format: string, blob: Blob) => Promise<void>;

/**
* Add an ingredient to the builder from a definition only.
*
* @param ingredientDefinition Ingredient definition.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you replace Ingredient with {@link Ingredient} here? That will allow typedoc to resolve this to the ingredient type and create an interactive link on the docs site.

*/
addIngredient: (ingredientDefinition: Ingredient) => Promise<void>;

/**
* Add an ingredient to the builder from a definition, format, and blob.
* Values specified in the ingredient definition will be merged with the ingredient, and these values take precendence.
Expand Down Expand Up @@ -231,6 +238,11 @@ function createBuilder(
await tx.builder_setThumbnailFromBlob(id, format, blob);
},

async addIngredient(ingredientDefinition: Ingredient) {
const json = JSON.stringify(ingredientDefinition);
await tx.builder_addIngredient(id, json);
},

async addIngredientFromBlob(
ingredientDefinition: Ingredient,
format: string,
Expand Down
4 changes: 4 additions & 0 deletions packages/c2pa-web/src/lib/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ rx({
const builder = builderMap.get(builderId);
builder.setThumbnailFromBlob(format, blob);
},
builder_addIngredient(builderId, json) {
const builder = builderMap.get(builderId);
builder.addIngredient(json);
},
builder_addIngredientFromBlob(builderId, json, format, blob) {
const builder = builderMap.get(builderId);
builder.addIngredientFromBlob(json, format, blob);
Expand Down
4 changes: 4 additions & 0 deletions packages/c2pa-web/src/lib/worker/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ const { createTx, rx } = channel<{
format: string,
blob: Blob
) => void;
builder_addIngredient: (
builderId: number,
json: string
) => void;
builder_addIngredientFromBlob: (
builderId: number,
json: string,
Expand Down