Skip to content
Merged
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
# Generated files
.docusaurus
.cache-loader

# External files loaded by fetch-readmes script
/docs/js-sdk/api
/docs/js-sdk/examples/quickstart/*.ts
/docs/js-sdk/examples/view-manifest/*.ts
Expand All @@ -23,6 +25,7 @@
/docs/rust-sdk/*.md
/docs/rust-sdk/docs/*.md
/docs/**/readme.md
/static/sb-alg-list.json

# Misc
.DS_Store
Expand Down
19 changes: 19 additions & 0 deletions docs/soft-bindings.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
id: sb-algs
title: Watermarking and fingerprinting algorithms
hide_table_of_contents: true
---

[_Durable Content Credentials_](https://contentauthenticity.org/blog/durable-content-credentials) is a concept that helps content provenance to persist across content platforms by also using one or both:

- **Undetectable watermarks**, actively inserted into the content
- **Content fingerprinting**, passively computed from the content.

Platforms might remove C2PA metadata if they don't yet support the standard or if they use automated process to, for example, provide multiple resolutions of an image which they then serve over the Web. By storing a copy of the metadata in an online database, you can use a watermark or a fingerprint to find it again.

Choose a reason for hiding this comment

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

Suggested change
Platforms might remove C2PA metadata if they don't yet support the standard or if they use automated process to, for example, provide multiple resolutions of an image which they then serve over the Web. By storing a copy of the metadata in an online database, you can use a watermark or a fingerprint to find it again.
Platforms might remove C2PA Manifests if they are using software that does not yet support the standard. By storing a copy of the C2PA Manifest in an online database, you can use a watermark or a fingerprint to find it again.

Combining both watermark and fingerprints further improves the robustness of the provenance information.

In the C2PA specification, watermarks and content fingerprinting are known as [soft bindings](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_soft_bindings), which can be used to find digital content, even if the underlying bits differ. The C2PA specification requires that soft bindings be generated using one of the [algorithms](https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_soft_binding_algorithm_list) approved by the C2PA Technical Working Group. The following table lists the algorithms from the [C2PA Soft Binding Algorithm List](https://github.com/c2pa-org/softbinding-algorithm-list).

import JSONToTable from '@site/src/components/JSONToTable';

<JSONToTable />
5 changes: 5 additions & 0 deletions scripts/fetch-readme.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ const readmes = [
repo: 'contentauth/c2pa-min',
path: 'README.md',
},
{
dest: resolve(__dirname, '../static/sb-alg-list.json'),
repo: 'c2pa-org/softbinding-algorithm-list',
path: 'softbinding-algorithm-list.json',
},
];

function resolveMarkdownLinks(linkBase, content) {
Expand Down
13 changes: 11 additions & 2 deletions sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,17 @@ const sidebars = {
id: 'faqs',
},
{
type: 'doc',
id: 'community-resources',
type: 'category',
label: 'Community resources',
link: { type: 'doc', id: 'community-resources' },
collapsed: true,
items: [
{
type: 'doc',
label: 'Watermarking and fingerprinting',
id: 'sb-algs',
},
],
},
{
type: 'doc',
Expand Down
130 changes: 130 additions & 0 deletions src/components/JSONToTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import React, { useState, useEffect } from 'react';

// Define the fields to display and their custom headers
const DISPLAY_FIELDS = {
alg: 'Algorithm Name',
decodedMediaTypes: 'Media Types',
'entryMetadata.informationalUrl': 'URL',
'entryMetadata.contact': 'Contact',
};

// Helper function to safely extract nested values and flatten arrays
const getNestedValue = (obj, path) => {
const value = path
.split('.')
.reduce(
(acc, key) => (acc && acc[key] !== undefined ? acc[key] : 'N/A'),
obj,
);
return Array.isArray(value) ? value.join(', ') : value; // Flatten arrays into a comma-separated string
};

// Function to extract and filter only the required fields
const extractAndFilterObject = (obj) => {
let result = {};
for (const key in DISPLAY_FIELDS) {
result[key] = getNestedValue(obj, key);
}
return result;
};

// Helper function to capitalize each word in a string
const capitalizeWords = (str) => {
return str
.split(' ')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
};

const JSONToTable = () => {
const [jsonData, setJsonData] = useState(null);
const [error, setError] = useState(null);

useEffect(() => {
fetch('/sb-alg-list.json')
.then((response) => {
if (!response.ok) {
throw new Error('Failed to fetch the JSON file');
}
return response.json();
})
.then((data) => {
setJsonData(data);
setError(null);
})
.catch((err) => {
setError(err.message);
setJsonData(null);
});
}, []);

// Function to group data by the 'type' field
const groupDataByType = (data) => {
return data.reduce((acc, item) => {
const type = getNestedValue(item, 'type');
if (!acc[type]) acc[type] = [];
acc[type].push(item);
return acc;
}, {});
};

const generateTableHeaders = () => {
return Object.keys(DISPLAY_FIELDS).map((key) => (
<th key={key}>{DISPLAY_FIELDS[key]}</th>
));
};

const generateTableRows = (data) => {
return data.map((item, rowIndex) => {
const filteredData = extractAndFilterObject(item);
const url = filteredData['entryMetadata.informationalUrl'];
const description = getNestedValue(item, 'entryMetadata.description');

return (
<tr key={rowIndex}>
{Object.keys(DISPLAY_FIELDS).map((key, index) => (
<td key={index}>
{key === 'entryMetadata.informationalUrl' ? (
url !== 'N/A' && description !== 'N/A' ? (
<a href={url} target="_blank" rel="noopener noreferrer">
{description}
</a>
) : (
'N/A'
)
) : (
filteredData[key]
)}
</td>
))}
</tr>
);
});
};

if (error) return <p style={{ color: 'red' }}>{error}</p>;

if (!jsonData || !Array.isArray(jsonData)) {
return <p>No data found in the JSON. Expected an array of objects.</p>;
}

const groupedData = groupDataByType(jsonData);

return (
<div>
{Object.entries(groupedData).map(([type, data]) => (
<div key={type} style={{ marginBottom: '30px' }}>
<h2>{capitalizeWords(type)} algorithms</h2>
<table style={{ borderCollapse: 'collapse' }}>
<thead>
<tr>{generateTableHeaders()}</tr>
</thead>
<tbody>{generateTableRows(data)}</tbody>
</table>
</div>
))}
</div>
);
};

export default JSONToTable;
158 changes: 158 additions & 0 deletions static/sb-alg-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
[
{
"identifier": 1,
"alg": "com.digimarc.validate.1",
"type": "watermark",
"decodedMediaTypes": ["audio", "video", "text", "image"],
"entryMetadata": {
"description": "Digimarc Validate Digital Watermarking algorithm",
"dateEntered": "2024-05-17T17:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://www.digimarc.com/products/digital-content-authentication"
}
},
{
"identifier": 2,
"alg": "org.atsc.a336",
"type": "watermark",
"decodedMediaTypes": ["audio", "video", "image"],
"entryMetadata": {
"description": "ATSC watermarking (A/334, A/335, A/336)",
"dateEntered": "2024-05-17T15:43:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://www.atsc.org/atsc-documents/a3362017-content-recovery-redistribution-scenarios/"
}
},
{
"identifier": 3,
"alg": "io.iscc.v0",
"type": "fingerprint",
"decodedMediaTypes": ["text", "image", "audio", "video", "application"],
"entryMetadata": {
"description": "ISO 24138 - International Standard Content Code (ISCC) V0 algorithm",
"dateEntered": "2024-05-17T16:00:00Z",
"contact": "[email protected]",
"informationalUrl": "https://www.iso.org/standard/77899.html"
}
},
{
"identifier": 4,
"alg": "com.adobe.trustmark.Q",
"type": "watermark",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Adobe Trustmark variant Q",
"dateEntered": "2024-05-17T17:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://github.com/adobe/trustmark/"
}
},
{
"identifier": 5,
"alg": "com.adobe.trustmark.C",
"type": "watermark",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Adobe Trustmark variant C",
"dateEntered": "2024-05-17T17:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://github.com/adobe/trustmark/"
}
},
{
"identifier": 6,
"alg": "com.adobe.icn.dense",
"type": "fingerprint",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Adobe Image Comparator Network Dense Fingerprint",
"dateEntered": "2024-05-17T17:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://openaccess.thecvf.com/content/CVPR2021W/WMF/html/Black_Deep_Image_Comparator_Learning_To_Visualize_Editorial_Change_CVPRW_2021_paper.html"
}
},
{
"identifier": 7,
"alg": "ai.steg.api",
"type": "watermark",
"decodedMediaTypes": ["image", "video", "application"],
"entryMetadata": {
"description": "Steg.AI invisible watermarking",
"dateEntered": "2024-05-20T10:50:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://openaccess.thecvf.com/content_CVPR_2019/papers/Wengrowski_Light_Field_Messaging_With_Deep_Photographic_Steganography_CVPR_2019_paper.pdf"
}
},
{
"identifier": 8,
"alg": "ai.trufo.gen1.image",
"type": "watermark",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Trufo image watermark.",
"dateEntered": "2024-08-14T15:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://trufo.ai/publications/"
}
},
{
"identifier": 9,
"alg": "ai.trufo.gen1.image-lite",
"type": "watermark",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Trufo image watermark (lite version).",
"dateEntered": "2024-08-14T15:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://trufo.ai/publications/"
}
},
{
"identifier": 10,
"alg": "app.overlai.watermark.1",
"type": "watermark",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Overlai Watermark version 1",
"dateEntered": "2024-08-14T16:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://overlai.app/watermark"
}
},
{
"identifier": 11,
"alg": "tv.kinetiq.watercast.48.1",
"type": "watermark",
"decodedMediaTypes": ["video"],
"entryMetadata": {
"description": "Teletrax Watermarking algorithm",
"dateEntered": "2024-10-16T17:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://kinetiq.tv/broadcasting-syndication/"
}
},
{
"identifier": 12,
"alg": "castLabs.watermark.1",
"type": "watermark",
"decodedMediaTypes": ["video"],
"entryMetadata": {
"description": "castLabs Single Frame Forensic Watermarking",
"dateEntered": "2024-11-13T12:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://castlabs.com/image-watermarking/"
}
},
{
"identifier": 13,
"alg": "com.adobe.trustmark.P",
"type": "watermark",
"decodedMediaTypes": ["image"],
"entryMetadata": {
"description": "Adobe Trustmark variant P",
"dateEntered": "2025-02-05T17:00:00.000Z",
"contact": "[email protected]",
"informationalUrl": "https://github.com/adobe/trustmark/"
}
}
]
Loading