Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions sdk/examples/c2pa.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ action = "c2pa.edited"
# The source type field is required for the c2pa.created action.
#
# For more information, see `c2pa::assertions::actions::source_type`.
source_type = "http://c2pa.org/digitalsourcetype/empty"
source_type = "empty"
# Description for the action
description = "Some edit action."
# Arbitrary key/value pairs to store in the action.
Expand Down Expand Up @@ -122,7 +122,7 @@ enabled = true
# The source type field is required for the c2pa.created action.
#
# For more information, see `c2pa::assertions::actions::source_type`.
source_type = "http://c2pa.org/digitalsourcetype/empty"
source_type = "empty"

# Settings for configuring how c2pa.opened actions are auto created.
#
Expand All @@ -134,7 +134,7 @@ enabled = true
# For more information, see `c2pa::assertions::actions::source_type`.
#
# Note this field is optional for the c2pa.opened action.
source_type = "http://c2pa.org/digitalsourcetype/empty"
source_type = "empty"

# Settings for configuring how c2pa.placed actions are auto created.
#
Expand All @@ -146,7 +146,7 @@ enabled = true
# For more information, see `c2pa::assertions::actions::source_type`.
#
# Note this field is optional for the c2pa.placed action.
source_type = "http://c2pa.org/digitalsourcetype/empty"
source_type = "empty"

# Settings for automatic thumbnail generation.
[builder.thumbnail]
Expand Down
203 changes: 180 additions & 23 deletions sdk/src/assertions/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// specific language governing permissions and limitations under
// each license.

use std::collections::HashMap;
use std::{collections::HashMap, fmt};

