Skip to main content
Known Participant
October 31, 2008
Question

Can I automate the writing of XMP metadata into JPEG and TIFF files?

  • October 31, 2008
  • 91 replies
  • 11729 views
I have written an ASP.NET 3.5 website application on behalf of an annual international photographic competition. Entrants will be uploading digital photos in either JPEG or TIFF format. Ideally, I would write entrant identity and image title information into the XMP metadata for each image immediately after upload - but so far, I have failed to find any way to do this in ASP.NET.

Thousands of images are involved, so I need to find a way to automate the metadata insertion, perhaps with some sort of script that uses a text file (extracted from the SQL Server database on my website) as the source of the metadata for a batch of images. Is this the sort of task that can be done by writing a script for Bridge CS3? Are there any scripts already in existence that I could use? I am a total beginner in this area.

I use a Win XP PC, though I have a colleague who, I think, has CS3 on his Mac (running under the Leopard OS), so scripts for either platform might be usable.

David
This topic has been closed for replies.

91 replies

Known Participant
October 31, 2008
I've just tried your latest version of the script but, once again, it runs without any user feedback or file metadata updates. Do I need anything other than Bridge CS3 to run these scripts?
Paul Riggott
Inspiring
October 31, 2008
I am wondering if it isn't finding the file?
This will put up an alert if it can not find the document.



#target bridge

if( BridgeTalk.appName == "bridge" ) {

addInfo = new MenuElement("command", "Update Entry Details", "at the end of Thumbnail");

}

addInfo .onSelect = function () {

main();

}

function main(){

var csv = File.openDialog("Please select CSV file.","CSV File:*.csv");

if(csv != null){

loadXMPScript();

csv.open("r");

while(!csv.eof){

strInputLine = csv.readln();

if (strInputLine.length > 3) {

strInputLine = strInputLine.replace(/\\/g,'/');

inputArray = strInputLine.split(",");

var csvFile = new File(inputArray[0]);

var title = inputArray[1];

var author = inputArray[2];

/////////////////////////////////////////////////////////////////////////////////////////////////

if(!csvFile.exists) alert(csvFile + " Does not exist"); //////////Check if file exists

//////////////////////////////////////////////////////////////////////////////////////////////////

if(csvFile.exists){

var file = new Thumbnail(csvFile);

var xmpFile = new XMPFile(file.path, XMPConst.UNKNOWN,XMPConst.OPEN_FOR_UPDATE);

var xmp = xmpFile.getXMP();

xmp.deleteProperty(XMPConst.NS_DC, "creator");

xmp.deleteProperty(XMPConst.NS_DC, "title");

xmp.appendArrayItem(XMPConst.NS_DC, "creator", author, 0,XMPConst.ARRAY_IS_ORDERED);

xmp.appendArrayItem(XMPConst.NS_DC, "title", title, 0,XMPConst.ARRAY_IS_ORDERED);

if (xmpFile.canPutXMP(xmp)) {

xmpFile.putXMP(xmp);

}

xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);

}

}

}

}

}

unloadXMPScript();



function loadXMPScript()

{

var results = new XMPLibMsg("XMPScript Library already loaded", 0, false);



if (!ExternalObject.AdobeXMPScript)

{

try

{

ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');

results.message = "XMPScript Library loaded";

}

catch (e)

{

results.message = "ERROR Loading AdobeXMPScript: " + e;

results.line = e.line;

results.error = true;

}

}



return results;

}

function unloadXMPScript()

{

var results = new XMPLibMsg("XMPScript Library not loaded", 0, false);



if( ExternalObject.AdobeXMPScript )

{

try

{

ExternalObject.AdobeXMPScript.unload();

ExternalObject.AdobeXMPScript = undefined;

results.message = "XMPScript Library successfully unloaded";

}

catch (e)

{

results.message = "ERROR unloading AdobeXMPScript: " + e;

results.line = e.line;

results.error = true;

}

}



return results;

}

function XMPLibMsg (inMessage, inLine, inError)

{

this.message = inMessage;

this.line = inLine;

this.error = inError;

}
Known Participant
October 31, 2008
The new version runs without any error or user feedback of any kind. However, none of my 4 test images have had their IPTC Creator or Title metadata fields updated.
Paul Riggott
Inspiring
October 31, 2008
Here is the other version, again this works on my system.
You will have to remove the last script or overwrite it with this one to test.



#target bridge

if( BridgeTalk.appName == "bridge" ) {

addInfo = new MenuElement("command", "Update Entry Details", "at the end of Thumbnail");

}

addInfo .onSelect = function () {

main();

}

