Skip navigation
Currently Being Moderated

Creating new metadata example in Javascript Tool Guide

Jan 6, 2010 4:39 AM

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?

 
Replies
  • Currently Being Moderated
    Jan 6, 2010 5:38 AM   in reply to John.Kordas

    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.

     
    |
    Mark as:
  • Currently Being Moderated
    Jan 6, 2010 5:00 PM   in reply to John.Kordas

    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" );
     
    |
    Mark as:
  • Currently Being Moderated
    Jun 24, 2010 3:16 PM   in reply to Michael L Hale

    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

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 24, 2010 4:01 PM   in reply to jugenjury

    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;
    

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 24, 2010 7:40 PM   in reply to John.Kordas

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

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 24, 2010 8:58 PM   in reply to jugenjury

    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);
    
     
    |
    Mark as:
  • Currently Being Moderated
    Jun 24, 2010 9:58 PM   in reply to Michael L Hale

    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);
    
     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points