use log::error;
use serde::{Deserialize, Serialize};
Expand All @@ -29,19 +29,176 @@ use crate::{
const ASSERTION_CREATION_VERSION: usize = 2;
pub const CAI_INGREDIENT_IDS: &str = "org.cai.ingredientIds";

// TODO: make enum
/// Constants indicating from which source a digital image was created.
///
/// These constants are used in conjunction with [`Actions::source_type`].
#[allow(unused)]
pub(crate) mod source_type {
/// Media whose digital content is effectively empty, such as a blank canvas or zero-length video.
pub const EMPTY: &str = "http://c2pa.org/digitalsourcetype/empty";
/// Data that is the result of algorithmically using a model derived from sampled content and data.
/// Differs from <http://cv.iptc.org/newscodes/digitalsourcetype/>trainedAlgorithmicMedia in that
/// the result isn’t a media type (e.g., image or video) but is a data format (e.g., CSV, pickle).
pub const TRAINED_ALGORITHMIC_DATA: &str =
"http://c2pa.org/digitalsourcetype/trainedAlgorithmicData";
// TODO: this is needed to supress clippy deprecated field warning: https://github.com/serde-rs/serde/pull/2879
pub use digital_source_type::DigitalSourceType;
mod digital_source_type {
#![allow(deprecated)]

#[cfg(feature = "json_schema")]
use schemars::JsonSchema;

use super::*;

/// Description of the source of an asset.
///
/// The full list of possible digital source types are found below:
/// <https://spec.c2pa.org/specifications/specifications/2.2/specs/C2PA_Specification.html#_digital_source_type>
/// <https://cv.iptc.org/newscodes/digitalsourcetype>
#[non_exhaustive]
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "json_schema", derive(JsonSchema))]
pub enum DigitalSourceType {
/// Media whose digital content is effectively empty, such as a blank canvas or zero-length video.
#[serde(alias = "empty", rename = "http://c2pa.org/digitalsourcetype/empty")]
Empty,
/// Data that is the result of algorithmically using a model derived from sampled content and data.
/// Differs from <http://cv.iptc.org/newscodes/digitalsourcetype/>trainedAlgorithmicMedia in that
/// the result isn’t a media type (e.g., image or video) but is a data format (e.g., CSV, pickle).
#[serde(
alias = "trainedAlgorithmicData",
rename = "http://c2pa.org/digitalsourcetype/trainedAlgorithmicData"
)]
TrainedAlgorithmicData,
/// The media was captured from a real-life source using a digital camera or digital recording device.
#[serde(
alias = "digitalCapture",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture"
)]
DigitalCapture,
/// The media is the result of capturing multiple frames from a real-life source using a digital camera
/// or digital recording device, then automatically merging them into a single frame using digital signal
/// processing techniques and/or non-generative AI. Includes High Dynamic Range (HDR) processing common in
/// smartphone camera apps.
#[serde(
alias = "computationalCapture",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/computationalCapture"
)]
ComputationalCapture,
/// The media was digitised from a negative on film or other transparent medium.
#[serde(
alias = "negativeFilm",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/negativeFilm"
)]
NegativeFilm,
/// The media was digitised from a positive on a transparency or other transparent medium.
#[serde(
alias = "positiveFilm",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/positiveFilm"
)]
PositiveFilm,
/// The media was digitised from a non-transparent medium such as a photographic print.
#[serde(
alias = "print",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/print"
)]
Print,
/// Minor augmentation or correction by a human, such as a digitally-retouched photo used in a magazine.
#[deprecated]
#[serde(
alias = "minorHumanEdits",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/minorHumanEdits"
)]
MinorHumanEdits,
/// Augmentation, correction or enhancement by one or more humans using non-generative tools.
#[serde(
alias = "humanEdits",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/humanEdits"
)]
HumanEdits,
/// Augmentation, correction or enhancement using a Generative AI model, such as with inpainting or
/// outpainting operations.
#[serde(
alias = "compositeWithTrainedAlgorithmicMedia",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/compositeWithTrainedAlgorithmicMedia"
)]
CompositeWithTrainedAlgorithmicMedia,
/// Modification or correction by algorithm without changing the main content of the media, initiated
/// or configured by a human, such as sharpening or applying noise reduction.
#[serde(
alias = "algorithmicallyEnhanced",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/algorithmicallyEnhanced"
)]
AlgorithmicallyEnhanced,
/// The digital image was created by computer software.
#[deprecated]
#[serde(
alias = "softwareImage",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/softwareImage"
)]
SoftwareImage,
/// Media created by a human using digital tools.
#[deprecated]
#[serde(
alias = "digitalArt",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/digitalArt"
)]
DigitalArt,
/// Media created by a human using non-generative tools.
#[serde(
alias = "digitalCreation",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCreation"
)]
DigitalCreation,
/// Digital media representation of data via human programming or creativity.
#[serde(
alias = "dataDrivenMedia",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/dataDrivenMedia"
)]
DataDrivenMedia,
/// Digital media created algorithmically using an Artificial Intelligence model trained on captured
/// content.
#[serde(
alias = "trainedAlgorithmicMedia",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia"
)]
TrainedAlgorithmicMedia,
/// Media created purely by an algorithm not based on any sampled training data, e.g. an image created
/// by software using a mathematical formula.
#[serde(
alias = "algorithmicMedia",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/algorithmicMedia"
)]
AlgorithmicMedia,
/// A capture of the contents of the screen of a computer or mobile device.
#[serde(
alias = "screenCapture",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/screenCapture"
)]
ScreenCapture,
/// Live recording of virtual event based on Generative AI and/or captured elements.
#[serde(
alias = "virtualRecording",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/virtualRecording"
)]
VirtualRecording,
/// Mix or composite of several elements, any of which may or may not be generative AI.
#[serde(
alias = "composite",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/composite"
)]
Composite,
/// Mix or composite of several elements that are all captures of real life.
#[serde(
alias = "compositeCapture",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/compositeCapture"
)]
CompositeCapture,
/// Mix or composite of several elements, at least one of which is Generative AI.
#[serde(
alias = "compositeSynthetic",
rename = "http://cv.iptc.org/newscodes/digitalsourcetype/compositeSynthetic"
)]
CompositeSynthetic,
/// An unknown digital source type.
#[serde(untagged)]
Other(String),
}

