Skip navigation
Currently Being Moderated

Need help [JS]: select images/captions in InD, switch to Bridge and write to XMP

Mar 23, 2009 11:33 AM

I've got a javascript for CS3/Tiger that I'm writing that eventually will let a user select an image and a caption in InDesign, then tells bridge to write the caption data into the image metadata. I need help - the script works in pieces, but not when put together.

It's built as an indesign script, then follows the procedure to create a script object to send to bridge. When it runs, the indesign portion works fine, but nothing happens in bridge.

The script is below, with comments.

Can someone help!? Thanks.

// This is the InDesign portion of the script, which was tested separately and is working fine. Right now, for testing purposes, the data from this portion isn't even used by the later Bridge portion but once I get the bridge part together, it will use those variables.
#target "indesign-5.0"
var myObjectList = new Array;
//Script does nothing if no documents are open or if no objects are selected.
if(app.documents.length != 0){
if(app.selection.length != 0){
for(myCounter = 0; myCounter < app.selection.length; myCounter ++){
switch(app.selection[myCounter].constructor.name){
case "TextFrame":
var myCaption = app.selection[myCounter].contents;
$.writeln(myCaption);
break;
default:
var myLink = app.selection[myCounter].graphics[0].itemLink.filePath;
$.writeln(myLink);
}
}
}
}

// here's where I create the string of the script to send to Bridge.
// the script itself is almost completely a lifted from the SnpModifyMetadta sample from the Bridge sdk
// it basically finds a certain image file and modifies the description metatata. i hardcoded the caption text and image path just for testing- eventually i would like it to use the variables from indesign.
// this script works fine as-is when run in the original Bridge scripting context.
// the method here of concatenating and sending the myScript string works fine when i use a different (smaller) script. so i can't tell why it's not working!?

var myScript = "function SnpModifyMetadata()";
myScript += "{";
myScript += " this.requiredContext = \"Needs to run in Bridge, \nwith a selection of a file, \nideally with some metadata\";";
myScript += "}";
myScript += "SnpModifyMetadata.prototype.run = function()";
myScript += "{";
myScript += " if(!this.canRun())";
myScript += " {";
myScript += " return false;";
myScript += " }";
myScript += " if( xmpLib == undefined )";
myScript += " {";
myScript += " if( Folder.fs == \"Windows\" )";
myScript += " {";
myScript += " var pathToLib = Folder.startup.fsName + \"/AdobeXMPScript.dll\";";
myScript += " }";
myScript += " else";
myScript += " {";
myScript += " var pathToLib = Folder.startup.fsName + \"/AdobeXMPScript.framework\";";
myScript += " }";
myScript += " var libfile = new File( pathToLib );";
myScript += " var xmpLib = new ExternalObject(\"lib:\" + pathToLib );";
myScript += " }";
myScript += " $.writeln(\"About to run SnpModifyXML\");";
myScript += " var thumb = new Thumbnail(Folder(\"/Macintosh HD/Users/hearstuser/Desktop/BridgeScriptImages/orion_stack copy 6.psd\"));";
myScript += " if(thumb.hasMetadata)";
myScript += " {";
myScript += " var md = thumb.synchronousMetadata;";
myScript += " var xmp = new XMPMeta(md.serialize());";
myScript += " $.writeln(\"SnpModifyXML: About to modify XMP data for \" + thumb.name);";
myScript += " $.writeln(\"XMP packet before modifications:\");";
myScript += " $.writeln(\"-------------------------------------------------\");";
myScript += " $.writeln(xmp.dumpObject());";
myScript += " xmp.deleteProperty(XMPConst.NS_XMP, \"Description\");";
myScript += " xmp.setProperty(XMPConst.NS_XMP, \"Description\", \"hoThereHeyThere\");";
myScript += " var d = new XMPDateTime(new Date());";
myScript += " d.convertToLocalTime();";
myScript += " xmp.setProperty(XMPConst.NS_XMP, \"ModifyDate\", d, XMPConst.XMPDATE);";
myScript += " $.writeln(\"XMP packet af
 
