Skip navigation
Currently Being Moderated

help - problem with a function

Sep 3, 2009 2:06 PM

There is a gerat Kasyan script here he prepared for one of my tasks / a special workflow:

 

Imagine you have a document with one hundred pages and all pages contain one image and a text box with individual photo credit / description.

The script is pasting each images text box into the images xmp description via bridge - great, fast and I've never seen anything like this elsewhere

 

Now there is one problem: The script removes all hard/new line breakts form the credit, but I need that sometimes.

I like to get rid of the ReturnWithSpace function, but it seems like it is a little bit complex.

 

Here is the complex function ...

 

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

 

 

Here is the full script  - maybe somebody can help:

 

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

 
Replies
  • Currently Being Moderated
    Sep 3, 2009 7:23 PM   in reply to dugiedugie

    If I may make an observation, the XMPScript API is separate from the Bridge DOM, so your script could avoid to invoke Bridge.

    InDesign is able to load the required library -- new ExternalObject('lib:AdobeXMPScript') -- and to process directly the XMP data.

     

    Then, we can really simplify the code. Try this:

     

    TextFrame.prototype.getCaption = function()
    // Here you can customize the caption written in XMP
    {
    // old behavior :
    // return this.contents.replace( /[\n\r]/g , " " );
     
    // contents as it (keeping newlines) :
    return this.contents;
    }
     
    Document.prototype.getScope = function()
    { // return the array of {txf,img} objects to process
    var scope = [], pages = this.pages;
    for ( var pg, p = pages.length-1 ; p >= 0 ; p-- )
         {
        pg = pages[p];
         if ( pg.textFrames.length != 1 ) continue;
         if ( pg.rectangles.length != 1 ) continue;
         if ( pg.rectangles[0].images.length != 1 ) continue;
         scope.push({txf: pg.textFrames[0],img: pg.rectangles[0].images[0]});
        }
    return(scope);
    }
     
    Application.prototype.main = function()
    {
    if ( this.documents.length<=0 )
         {alert("Think to open a document!");return;}
         
    var scope, sel = this.selection;
    switch(sel.length)
         {
         case 0 :
              scope = this.activeDocument.getScope();
              break;
         case 2 :
              scope = ( function()
                   {
                   var t = (sel[0].constructor == TextFrame) ? 0 :
                        ( (sel[1].constructor == TextFrame) ? 1 : false );
                   if (t===false) return(null);
                   if ( sel[1-t].images.length != 1 ) return(null);
                   return [{txf: sel[t], img: sel[1-t].images[0]}];
                   } )();
              if (scope) break;
         default :
              alert("One image and one textframe should be selected.");
              return;
         }
     
    if (ExternalObject.AdobeXMPScript == undefined)
         {
         try {ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');}
         catch(ex) {alert("Unable to load the AdobeXMPScript library"); return;}
         };
     
    var txfImg, iLink, iFile, xmpFile, xmp;
    var err=0, cpt=0;
    while (txfImg=scope.pop())
         {
         iLink = txfImg.img.itemLink;
         try {iFile = new File(iLink.filePath);}
         catch(ex) {err++;continue;}
     
         xmpFile = new XMPFile(iFile.fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
     
         xmp = xmpFile.getXMP();
         xmp.deleteProperty(XMPConst.NS_XMP, "Description");
         xmp.setProperty(XMPConst.NS_XMP, "Description", txfImg.txf.getCaption());
     
         if (xmpFile.canPutXMP(xmp)) { xmpFile.putXMP(xmp); cpt++;} else err++;
         xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
         
         if (iLink.status == LinkStatus.linkOutOfDate) iLink.update();
         }
     
    alert(''+cpt+" image descriptions updated -- "+err+" errors.");
     
    try{this.activeDocument.save();}
    catch(ex){}
    }
     
    app.main();
    
     
    |
    Mark as:
  • Currently Being Moderated
    Sep 7, 2009 9:23 AM   in reply to dugiedugie

    Hi dugiedugie,

     

    The script I've written was intended for ID CS4 --sorry for this frustrating mistake!-- wich provides scripting access to XMPMetaData (via the XMPScript library).

     

    But apparently, the XMPScript lib wasn't existing in CS3 JavaScript package.

     

    Thus, the automatic load in the line:

      ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript')

    can't succeed.

     

    The modification you made in the code throws a syntax error because the path that you try to pass to the ExternalObject contructor is not embedded in string quotes:

     

    ExternalObject.AdobeXMPScript = new ExternalObject(lib:/Applications/Adobe\ InDesign\ CS3/Adobe\ InDesign\ CS3.app/Contents/Frameworks/AdobeXMP.framework);

     

    You rather need to write something like:

     

    ExternalObject.AdobeXMPScript = new ExternalObject("lib:/Applications/Adobe InDesign CS3/Adobe InDesign CS3.app/Contents/Frameworks/AdobeXMP.framework");

     

    Anyway, I'm not sure that the AdobeXMP.framework would be equivalent to XMPScript.

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 7, 2009 2:13 PM   in reply to dugiedugie

    dugiedugie wrote:

     

    Hi Marc,

     

    oh - that is very sad. At the moment I'm stuck with CS3. I'll keep your script till CS4 is at work.

    So maybe a workaround of that function from my old script might solve and fix my worflow for the time till I'm back from holidays:

     

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

     

    I've tried to alternate versions like this

     

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

     

    But that does not work at all. The scripts works pretty good with bridge - maybe with this function not replacing new lines and hard line breaks would make my day. Can you help?

     

    If you just want to keep the XMP description 'as-it' from the caption text frames, the ReplaceReturnWithSpace function of the old script need to be neutralized. Then, the patch is very very simple:

     

    function ReplaceReturnWithSpace(myString) { return myString; }

     


    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Sep 8, 2009 2:12 AM   in reply to dugiedugie

    dugiedugie wrote:

     

    Oh, I just figured, that the function works but not when using new line/ hard line breaks.

    So my final question is: How can I presever this - it seems like the field is not transporting the content with special charakters thus the xmp descriptions allows hard and soft line breaks.

     

    Can someone help?

     

    OK, the problem comes from the CreateBridgeTalkMessage function, which writes dynamically a code fragment and injects the caption contents in it. So, the newline characters are not interpreted correctly. Actually, there are many other potential issues with such a function!

     

    Temporarily, you could try to patch ReplaceReturnWithSpace with this:

     

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

     

     

    Not sure it will work --cannot test a CS3 scripting configuration.

     

    @+

    Marc

     
    |
    Mark as:
  • Currently Being Moderated
    Oct 25, 2010 9:12 AM   in reply to dugiedugie

    Hey!

     

    Unfortunately, XMP is not really working good in InDesign. For example you can't pull out data from image without using external object except you want to pull just data from XMP namespace. Fortunately we can use external library to access and edit metadata already stored in files. Error you are getting is, like you said, because file is already opened or being edited from another place. I suggest you to take a look at five posts that I wrote about XMP data.

     

    Extract Metadata with Adobe XMP [Part 1] http://bit.ly/arpiLq

    Extract Metadata with Adobe XMP [Part 2] http://bit.ly/cFOXvS

    Extract file preview stored in Adobe XMP data http://bit.ly/9GPoOm

    Fill InDesign XMP info from document content http://bit.ly/9ubvRh

    Storing custom data into InDesign file XMP http://bit.ly/9VafXe

     

    Hope that helps.

     

    --

    tomaxxi

    http://indisnip.wordpress.com

     
    |
    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