Copy link to clipboard
Copied
I'm working my way through the example but when I run the following code:
// load the library
if (ExternalObject.AdobeXMPScript == undefined) {
ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
}
xmp = new XMPMeta();
xmp.setProperty(XMPConst.NS_XMP, "CreatorTool", "My Script");
xmpStr = xmp.serialize(); // serialize the XMP packet to XML
The console in EST returns
Execution finished. Result: <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.2-c063 53.352624, 2008/07/30-18:05:41 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/">
<xmp:CreatorTool>My Script</xmp:CreatorTool>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
But when I check the file info of the file open the <xmp:CreatorTool>My Script</xmp:CreatorTool> has not been added.
Am I doing something wrong?
With CS4 the AdobeXMPScript works with both Bridge and Photoshop. I'm not sure about CS3.
The reason you are getting a return of -1 is you are giving the function a String. It requires a File.
setRating( new File("/c/hold/TestImage.tif"), "2" );
//or
var f = new File('~/Desktop/temp.tif');
setRating( f, "2" );
Copy link to clipboard
Copied
In your code you are creating a new XMPMetadata object, setting one property to that object, then serializing to a string.
You need to read the metadata from the file, set the property, then write the metadata back to the file. Below is an example to how to set the file's rating.
function setRating( file, rating ){// File object, String
try{
loadXMPLibrary();
var xmpf = new XMPFile( file.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
var xmpObj = xmpf.getXMP();
xmpObj.setProperty( XMPConst.NS_XMP, "Rating", rating );
if( xmpf.canPutXMP(xmpObj)) xmpf.putXMP( xmpObj );
xmpf.closeFile();
}catch(e){
return -1;
}
}
The loadXMPLibrary function is about the same as your lib load code but in a try/catch block with error handling.
Copy link to clipboard
Copied
Thanks Michael,
I just realised that the AdobeXMPScript.dll is in Bridge in CS3 not PhotoShop. So I should be running the Bridge engine (in EST) not the Photoshop engine. Is this correct?
if (ExternalObject.AdobeXMPScript == undefined) {
ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
}function setRating( file, rating ){// File object, String
try{
//loadXMPLibrary();
var xmpf = new XMPFile( file.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
var xmpObj = xmpf.getXMP();
xmpObj.setProperty( XMPConst.NS_XMP, "Rating", rating );
if( xmpf.canPutXMP(xmpObj)) xmpf.putXMP( xmpObj );
xmpf.closeFile();
}catch(e){
return -1;
}
}setRating( "/c/hold/TestImage.tif", "2" );
I keep getting a -1 in the console.
Copy link to clipboard
Copied
With CS4 the AdobeXMPScript works with both Bridge and Photoshop. I'm not sure about CS3.
The reason you are getting a return of -1 is you are giving the function a String. It requires a File.
setRating( new File("/c/hold/TestImage.tif"), "2" );
//or
var f = new File('~/Desktop/temp.tif');
setRating( f, "2" );
Copy link to clipboard
Copied
Fantastic Michael,
Unfortunately this will only work in Bridge on CS3 but still does what I need.
If anyone else needs a script to will change the metadata of a selected file check out the Bridge SDK there a good example there which lead to this:
if (ExternalObject.AdobeXMPScript == undefined) {
ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
}var thumb = app.document.selections[0];
var md = thumb.synchronousMetadata;
var xmp = new XMPMeta(md.serialize());
xmp.setProperty(XMPConst.NS_XMP, "CreatorTool", "Changed by SnpModifyMetadata");
var updatedPacket = xmp.serialize(XMPConst.SERIALIZE_OMIT_PACKET_WRAPPER | XMPConst.SERIALIZE_USE_COMPACT_FORMAT);
thumb.metadata = new Metadata(updatedPacket);
Much appreciated for your help.
John.
Copy link to clipboard
Copied
Hi again.
In CS4...
I'm trying to implement this to set ratings on the files in a folder. I was actually trying this through Bridge but it isn't working so I'm now trying it from Photoshop. On my website, clients choose files and can set a rating from 1-4 stars ****. I then get an email with their choices and ratings in the following format:
Molli_20100620_0183.jpg ***
Molli_20100620_0182.jpg **
Molli_20100620_0181.jpg **
Molli_20100620_0180.jpg **
Molli_20100620_0179.jpg *
Molli_20100620_0178.jpg *
So I wrote a script to parse through these to try to have it assign the ratings to the associated .CR2 files. Here is the output from that:
Molli_20100620_0183.CR2 3
Molli_20100620_0182.CR2 2
Molli_20100620_0181.CR2 2
Molli_20100620_0180.CR2 2
Molli_20100620_0179.CR2 1
Molli_20100620_0178.CR2 1
I then pass the file and rating to the function Mr. Hale wrote and I get a returned value of -1. Here is the script in full:
function setRating(file,rating) {
try{loadXMPLibrary();
var xmpf = new XMPFile( file.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
var xmpObj = xmpf.getXMP();xmpObj.setProperty( XMPConst.NS_XMP, "Rating", rating );
if( xmpf.canPutXMP(xmpObj)) xmpf.putXMP( xmpObj );
xmpf.closeFile();
}
catch(e){return -1;}
}
function main(md) {
var fold=new Folder(md.fname);
ratings=new File(fold+"/Ratings.txt");
alert(ratings.fullName);
var done=false;
if (!ratings.created) {
ratings.open('w');
ratings.close();
ratings.execute();
return;
}
else {
ratings.open('r');
while (!done) {
rate=new String(ratings.readln());
if (!ratings.eof) {
sp=rate.split(" ");
file=new File(fold+"/"+sp[0].substring(0,sp[0].length-3)+"CR2");
rating=sp[1].length;
er=setRating(file,rating);
}
else done=true;
}
}
ratings.close();
alert(er);
}
var bt = new BridgeTalk;
bt.target = "bridge-3.0";
bt.body = "var tn = app.document; var md = {fname:tn.presentationPath}; md.toSource();"
bt.onResult = function(resObj) {
md = bt.result = eval(resObj.body);
main(md);
}
bt.send();
I'm using BridgeTalk to get the active folder that is open in Bridge. Ideally, I would like to run this from within Bridge and not use Photoshop. For that I have the following:
var menu = MenuElement.create( "command", "Set Ratings", "-at the end of Tools");
function setRating(file,rating) {
try{
loadXMPLibrary();
var xmpf = new XMPFile( file.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
var xmpObj = xmpf.getXMP();
xmpObj.setProperty( XMPConst.NS_XMP, "Rating", rating );
if( xmpf.canPutXMP(xmpObj)) xmpf.putXMP( xmpObj );
xmpf.closeFile();
}
catch(e){ return -1; }
}
menu.onSelect = function () {
fold=app.document.presentationPath;
ratings=new File(win+"/Ratings.txt");
var done=false;
if (!ratings.created) {
ratings.open('w');
ratings.close();
ratings.execute();
return;
}
else {
ratings.open('r');
while (!done) {
rate=new String(ratings.readln());
if (!ratings.eof) {
sp=rate.split(" ");
file=new File(fold+"/"+sp[0].substring(0,sp[0].length-3)+"CR2");
rating=sp[1].length;
er=setRating(file,rating);
}
else done=true;
}
}
ratings.close();
alert(er);
}
Everything runs fine both ways I do this and sends the same format to the setRating() function. If I run an execute on the file, it does open up the appropriate image file "file.execute()". However, the alert(er) at the end returns -1 every time in both scripts.
If anyone can help with this, I'd appreciate it.
Thanks
Copy link to clipboard
Copied
rating is a property of thumbnail object in bridge so just set it a value?
#target bridge // First doc var x = app.documents[0]; // Selections is Array of thumbnail objects var y = x.selections; // Set for first item in Array y[0].rating = 3;
Copy link to clipboard
Copied
Thanks, Mark.
I did finally get this figured out. It seems that when it comes to CR2 files, the xmp library doesn't work. In order to set the Rating of the files, the sidecar .xmp files had to be edited. I'm including my final script here in case anyone else is working with CR2 files and wishes to do something similar. I haven't added in any error checking to this, so user beware.
#target bridge
var menu = MenuElement.create( "command", "Set Ratings", "-at the end of Tools");
function setRating(file,rating) {
file.open('e');
while (!file.eof) {
pos=file.tell();
line=new String(file.readln());
if (line.indexOf("xap:Rating")>0) {
file.seek(pos);
if (file.writeln(" <xap:Rating>",rating,"</xap:Rating>")) {
file.close();
return;
}
}
}
file.close();
return;
}
menu.onSelect = function () {
fold=app.document.presentationPath;
ratings=new File(fold+"/Ratings.txt");
if (!ratings.created) {
ratings.open('w');
ratings.close();
ratings.execute();
return;
}
else {
ratings.open('r');
while (!ratings.eof) {
rate=new String(ratings.readln());
sp=rate.split(" ");
file=File(fold+"/"+sp[0].substring(0,sp[0].length-3)+"xmp");
rating=sp[1].length;
setRating(file,rating);
}
}
ratings.close();
app.document.refresh();
}
Copy link to clipboard
Copied
Camera raw files are read only so you can update them directly and XMPFile does not support sidecar .xmp files.
But you can still use the XMPLibrary and XMPMeta to update camera raw files. You just have to get the metadata from a thumbnail object and write the updated metadata back to the thumbnail.
I would think doing the update this way would be better than doing a string search and writing to the sidecar.
The script below set the rating to a NEF file in Bridge. If the xmp sidecar file for the camera raw file does not exists one will be created. It shoud work with any camera raw format.
function setRating(file,rating) {
try{
loadXMPLibrary();
var thumb = new Thumbnail(file);//make a new thumbnail for file
app.synchronousMode = true;// make sure metadata is up todate
var xmp = new XMPMeta(thumb.synchronousMetadata.serialize());// make an XMP object from thumb metadata
xmp.setProperty( XMPConst.NS_XMP, "Rating", rating );// edit the metadata
// prepare xmp to update file
var newPacket = xmp.serialize(XMPConst.SERIALIZE_USE_COMPACT_FORMAT);
thumb.metadata = new Metadata(newPacket);// update file via thumb
unloadXMPLibrary();
}catch(e){
alert(e);
unloadXMPLibrary();
return -1;
}
}
function loadXMPLibrary(){
if ( !ExternalObject.AdobeXMPScript ){
try{
ExternalObject.AdobeXMPScript = new ExternalObject
('lib:AdobeXMPScript');
}catch (e){
alert( ErrStrs.XMPLIB );
return false;
}
}
return true;
};
function unloadXMPLibrary(){
if( ExternalObject.AdobeXMPScript ) {
try{
ExternalObject.AdobeXMPScript.unload();
ExternalObject.AdobeXMPScript = undefined;
}catch (e){
alert( ErrStrs.XMPLIB );
}
}
};
var f = new File('~/Desktop/DSC_5396.NEF');
setRating(f,5);
Copy link to clipboard
Copied
This works, too. Thanks, Mike.
Michael L Hale wrote:
Camera raw files are read only so you can update them directly and XMPFile does not support sidecar .xmp files.
But you can still use the XMPLibrary and XMPMeta to update camera raw files. You just have to get the metadata from a thumbnail object and write the updated metadata back to the thumbnail.
I would think doing the update this way would be better than doing a string search and writing to the sidecar.
The script below set the rating to a NEF file in Bridge. If the xmp sidecar file for the camera raw file does not exists one will be created. It shoud work with any camera raw format.
function setRating(file,rating) { try{ loadXMPLibrary(); var thumb = new Thumbnail(file);//make a new thumbnail for file app.synchronousMode = true;// make sure metadata is up todate var xmp = new XMPMeta(thumb.synchronousMetadata.serialize());// make an XMP object from thumb metadata xmp.setProperty( XMPConst.NS_XMP, "Rating", rating );// edit the metadata // prepare xmp to update file var newPacket = xmp.serialize(XMPConst.SERIALIZE_USE_COMPACT_FORMAT); thumb.metadata = new Metadata(newPacket);// update file via thumb unloadXMPLibrary(); }catch(e){ alert(e); unloadXMPLibrary(); return -1; } } function loadXMPLibrary(){ if ( !ExternalObject.AdobeXMPScript ){ try{ ExternalObject.AdobeXMPScript = new ExternalObject ('lib:AdobeXMPScript'); }catch (e){ alert( ErrStrs.XMPLIB ); return false; } } return true; }; function unloadXMPLibrary(){ if( ExternalObject.AdobeXMPScript ) { try{ ExternalObject.AdobeXMPScript.unload(); ExternalObject.AdobeXMPScript = undefined; }catch (e){ alert( ErrStrs.XMPLIB ); } } }; var f = new File('~/Desktop/DSC_5396.NEF'); setRating(f,5);