4949 'c2pa_builder_set_remote_url' ,
5050 'c2pa_builder_add_resource' ,
5151 'c2pa_builder_add_ingredient_from_stream' ,
52+ 'c2pa_builder_add_action' ,
5253 'c2pa_builder_to_archive' ,
5354 'c2pa_builder_sign' ,
5455 'c2pa_manifest_bytes_free' ,
@@ -403,6 +404,9 @@ def _setup_function(func, argtypes, restype=None):
403404 ctypes .c_char_p ,
404405 ctypes .POINTER (C2paStream )],
405406 ctypes .c_int )
407+ _setup_function (_lib .c2pa_builder_add_action ,
408+ [ctypes .POINTER (C2paBuilder ), ctypes .c_char_p ],
409+ ctypes .c_int )
406410_setup_function (_lib .c2pa_builder_to_archive ,
407411 [ctypes .POINTER (C2paBuilder ), ctypes .POINTER (C2paStream )],
408412 ctypes .c_int )
@@ -667,20 +671,44 @@ def version() -> str:
667671 return _convert_to_py_string (result )
668672
669673
674+ @overload
670675def load_settings (settings : str , format : str = "json" ) -> None :
671- """Load C2PA settings from a string.
676+ ...
677+
678+
679+ @overload
680+ def load_settings (settings : dict ) -> None :
681+ ...
682+
683+
684+ def load_settings (settings : Union [str , dict ], format : str = "json" ) -> None :
685+ """Load C2PA settings from a string or dict.
672686
673687 Args:
674- settings: The settings string to load
675- format: The format of the settings string (default: "json")
688+ settings: The settings string or dict to load
689+ format: The format of the settings string (default: "json").
690+ Ignored when settings is a dict.
676691
677692 Raises:
678693 C2paError: If there was an error loading the settings
679694 """
680- result = _lib .c2pa_load_settings (
681- settings .encode ('utf-8' ),
682- format .encode ('utf-8' )
683- )
695+ # Convert to JSON string as necessary
696+ try :
697+ if isinstance (settings , dict ):
698+ settings_str = json .dumps (settings )
699+ format = "json"
700+ else :
701+ settings_str = settings
702+ except (TypeError , ValueError ) as e :
703+ raise C2paError (f"Failed to serialize settings to JSON: { e } " )
704+
705+ try :
706+ settings_bytes = settings_str .encode ('utf-8' )
707+ format_bytes = format .encode ('utf-8' )
708+ except (AttributeError , UnicodeEncodeError ) as e :
709+ raise C2paError (f"Failed to encode settings to UTF-8: { e } " )
710+
711+ result = _lib .c2pa_load_settings (settings_bytes , format_bytes )
684712 if result != 0 :
685713 error = _parse_operation_result_for_error (_lib .c2pa_error ())
686714 if error :
@@ -2198,6 +2226,7 @@ class Builder:
21982226 'url_error' : "Error setting remote URL: {}" ,
21992227 'resource_error' : "Error adding resource: {}" ,
22002228 'ingredient_error' : "Error adding ingredient: {}" ,
2229+ 'action_error' : "Error adding action: {}" ,
22012230 'archive_error' : "Error writing archive: {}" ,
22022231 'sign_error' : "Error during signing: {}" ,
22032232 'encoding_error' : "Invalid UTF-8 characters in manifest: {}" ,
@@ -2495,13 +2524,16 @@ def add_resource(self, uri: str, stream: Any):
24952524 )
24962525 )
24972526
2498- def add_ingredient (self , ingredient_json : str , format : str , source : Any ):
2527+ def add_ingredient (
2528+ self , ingredient_json : Union [str , dict ], format : str , source : Any
2529+ ):
24992530 """Add an ingredient to the builder (facade method).
25002531 The added ingredient's source should be a stream-like object
25012532 (for instance, a file opened as stream).
25022533
25032534 Args:
25042535 ingredient_json: The JSON ingredient definition
2536+ (either a JSON string or a dictionary)
25052537 format: The MIME type or extension of the ingredient
25062538 source: The stream containing the ingredient data
25072539 (any Python stream-like object)
@@ -2521,14 +2553,15 @@ def add_ingredient(self, ingredient_json: str, format: str, source: Any):
25212553
25222554 def add_ingredient_from_stream (
25232555 self ,
2524- ingredient_json : str ,
2556+ ingredient_json : Union [ str , dict ] ,
25252557 format : str ,
25262558 source : Any ):
25272559 """Add an ingredient from a stream to the builder.
25282560 Explicitly named API requiring a stream as input parameter.
25292561
25302562 Args:
25312563 ingredient_json: The JSON ingredient definition
2564+ (either a JSON string or a dictionary)
25322565 format: The MIME type or extension of the ingredient
25332566 source: The stream containing the ingredient data
25342567 (any Python stream-like object)
@@ -2540,6 +2573,9 @@ def add_ingredient_from_stream(
25402573 """
25412574 self ._ensure_valid_state ()
25422575
2576+ if isinstance (ingredient_json , dict ):
2577+ ingredient_json = json .dumps (ingredient_json )
2578+
25432579 try :
25442580 ingredient_str = ingredient_json .encode ('utf-8' )
25452581 format_str = format .encode ('utf-8' )
@@ -2570,7 +2606,7 @@ def add_ingredient_from_stream(
25702606
25712607 def add_ingredient_from_file_path (
25722608 self ,
2573- ingredient_json : str ,
2609+ ingredient_json : Union [ str , dict ] ,
25742610 format : str ,
25752611 filepath : Union [str , Path ]):
25762612 """Add an ingredient from a file path to the builder (deprecated).
@@ -2582,6 +2618,7 @@ def add_ingredient_from_file_path(
25822618
25832619 Args:
25842620 ingredient_json: The JSON ingredient definition
2621+ (either a JSON string or a dictionary)
25852622 format: The MIME type or extension of the ingredient
25862623 filepath: The path to the file containing the ingredient data
25872624 (can be a string or Path object)
@@ -2613,6 +2650,42 @@ def add_ingredient_from_file_path(
26132650 except Exception as e :
26142651 raise C2paError .Other (f"Could not add ingredient: { e } " ) from e
26152652
2653+ def add_action (self , action_json : Union [str , dict ]) -> None :
2654+ """Add an action to the builder, that will be placed
2655+ in the actions assertion array in the generated manifest.
2656+
2657+ Args:
2658+ action_json: The JSON action definition
2659+ (either a JSON string or a dictionary)
2660+
2661+ Raises:
2662+ C2paError: If there was an error adding the action
2663+ C2paError.Encoding: If the action JSON contains invalid UTF-8 chars
2664+ """
2665+ self ._ensure_valid_state ()
2666+
2667+ if isinstance (action_json , dict ):
2668+ action_json = json .dumps (action_json )
2669+
2670+ try :
2671+ action_str = action_json .encode ('utf-8' )
2672+ except UnicodeError as e :
2673+ raise C2paError .Encoding (
2674+ Builder ._ERROR_MESSAGES ['encoding_error' ].format (str (e ))
2675+ )
2676+
2677+ result = _lib .c2pa_builder_add_action (self ._builder , action_str )
2678+
2679+ if result != 0 :
2680+ error = _parse_operation_result_for_error (_lib .c2pa_error ())
2681+ if error :
2682+ raise C2paError (error )
2683+ raise C2paError (
2684+ Builder ._ERROR_MESSAGES ['action_error' ].format (
2685+ "Unknown error"
2686+ )
2687+ )
2688+
26162689 def to_archive (self , stream : Any ) -> None :
26172690 """Write an archive of the builder to a stream.
26182691
0 commit comments