Skip to main content
John_Kordas
Inspiring
January 6, 2010
Answered

Creating new metadata example in Javascript Tool Guide

  • January 6, 2010
  • 2 replies
  • 6113 views

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?

This topic has been closed for replies.
Correct answer Michael_L_Hale

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" );

2 replies

Inspiring
June 25, 2010

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();
}

Inspiring
June 25, 2010

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);

Inspiring
June 25, 2010

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);
Inspiring
January 6, 2010

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.

John_Kordas
Inspiring
January 7, 2010

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.

Michael_L_HaleCorrect answer
Inspiring
January 7, 2010

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" );