impl fmt::Display for DigitalSourceType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.serialize(f)
}
}
}

/// C2PA actions defined in the C2PA specification.
Expand Down Expand Up @@ -188,7 +345,7 @@ pub struct Action {

/// One of the defined URI values at `<https://cv.iptc.org/newscodes/digitalsourcetype/>`
#[serde(rename = "digitalSourceType", skip_serializing_if = "Option::is_none")]
pub(crate) source_type: Option<String>,
pub(crate) source_type: Option<DigitalSourceType>,

/// List of related actions.
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -281,8 +438,8 @@ impl Action {

/// Returns a digitalSourceType as defined at <https://cv.iptc.org/newscodes/digitalsourcetype/>.
// QUESTION: Keep in docs?
pub fn source_type(&self) -> Option<&str> {
self.source_type.as_deref()
pub fn source_type(&self) -> Option<&DigitalSourceType> {
self.source_type.as_ref()
}

/// Returns the list of related actions.
Expand Down Expand Up @@ -418,8 +575,8 @@ impl Action {
}

/// Set a digitalSourceType URI as defined at <https://cv.iptc.org/newscodes/digitalsourcetype/>.
pub fn set_source_type<S: Into<String>>(mut self, uri: S) -> Self {
self.source_type = Some(uri.into());
pub fn set_source_type<T: Into<DigitalSourceType>>(mut self, source_type: T) -> Self {
self.source_type = Some(source_type.into());
self
}

Expand Down Expand Up @@ -503,7 +660,7 @@ impl Action {
}
}

#[derive(Deserialize, Serialize, Debug, Clone, Default, PartialEq, Eq)]
#[derive(Deserialize, Serialize, Debug, Clone, Default, PartialEq)]
#[non_exhaustive]
pub struct ActionTemplate {
/// The label associated with this action. See ([`c2pa_action`]).
Expand All @@ -519,7 +676,7 @@ pub struct ActionTemplate {

/// One of the defined URI values at `<https://cv.iptc.org/newscodes/digitalsourcetype/>`
#[serde(rename = "digitalSourceType", skip_serializing_if = "Option::is_none")]
pub source_type: Option<String>,
pub source_type: Option<DigitalSourceType>,

#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<UriOrResource>,
Expand Down Expand Up @@ -756,7 +913,7 @@ pub mod tests {
.set_parameter("name".to_owned(), "gaussian blur")
.unwrap()
.set_when("2015-06-26T16:43:23+0200")
.set_source_type("digsrctype:algorithmicMedia")
.set_source_type(DigitalSourceType::AlgorithmicMedia)
.add_change(RegionOfInterest {
region: vec![Range {
range_type: RangeType::Temporal,
Expand Down Expand Up @@ -797,7 +954,7 @@ pub mod tests {
assert_eq!(result.actions[1].when(), original.actions[1].when());
assert_eq!(
result.actions[1].source_type().unwrap(),
"digsrctype:algorithmicMedia"
&DigitalSourceType::AlgorithmicMedia
);
assert_eq!(result.actions[1].changes(), original.actions()[1].changes());
assert_eq!(
Expand Down
4 changes: 1 addition & 3 deletions sdk/src/assertions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
//! Assertion helpers to build, validate, and parse assertions.

mod actions;
#[allow(unused)]
pub(crate) use actions::source_type;
pub(crate) use actions::V2_DEPRECATED_ACTIONS;
pub use actions::{c2pa_action, Action, ActionTemplate, Actions, SoftwareAgent};
pub use actions::{c2pa_action, Action, ActionTemplate, Actions, DigitalSourceType, SoftwareAgent};

mod asset_reference;
pub use asset_reference::AssetReference;
Expand Down
Loading
Loading