(Windows users would swap out the single-straight quotes ' for double-straight quotes ")
I'll need to see if it is possible to script Photoshop or Bridge to add such metadata...
Of course, this depends on machine learning companies to support and honour such metadata entries excluding them from training their services on your data (yeah, I know).
This example Photoshop script will clear and add the AI/ML data mining "prohibited" metadata entry to an open document.
/*
Add IPTC PLUS Generative AI-ML Metadata to Open Doc.jsx
v1.0 - 19th August 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-ideas/add-support-for-iptc-plus-coalition-generative-ai-ml-training-metadata/idi-p/14808232
https://iptc.org/news/exclude-images-from-generative-ai-iptc-photo-metadata-standard-2023-1/
https://ns.useplus.org/LDF/ldf-XMPSpecification#DataMining
Example Controlled Vocabulary Entries:
https://ns.useplus.org/ldf/vocab/DMI-UNSPECIFIED
https://ns.useplus.org/ldf/vocab/DMI-ALLOWED
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-AIMLTRAINING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-GENAIMLTRAINING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED
*/
#target photoshop
if (app.documents.length) {
var contVocabEntry = "https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED";
if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
xmp.deleteProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining");
xmp.setProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining", contVocabEntry);
app.activeDocument.xmpMetadata.rawData = xmp.serialize();
} else {
alert("A document must be open to run this script!");
}
Here it is for selected files in Adobe Bridge:
/*
Add IPTC PLUS Generative AI-ML Metadata from Bridge Tools.jsx
v1.0 - 19th August 2024, Stephen Marsh
https://community.adobe.com/t5/photoshop-ecosystem-ideas/add-support-for-iptc-plus-coalition-generative-ai-ml-training-metadata/idi-p/14808232
https://ns.useplus.org/LDF/ldf-XMPSpecification#DataMining
https://iptc.org/news/exclude-images-from-generative-ai-iptc-photo-metadata-standard-2023-1/
Example Controlled Vocabulary Entries:
https://ns.useplus.org/ldf/vocab/DMI-UNSPECIFIED
https://ns.useplus.org/ldf/vocab/DMI-ALLOWED
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-AIMLTRAINING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-GENAIMLTRAINING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED
*/
#target bridge
addAIMLmeta = {};
addAIMLmeta.execute = function () {
var contVocabEntry = "https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED";
var sels = app.document.selections;
for (var i = 0; i < sels.length; i++) {
var md = sels[i].synchronousMetadata;
// Clear the metadata before writing?
md.namespace = "http://ns.useplus.org/ldf/xmp/1.0/";
md.DataMining = contVocabEntry;
}
}
if (BridgeTalk.appName == "bridge") {
var menu = MenuElement.create("command", "Add PLUS Generative AI-ML Metadata", "at the end of Tools");
menu.onSelect = addAIMLmeta.execute;
}
/*
Add IPTC PLUS Generative AI-ML Metadata to Open Doc scriptUI GUI.jsx
v1.0 - 26th September 2024, Stephen Marsh
v1.1 - 27th September 2024, Added a "None" option to remove data mining metadata
https://community.adobe.com/t5/photoshop-ecosystem-ideas/add-support-for-iptc-plus-coalition-generative-ai-ml-training-metadata/idi-p/14808232
https://iptc.org/news/exclude-images-from-generative-ai-iptc-photo-metadata-standard-2023-1/
https://ns.useplus.org/LDF/ldf-XMPSpecification#DataMining
Regional laws applying to an asset may prohibit, constrain, or allow data mining for certain purposes (such as search indexing or research), and may overrule the value selected for this property. Similarly, the absence of a prohibition does not indicate that the asset owner grants permission for data mining or any other use of an asset. The prohibition “Prohibited except for search engine indexing” only permits data mining by search engines available to the public to identify the URL for an asset and its associated data (for the purpose of assisting the public in navigating to the URL for the asset), and prohibits all other uses, such as AI/ML training.
*/
#target photoshop
if (app.documents.length) {
// Create the ScriptUI dialog
var dialog = new Window("dialog", "Add IPTC PLUS Data Mining Permission Metadata");
dialog.orientation = "column";
dialog.alignChildren = ["left", "top"];
dialog.spacing = 10;
dialog.margins = 16;
// Create the label and dropdown menu
dialog.add("statictext", undefined, "Data Mining Permission:");
var dropdown = dialog.add("dropdownlist", undefined, [
"Unspecified - no prohibition defined",
"Allowed",
"Prohibited for AI/ML training",
"Prohibited for Generative AI/ML training",
"Prohibited except for search engine indexing",
"Prohibited",
"None" // Remove data mining metadata
]);
dropdown.selection = 0;
// Array of corresponding values
var dropdownValues = [
"DMI-UNSPECIFIED",
"DMI-ALLOWED",
"DMI-PROHIBITED-AIMLTRAINING",
"DMI-PROHIBITED-GENAIMLTRAINING",
"DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING",
"DMI-PROHIBITED",
"" // "None"
];
// Create OK and Cancel buttons
var buttonGroup = dialog.add("group");
buttonGroup.orientation = "row";
buttonGroup.alignment = ["right", "top"];
var okButton = buttonGroup.add("button", undefined, "OK");
var cancelButton = buttonGroup.add("button", undefined, "Cancel");
// Show the dialog
if (dialog.show() == 1) {
var contVocabEntry = dropdownValues[dropdown.selection.index];
if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
if (contVocabEntry === "") {
xmp.deleteProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining");
} else {
xmp.setProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining", "https://ns.useplus.org/ldf/vocab/" + contVocabEntry);
}
app.activeDocument.xmpMetadata.rawData = xmp.serialize();
alert("Data Mining Permission set to: " + "\r" + dropdown.selection.text);
}
} else {
alert("A document must be open to run this script!");
}
Thanks David, that’s fantastic! I like the "NONE" option to remove said metadata. I don't script Bridge very often and a GUI is extra hard work for me as well, so thank you for contributing.
Yeah creating the GUI in every script is crazy, both Windows and Mac have built-in frameworks for building apps that don't require hand coding. I could completely remove the namespace instead of just making it blank but that takes a bit different approach and using XMPUTILS so I left it like this. I'm glad you posted this as I wasn't aware but I'm tagging all my images.
I could completely remove the namespace instead of just making it blank but that takes a bit different approach and using XMPUTILS so I left it like this.
I ironically used AI/ML to revise the Bridge script! :]
/*
Add IPTC PLUS Generative AI-ML Metadata from Bridge Tools scriptUI GUI.jsx
v1.0 - 19th August 2024, Stephen Marsh
Modified 26th September 2024 by David M. Converse - Added a scriptUI GUI and a "None" option
Modified 28th September 2024, by Stephen Marsh - Updated the code from David to completely remove the metadata without leaving any "debris" when "None" is selected
https://community.adobe.com/t5/photoshop-ecosystem-ideas/add-support-for-iptc-plus-coalition-generative-ai-ml-training-metadata/idi-p/14808232
https://iptc.org/news/exclude-images-from-generative-ai-iptc-photo-metadata-standard-2023-1/
https://ns.useplus.org/LDF/ldf-XMPSpecification#DataMining
Example Controlled Vocabulary Entries:
https://ns.useplus.org/ldf/vocab/DMI-UNSPECIFIED
https://ns.useplus.org/ldf/vocab/DMI-ALLOWED
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-AIMLTRAINING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-GENAIMLTRAINING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING
https://ns.useplus.org/ldf/vocab/DMI-PROHIBITED
*/
#target bridge
if (BridgeTalk.appName == 'bridge') {
var MLmenu = MenuElement.create('command', 'Add IPTC PLUS GenAI-ML Metadata Window', 'at the end of Tools');
}
try {
MLmenu.onSelect = function () {
if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); //load XMP Library
var plusPrefix = 'https://ns.useplus.org/ldf/vocab/'; //shared prefix
var contVocabEntry = ['DMI-UNSPECIFIED', 'DMI-ALLOWED', 'DMI-PROHIBITED-AIMLTRAINING', 'DMI-PROHIBITED-GENAIMLTRAINING', 'DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING', 'DMI-PROHIBITED'];
var ddlItem = contVocabEntry[0]; //initialize
var sels = app.document.selections;
var MLWindow = new Window('palette', '', undefined); //create window
var MLPanel = MLWindow.add('panel', undefined, 'PLUS Generative AL-ML Restrictions');
MLPanel.alignChildren = ['fill', 'top'];
MLPanel.margins = [10, 10, 10, 10];
MLPanel.ddl = MLPanel.add('dropdownlist', undefined, '');
MLPanel.ddl.preferredSize = [350, 25];
// Populate dropdown list
for (var i = 0; i < contVocabEntry.length; i++) {
MLPanel.ddl.add('item', contVocabEntry[i]);
}
MLPanel.ddl.add('item', 'NONE'); // Add 'None' option
MLPanel.ddl.selection = 0;
// Cancel and Process buttons
var MLGroup = MLWindow.add('group', undefined, '');
MLGroup.orientation = 'row';
MLGroup.alignChildren = ['fill', 'top'];
var cancelButton = MLGroup.add('button', undefined, 'Cancel');
cancelButton.preferredSize = [80, 25];
var processButton = MLGroup.add('button', undefined, 'Process');
processButton.preferredSize = [80, 25];
// Cancel button closes the window
cancelButton.onClick = function () {
MLWindow.close();
};
// Process button to update metadata
processButton.onClick = function () {
if (sels.length < 1) { // No selections
MLWindow.close();
return;
}
for (var j = 0; j < sels.length; j++) {
if (sels[j].hasMetadata && !sels[j].container) { // Not a folder
var md = sels[j].synchronousMetadata;
var xmp = new XMPMeta(md.serialize()); // Create XMPMeta from file metadata
// Remove existing DataMining metadata
XMPUtils.removeProperties(xmp, 'http://ns.useplus.org/ldf/xmp/1.0/', 'DataMining', XMPConst.REMOVE_ALL_PROPERTIES);
// If dropdown selection is not 'None', add the new metadata
if (MLPanel.ddl.selection.index != 6) { // 'None' is at index 6
var selectedValue = plusPrefix + contVocabEntry[MLPanel.ddl.selection.index];
xmp.setProperty('http://ns.useplus.org/ldf/xmp/1.0/', 'DataMining', selectedValue);
}
// Write the updated metadata back to the file
var updatedPacket = xmp.serialize(XMPConst.SERIALIZE_OMIT_PACKET_WRAPPER); // Serialize without extra wrapper
sels[j].metadata = new Metadata(updatedPacket); // Assign the new metadata back to the file
}
}
MLWindow.close(); // Close the window after processing
};
MLWindow.layout.layout(true);
MLWindow.show();
MLWindow.active = true;
};
}
catch (e) {
Window.alert(e + ' ' + e.line);
}
Minor updates to the Photoshop 1.2 version script:
/*
Add IPTC PLUS Generative AI-ML Metadata to Open Doc scriptUI GUI v1-2.jsx
v1.0 - 26th September 2024, Stephen Marsh
v1.1 - 27th September 2024, Added a "None" option to remove data mining metadata
v1.2 - 31st October 2024, Cosmetic Update to dropdown list text and default selection
https://community.adobe.com/t5/photoshop-ecosystem-ideas/add-support-for-iptc-plus-coalition-generative-ai-ml-training-metadata/idi-p/14808232
https://iptc.org/news/exclude-images-from-generative-ai-iptc-photo-metadata-standard-2023-1/
https://ns.useplus.org/LDF/ldf-XMPSpecification#DataMining
Regional laws applying to an asset may prohibit, constrain, or allow data mining for certain purposes (such as search indexing or research),and may overrule the value selected for this property. Similarly, the absence of a prohibition does not indicate that the asset owner grants permission for data mining or any other use of an asset. The prohibition “Prohibited except for search engine indexing” only permits data mining by search engines available to the public to identify the URL for an asset and its associated data (for the purpose of assisting the public in navigating to the URL for the asset), and prohibits all other uses, such as AI/ML training.
*/
#target photoshop
if (app.documents.length) {
// Create the ScriptUI dialog
var dialog = new Window("dialog", "Add IPTC PLUS Data Mining Permission Metadata (v1.2)");
dialog.orientation = "column";
dialog.alignChildren = ["left", "top"];
dialog.preferredSize.width = 450;
dialog.spacing = 10;
dialog.margins = 16;
// Create the label and dropdown menu
dialog.add("statictext", undefined, "Data Mining Permission:");
var dropdown = dialog.add("dropdownlist", undefined, [
"Unspecified - no prohibition defined",
"Allowed",
"Prohibited for AI/ML training",
"Prohibited for Generative AI/ML training",
"Prohibited except for search engine indexing",
"Prohibited",
"None (Remove existing metadata)" // Remove data mining metadata
]);
dropdown.selection = 4; // Prohibited except for search engine indexing
// Array of corresponding values
var dropdownValues = [
"DMI-UNSPECIFIED",
"DMI-ALLOWED",
"DMI-PROHIBITED-AIMLTRAINING",
"DMI-PROHIBITED-GENAIMLTRAINING",
"DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING",
"DMI-PROHIBITED",
"" // "None"
];
// Create OK and Cancel buttons
var buttonGroup = dialog.add("group");
buttonGroup.orientation = "row";
buttonGroup.alignment = ["right", "top"];
var cancelButton = buttonGroup.add("button", undefined, "Cancel");
var okButton = buttonGroup.add("button", undefined, "OK");
// Show the dialog
if (dialog.show() == 1) {
var contVocabEntry = dropdownValues[dropdown.selection.index];
if (ExternalObject.AdobeXMPScript === undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
var xmp = new XMPMeta(activeDocument.xmpMetadata.rawData);
if (contVocabEntry === "") {
xmp.deleteProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining");
} else {
xmp.setProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining", "https://ns.useplus.org/ldf/vocab/" + contVocabEntry);
}
app.activeDocument.xmpMetadata.rawData = xmp.serialize();
alert("Data Mining Permission set to: " + "\r" + dropdown.selection.text);
}
} else {
alert("A document must be open to run this script!");
}
I have updated the Photoshop script to a v2.0, now including batch processing:
* The interface defaults to "Single Document" mode on an open/active document.
* The interface defaults to "Batch Processing" mode if the script is run without any open documents. Select a root/top-level folder and optionally all sub-folders.
/*
Add IPTC PLUS Generative AI-ML Metadata scriptUI GUI v2.jsx
v1.0 - 26th September 2024, Stephen Marsh
v1.1 - 27th September 2024, Added a "None" option to remove data mining metadata
https://community.adobe.com/t5/photoshop-ecosystem-ideas/add-support-for-iptc-plus-coalition-generative-ai-ml-training-metadata/idi-p/14808232
https://iptc.org/news/exclude-images-from-generative-ai-iptc-photo-metadata-standard-2023-1/
https://ns.useplus.org/LDF/ldf-XMPSpecification#DataMining
Regional laws applying to an asset may prohibit, constrain, or allow data mining for certain purposes (such as search indexing or research), and may overrule the value selected for this property. Similarly, the absence of a prohibition does not indicate that the asset owner grants permission for data mining or any other use of an asset. The prohibition “Prohibited except for search engine indexing” only permits data mining by search engines available to the public to identify the URL for an asset and its associated data (for the purpose of assisting the public in navigating to the URL for the asset), and prohibits all other uses, such as AI/ML training.
*/
#target photoshop
// Create the ScriptUI dialog
var dialog = new Window("dialog", "Add IPTC PLUS Data Mining Permission Metadata (v2.0)");
dialog.orientation = "column";
dialog.alignChildren = ["fill", "top"];
dialog.preferredSize.width = 450;
dialog.spacing = 10;
dialog.margins = 16;
// Create panel for single document processing
var singlePanel = dialog.add("panel", undefined, "Single Document Processing Options");
singlePanel.orientation = "column";
singlePanel.alignChildren = ["fill", "top"];
singlePanel.margins = 16;
// Add "Data Mining Permission" label and dropdown to singlePanel
singlePanel.add("statictext", undefined, "Data Mining Permission:");
var singleDropdown = singlePanel.add("dropdownlist", undefined, [
"Unspecified - no prohibition defined",
"Allowed",
"Prohibited for AI/ML training",
"Prohibited for Generative AI/ML training",
"Prohibited except for search engine indexing",
"Prohibited",
"None (Remove existing metadata)"
]);
singleDropdown.selection = 4; // Default selection
// Array of corresponding values for metadata entries
var dropdownValues = [
"DMI-UNSPECIFIED",
"DMI-ALLOWED",
"DMI-PROHIBITED-AIMLTRAINING",
"DMI-PROHIBITED-GENAIMLTRAINING",
"DMI-PROHIBITED-EXCEPTSEARCHENGINEINDEXING",
"DMI-PROHIBITED",
""
];
// Create panel for batch processing
var batchPanel = dialog.add("panel", undefined, "Batch Processing Options");
batchPanel.orientation = "column";
batchPanel.alignChildren = ["fill", "top"];
batchPanel.margins = 16;
// Add "Data Mining Permission" label and dropdown to batchPanel
batchPanel.add("statictext", undefined, "Data Mining Permission:");
var batchDropdown = batchPanel.add("dropdownlist", undefined, [
"Unspecified - no prohibition defined",
"Allowed",
"Prohibited for AI/ML training",
"Prohibited for Generative AI/ML training",
"Prohibited except for search engine indexing",
"Prohibited",
"None (Remove existing metadata)"
]);
batchDropdown.selection = 4; // Default selection
// Folder selection for batch processing
batchPanel.add("statictext", undefined, "Select Folder:");
var browseGroup = batchPanel.add("group");
browseGroup.orientation = "row";
browseGroup.alignChildren = ["left", "center"];
browseGroup.spacing = 5;
var selectFolderButton = browseGroup.add("button", undefined, "Select Folder");
selectFolderButton.preferredSize.width = 80;
var folderPath = browseGroup.add("edittext");
folderPath.text = "No folder selected";
folderPath.enabled = false; // Read-only
folderPath.alignment = ["fill", "center"]; // Fill width
// Checkbox to include subfolders
var subFolderCheckbox = batchPanel.add("checkbox", undefined, "Include Subfolders");
// Set panel states based on open documents
if (app.documents.length === 0) {
batchPanel.enabled = true;
singlePanel.enabled = false;
} else {
batchPanel.enabled = false;
singlePanel.enabled = true;
}
// Select folder button functionality
selectFolderButton.onClick = function () {
var selectedFolder = Folder.selectDialog("Select the root folder for batch processing");
if (selectedFolder) folderPath.text = selectedFolder.fsName;
};
// Create Cancel and OK buttons
var buttonGroup = dialog.add("group");
buttonGroup.orientation = "row";
buttonGroup.alignment = ["right", "top"];
var cancelButton = buttonGroup.add("button", undefined, "Cancel");
var okButton = buttonGroup.add("button", undefined, "OK");
// Show the dialog
if (dialog.show() == 1) {
var contVocabEntry = (batchPanel.enabled ? dropdownValues[batchDropdown.selection.index] : dropdownValues[singleDropdown.selection.index]);
// Check if the AdobeXMPScript library is available
if (ExternalObject.AdobeXMPScript === undefined) {
try {
ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
} catch (e) {
alert("Unable to load AdobeXMPScript. Please ensure the library is available.");
dialog.close();
}
}
// Function to update XMP metadata for a given file without opening it
function updateXMP(filePath) {
var xmpFile = new XMPFile(filePath.fsName, XMPConst.FILE_JPEG, XMPConst.OPEN_FOR_UPDATE);
var xmp = xmpFile.getXMP();
if (contVocabEntry === "") {
xmp.deleteProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining");
} else {
xmp.setProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining", "https://ns.useplus.org/ldf/vocab/" + contVocabEntry);
}
if (xmpFile.canPutXMP(xmp)) {
xmpFile.putXMP(xmp);
}
xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
}
// Process the active document if batch processing is disabled
if (!batchPanel.enabled) {
var xmp = new XMPMeta(app.activeDocument.xmpMetadata.rawData);
if (contVocabEntry === "") {
xmp.deleteProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining");
} else {
xmp.setProperty("http://ns.useplus.org/ldf/xmp/1.0/", "DataMining", "https://ns.useplus.org/ldf/vocab/" + contVocabEntry);
}
app.activeDocument.xmpMetadata.rawData = xmp.serialize();
alert("Data Mining Permission set to: " + "\r" + singleDropdown.selection.text);
}
// Process files in the selected folder and subfolders if batch processing is enabled
else {
if (folderPath.text === "" || folderPath.text === "No folder selected") {
alert("Please select a folder for batch processing.");
} else {
var rootFolder = new Folder(folderPath.text);
// Recursive function to process files in folder and subfolders if selected
function processFolder(folder) {
var files = folder.getFiles();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (file instanceof Folder && subFolderCheckbox.value) {
processFolder(file); // Recurse into subfolders
} else if (file instanceof File && file.name.match(/\.(png|webp|jpg|jpeg|tif|tiff|psd|psb)$/i)) {
updateXMP(file); // Update metadata for valid image files
}
}
}
processFolder(rootFolder);
alert("Batch processing complete. Data Mining Permission set to: " + "\r" + batchDropdown.selection.text);
}
}
} else {
dialog.close();
}
I think the jury is out on that... It's an opt-in and honour system, and I don't believe that any of the AI players are following such flags, but it can't hurt. :]