function main(){

var csv = File.openDialog("Please select CSV file.","CSV File:*.csv");

if(csv != null){

loadXMPScript();

csv.open("r");

while(!csv.eof){

strInputLine = csv.readln();

if (strInputLine.length > 3) {

strInputLine = strInputLine.replace(/\\/g,'/');

inputArray = strInputLine.split(",");

var csvFile = new File(inputArray[0]);

var title = inputArray[1];

var author = inputArray[2];

if(csvFile.exists){

var file = new Thumbnail(csvFile);

var xmpFile = new XMPFile(file.path, XMPConst.UNKNOWN,XMPConst.OPEN_FOR_UPDATE);

var xmp = xmpFile.getXMP();

xmp.deleteProperty(XMPConst.NS_DC, "creator");

xmp.deleteProperty(XMPConst.NS_DC, "title");

xmp.appendArrayItem(XMPConst.NS_DC, "creator", author, 0,XMPConst.ARRAY_IS_ORDERED);

xmp.appendArrayItem(XMPConst.NS_DC, "title", title, 0,XMPConst.ARRAY_IS_ORDERED);

if (xmpFile.canPutXMP(xmp)) {

xmpFile.putXMP(xmp);

}

xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);

}}}

}

}

unloadXMPScript();



function loadXMPScript()

{

var results = new XMPLibMsg("XMPScript Library already loaded", 0, false);



if (!ExternalObject.AdobeXMPScript)

{

try

{

ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');

results.message = "XMPScript Library loaded";

}

catch (e)

{

results.message = "ERROR Loading AdobeXMPScript: " + e;

results.line = e.line;

results.error = true;

}

}



return results;

}

function unloadXMPScript()

{

var results = new XMPLibMsg("XMPScript Library not loaded", 0, false);



if( ExternalObject.AdobeXMPScript )

{

try

{

ExternalObject.AdobeXMPScript.unload();

ExternalObject.AdobeXMPScript = undefined;

results.message = "XMPScript Library successfully unloaded";

}

catch (e)

{

results.message = "ERROR unloading AdobeXMPScript: " + e;

results.line = e.line;

results.error = true;

}

}



return results;

}

function XMPLibMsg (inMessage, inLine, inError)

{

this.message = inMessage;

this.line = inLine;

this.error = inError;

}
Paul Riggott
Inspiring
October 31, 2008
Mmm I don't this the spaces will cause a problem.
Could you try just one line with the slash the other way and see if that works?

C:/Documents and Settings/Administrator/My Documents/Visual Studio 2008/WebSites/SIEWebsite/EntryImages/E2-1261 Moray & Max.jpg,Moray & Max,David Anderson

I'm trying to create another version using AdobeXMPScript, this is proberbly what Bobs will be using? He is "The Bridge Man"
Known Participant
October 31, 2008
Could the problem be caused by my having embedded blanks in my filenames?

My CSV file includes rows like the following:

C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\WebSites\SIEWebsite\EntryImages\E2-1261 Moray & Max.jpg,Moray & Max,David Anderson

C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\WebSites\SIEWebsite\EntryImages\E3-1261 Early morning in Bruges.jpg,Early morning in Bruges,David Anderson
Paul Riggott
Inspiring
October 31, 2008
Just tried it again with 20 files and all were updated.
My csv format is like this:-
C:/Pictures/China/Paul/P1000662.jpg,Title,Author Details
C:/Pictures/China/Paul/P1000663.jpg,Title Details,More Author Details

Etc..

I have even tried with backslashes in the file path and that works as well.
I will keep looking to see if I can find something.
Known Participant
October 31, 2008
Paul,
I've tried your script with a fairly short test csv file. It runs through all the files one by one, but in each case I get the message "There was an error writing metadata to xxxxxx". What do you think might be going wrong?

BTW, I don't have any problem writing metadata to these image files manually with Bridge.

David
Known Participant
October 31, 2008
Paul,
Thanks a bundle for your script. Bob has also very kindly agreed to send me his one when he has had a chance to check it over (he hasn't used it for some time). It will be interesting to see how the scripts compare.

I'll post back here in due course with my comments on how I get on.

David
Paul Riggott
Inspiring
October 31, 2008
EDIT: Bob beat me to it.

This might do.
It uses a csv file, three fields comma seperated.
FileName including path eg: c:/folder/picture.jpg
Title and Author details.
It updates the Title and Autor fields in IPTC.
To install unzip and place this script into the following folder:
Start Bridge
Edit - Preferences -Startup Scripts
At the bottom click the "Reveal Button" this will open the folder where the script should be placed.
To use:
Mouse Right click (menu) and select "Update Entry Details"



#target bridge

if( BridgeTalk.appName == "bridge" ) {

addInfo = new MenuElement("command", "Update Entry Details", "at the end of Thumbnail");

}

addInfo .onSelect = function () {

main();

}

function main(){

var csv = File.openDialog("Please select CSV file.","CSV File:*.csv");

if(csv != null){

csv.open("r");

while(!csv.eof){

strInputLine = csv.readln();

if (strInputLine.length > 3) { // Make sure it isn't a blank line

strInputLine = strInputLine.replace(/\\/g,'/'); //Change backslash to forward slash.

inputArray = strInputLine.split(",");

var csvFile = new File(inputArray[0]);

var title = inputArray[1];

var author = inputArray[2];

if(csvFile.exists){ //Check if file exists

writeMetadata(inputArray[0],inputArray[1],inputArray[2]);

}

}

}

}

}



function writeMetadata(file,title,author){

item = new Thumbnail(file);

md =item.synchronousMetadata;

md.namespace = "http://purl.org/dc/elements/1.1/"

md.title = title;

md.namespace = "http://ns.adobe.com/photoshop/1.0/";

md.Author = author;

}