Replies
  • Currently Being Moderated
    Mar 24, 2009 2:08 AM   in reply to jhuddle123

    #target 'indesign-5.0'
    var myObjectList = new Array;
    if(app.documents.length != 0){
       if(app.selection.length != 0){
          for(myCounter = 0; myCounter < app.selection.length; myCounter ++){
             switch(app.selection[myCounter].constructor.name){
             case "TextFrame":
             var myCaption = app.selection[myCounter].contents;
             $.writeln(myCaption); break;
             default: var myLink = app.selection[myCounter].graphics[0].itemLink.filePath;
             $.writeln(myLink);
             }
          }
       }
    }

    var myScript = 'function SnpModifyMetadata()\n';
    myScript += '{\n';
    myScript += ' this.requiredContext = \"Needs to run in Bridge, with a selection of a file, ideally with some metadata\";\n';
    myScript += '}\n';
    myScript += 'SnpModifyMetadata.prototype.run = function()\n';
    myScript += '{\n';
    myScript += ' if(!this.canRun())\n';
    myScript += ' {\n';
    myScript += ' return false;\n';
    myScript += ' }\n';
    myScript += ' if( xmpLib == undefined )\n';
    myScript += ' {\n';
    myScript += ' if( Folder.fs == \"Windows\")\n';
    myScript += ' {\n';
    myScript += ' var pathToLib = Folder.startup.fsName + \"/AdobeXMPScript.dll\";\n';
    myScript += ' }\n';
    myScript += ' else\n';
    myScript += ' {\n';
    myScript += ' var pathToLib = Folder.startup.fsName + \"/AdobeXMPScript.framework\";\n';
    myScript += ' }\n';
    myScript += ' var libfile = new File( pathToLib );\n';
    myScript += ' var xmpLib = new ExternalObject(\"lib:\" + pathToLib );\n';
    myScript += ' }\n';
    myScript += ' $.writeln(\"About to run SnpModifyXML\");\n';
    myScript += ' var thumb = new Thumbnail(Folder(\"~/Desktop/BridgeScriptImages/orion_stack copy 6.psd\"));\n';
    myScript += ' if(thumb.hasMetadata)\n';
    myScript += ' {\n';
    myScript += ' var md = thumb.synchronousMetadata;\n';
    myScript += ' var xmp = new XMPMeta(md.serialize());\n';
    myScript += ' $.writeln(\"SnpModifyXML: About to modify XMP data for \" + thumb.name);\n';
    myScript += ' $.writeln(\"XMP packet before modifications:\");\n';
    myScript += ' $.writeln(\"-------------------------------------------------\");\n';
    myScript += ' $.writeln(xmp.dumpObject());\n';
    myScript += ' xmp.deleteProperty(XMPConst.NS_XMP, \"Description\");\n';
    myScript += ' xmp.setProperty(XMPConst.NS_XMP, \"Description\", \"hoThereHeyThere\");\n';
    myScript += ' var d = new XMPDateTime(new Date());\n';
    myScript += ' d.convertToLocalTime();\n';
    myScript += ' xmp.setProperty(XMPConst.NS_XMP, \"ModifyDate\", d, XMPConst.XMPDATE);\n';
    myScript += ' $.writeln(\"XMP packet after modifications:\");\n';
    myScript += ' $.writeln(\"-------------------------------------------------\");\n';
    myScript += ' $.writeln(xmp.dumpObject());\n';
    myScript += ' var updatedPacket = xmp.serialize(XMPConst.SERIALIZE_OMIT_PACKET_WRAPPER | XMPConst.SERIALIZE_USE_COMPACT_FORMAT);\n';
    myScript += ' thumb.metadata = new Metadata(updatedPacket);\n';
    myScript += ' }\n';
    myScript += ' else\n';
    myScript += ' {\n';
    myScript += ' $.writeln(\"The selected thumbnail has no metadata.\");\n';
    myScript += ' }\n';
    myScript += ' $.writeln(\"Ran SnpModifyMetadata\");\n';
    myScript += ' return true;\n';
    myScript += '}\n';
    myScript += 'SnpModifyMetadata.prototype.canRun = function()\n';
    myScript += ' {\n';
    myScript += ' if( (BridgeTalk.appName == \"bridge\") && (app.document.selectionLength == 1)) {\n';
    myScript += ' return true;\n';
    myScript += ' }\n';
    myScript += ' $.writeln(\"ERROR:: Cannot run SnpModifyMetadata\");\n';1
    myScript += ' $.writeln(this.requiredContext);\n';
    myScript += ' return false;\n';
    myScript += '}\n';
    myScript += 'if(typeof(SnpModifyMetadata_unitTest ) == \"undefined\") {\n';
    myScript += ' new SnpModifyMetadata().run();\n';
    myScript += '}';

    var targetApp = BridgeTalk.getSpecifier( "bridge", "2");
    if( targetApp ) {
       var bt = new BridgeTalk; // create a new BridgeTalk message object
       bt.target = "bridge"; // send this msg to the Adobe Bridge application
       bt.body = myScript
       bt.send(0);
    }
     
    |
    Mark as:
  • Currently Being Moderated
    Mar 24, 2009 2:40 AM   in reply to jhuddle123
    Hi Jim,

    First of all please use Script Poster when you post your code – this will make it much easier to read.
    If you place a breakpoint somewhere in your code, after you defined myScript variable and type ‘myScript’ and return in console, you’ll get the script you are about to send to Bridge. Copy it , create a new file and paste. You’ll see that your code is totally scrambled. It can’t work.
    At first, you need to create a script for Bridge, test it and then assign it to a variable as a string.
    When you do this, use two sets of quotes single – outside and double – inside each line, and also put a new line (\n)at the end of every but last line.
    And you don’t need to place the whole example script – it looks like spaghetti code. Just write what is necessary for your script to work.

    Kasyan
     
    |
    Mark as:
  • Currently Being Moderated
    Mar 31, 2009 7:12 AM   in reply to jhuddle123
    Hi Jim,

    You don’t need to use headers like so:
    bt.headers ["myNewCaption"] = "" + myCaption;
    


    Here is my vision of how to make this script – it's not totally tested and it requires improvement of course.

    Kasyan

    #target indesign
    
    var myDoc = app.activeDocument;
    var mySelection = app.selection;

    if (mySelection.length != 2) {
       alert("One image and one textframe should be selected.");
       exit();
    }
    try {
       if (mySelection[0].constructor.name == "TextFrame" && mySelection[1].images.length == 1) {
          var myTextFrame = mySelection[0];
          var myImage = mySelection[1].images[0];
          var myCaption = myTextFrame.contents;
          var myPath = new File(myImage.itemLink.filePath).absoluteURI;
       }
       else if (mySelection[1].constructor.name != "TextFrame" && mySelection[0].images.length == 1) {
          var myTextFrame = mySelection[1];
          var myImage = mySelection[0].images[0];
          var myCaption = myTextFrame.contents;
          var myPath = new File(myImage.itemLink.filePath).absoluteURI;
       }
    }
    catch(e) {
       alert("Something wrong with your selection.\nError: " + e.message);
       exit();
    }

    var bt = new BridgeTalk();
    bt.target = "bridge";
    var myScript = 'function WriteCaption(myCaption, myPath) {\n';
    myScript += '    if( xmpLib == undefined )\n';
    myScript += '    {\n';
    myScript += '       if( Folder.fs == "Windows")\n';
    myScript += '       {\n';
    myScript += '          var pathToLib = Folder.startup.fsName + "/AdobeXMPScript.dll";\n';
    myScript += '       }\n';
    myScript += '      else\n';
    myScript += '      {\n';
    myScript += '          var pathToLib = Folder.startup.fsName + "/AdobeXMPScript.framework";\n';
    myScript += '       }\n';
    myScript += '       var libfile = new File( pathToLib );\n';
    myScript += '       var xmpLib = new ExternalObject("lib:" + pathToLib );\n';
    myScript += '    }\n';
    myScript += '   var thumb = new Thumbnail (File (myPath));\n';
    myScript += '   if (thumb.hasMetadata)\n';
    myScript += '    {\n';
    myScript += '      var md = thumb.synchronousMetadata;\n';
    myScript += '      var xmp = new XMPMeta(md.serialize());\n';
    myScript += '      xmp.deleteProperty(XMPConst.NS_XMP, "Description");\n';
    myScript += '      xmp.setProperty(XMPConst.NS_XMP, "Description", myCaption);\n';
    myScript += '      var updatedPacket = xmp.serialize(XMPConst.SERIALIZE_OMIT_PACKET_WRAPPER | XMPConst.SERIALIZE_USE_COMPACT_FORMAT);\n';
    myScript += '      thumb.metadata = new Metadata(updatedPacket);\n';
    myScript += '   }\n';
    myScript += '}\n';
    myScript += 'WriteCaption(\"' + myCaption + '\", \"' + myPath + '\");\n';
    bt.body = myScript;
    bt.send();
     
    |
    Mark as:
  • Currently Being Moderated
    Apr 18, 2009 8:24 AM   in reply to jhuddle123

    Recently I received an e-mail from a user asking me to remake the script I had posted here a while ago.

    I rechecked my previous post and found a couple of serious mistakes. So I revised it according to what he asked. Each page in his InDesign document contains one image and one text frame with description.

    At start the script checks the selection. If nothing is selected it processes all pages in the document. In case two objects are selected – it checks whether one of them text frame and the other a rectangle and if the rectangle contains an image, then it reads the contents of the text frame, replacing hard and soft returns with spaces and writes this text to the corresponding image’s description field.

    In the end, it updates all links and saves the file.

    The script works both on Mac and PC, assuming that CS3 installed in the default location so long as it depends on libraries:

    /C/Program Files/Adobe/Adobe Bridge CS3/AdobeXMPScript.dll (on PC)

    /Applications/Adobe Bridge CS3/Bridge CS3.app/Contents/MacOS/AdobeXMPScript.framework (on MAC)

    So, if necessary, correct these lines.

     

    Here is my script in case somebody is interested:

     

    #target indesign

     

    var myDoc = app.activeDocument;
    var mySelection = app.selection;

     

    if (mySelection.length == 0) {
        ProcessPages();
    }
    else if (mySelection.length == 1) {
        alert("One image and one textframe should be selected.");
        exit();   
    }
    else if (mySelection.length == 2) {
        try {
            if (mySelection[0].constructor.name == "TextFrame" && mySelection[1].images.length == 1) {
                var myTextFrame = mySelection[0];
                var myImage = mySelection[1].images[0];
                var myCaption = ReplaceReturnWithSpace(myTextFrame.contents);
                var myPath = new File(myImage.itemLink.filePath).absoluteURI;
            }
            else if (mySelection[1].constructor.name == "TextFrame" && mySelection[0].images.length == 1) {
                var myTextFrame = mySelection[1];
                var myImage = mySelection[0].images[0];
                var myCaption = ReplaceReturnWithSpace(myTextFrame.contents);
                var myPath = new File(myImage.itemLink.filePath).absoluteURI;
            }
        }
        catch(e) {
            alert("Something wrong with your selection.\nError: " + e.message);
            exit();
        }

     

        CreateBridgeTalkMessage(myCaption, myPath);
    }
    else if (mySelection.length > 2) {
        alert("One image and one textframe should be selected.");
        exit();
    }

     

    UpdateAllOutdatedLinks();
    myDoc.save();
    alert("All done.");

     

    //+++++++++++++++++++ FUNCTIONS ++++++++++++++++++++++

     

    function CreateBridgeTalkMessage(myCaption, myPath) {
        var bt = new BridgeTalk();
        bt.target = "bridge";
        var myScript = WriteCaption.toString() + '\r';
        myScript += 'WriteCaption(\"' + myCaption + '\", \"' + myPath + '\");';
        bt.body = myScript;
        bt.send();
    }

     

    function WriteCaption(myCaption, myPath) {
        if( xmpLib == undefined ) {
            if( Folder.fs == "Windows") {
                var pathToLib = "/C/Program Files/Adobe/Adobe Bridge CS3/AdobeXMPScript.dll";
            }
            else {
                var pathToLib = "/Applications/Adobe Bridge CS3/Bridge CS3.app/Contents/MacOS/AdobeXMPScript.framework";
            }
            var libfile = new File( pathToLib );
            var xmpLib = new ExternalObject("lib:" + pathToLib );
        }
        var thumb = new Thumbnail (File (myPath));

     

        if (thumb.hasMetadata) {
            var md = thumb.synchronousMetadata;
            var xmp = new XMPMeta(md.serialize());
            xmp.deleteProperty(XMPConst.NS_XMP, "Description");
            xmp.setProperty(XMPConst.NS_XMP, "Description", myCaption);
            var updatedPacket = xmp.serialize(XMPConst.SERIALIZE_OMIT_PACKET_WRAPPER | XMPConst.SERIALIZE_USE_COMPACT_FORMAT);
            thumb.metadata = new Metadata(updatedPacket);
        }
    }

     

    function ProcessPages() {
        var myPages = myDoc.pages;
        for (i = 0; i < myPages.length; i++) {
            var myPage = myPages[i];
            if (myPage.textFrames.length == 1 && myPage.rectangles.length == 1) {
                if (myPage.rectangles[0].graphics.length == 1) {
                var a = myPage.rectangles[0];
                    var myImage = myPage.rectangles[0].graphics[0];
                    var myPath = new File(myImage.itemLink.filePath).absoluteURI;
                    var myTextFrame = myPage.textFrames[0];
                    var myCaption = ReplaceReturnWithSpace(myTextFrame.contents);
                    CreateBridgeTalkMessage(myCaption, myPath);
                }
            }
        }
    }

     

    function ReplaceReturnWithSpace(myString) {
        myString = myString.replace( /\n/g , " " );
        myString = myString.replace( /\r/g , " " );
        return myString;
    }

     

    function UpdateAllOutdatedLinks() {
        for(var myCounter = myDoc.links.length-1; myCounter >= 0; myCounter--){
            var myLink = myDoc.links[myCounter];
            if (myLink.status == LinkStatus.linkOutOfDate){
                myLink.update();
            }
        }
    }

     

    If somebody interested in developing this script further, do not hesitate to post here your feedback.

     

    Kasyan

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)