• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Creating new metadata example in Javascript Tool Guide

Explorer ,
Jan 06, 2010 Jan 06, 2010

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?

TOPICS
Actions and scripting

Views

5.6K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Guru , Jan 06, 2010 Jan 06, 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" );

Votes

Translate

Translate
Adobe
Guru ,
Jan 06, 2010 Jan 06, 2010

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 06, 2010 Jan 06, 2010

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Jan 06, 2010 Jan 06, 2010

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Jan 06, 2010 Jan 06, 2010

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.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Jun 24, 2010 Jun 24, 2010

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Jun 24, 2010 Jun 24, 2010

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;

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Jun 24, 2010 Jun 24, 2010

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guru ,
Jun 24, 2010 Jun 24, 2010

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Jun 24, 2010 Jun 24, 2010

Copy link to clipboard

Copied

LATEST

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

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines