11 Replies Latest reply: Oct 25, 2010 9:12 AM by Marijan Tompa RSS

    help - problem with a function

    dugiedugie

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

        • 1. Re: help - problem with a function
          Marc Autret MeganK

          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();
          
          • 2. Re: help - problem with a function
            dugiedugie Community Member

            Hi Marc,

             

            I'm not so script savvy but try to understand.

             

            I've put you script into a new document:

             

            #target indesign

             

            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:/Applications/Adobe\ InDesign\ CS3/Adobe\ InDesign\ CS3.app/Contents/Frameworks/AdobeXMP.framework);} // this is where the script reports errors
                 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();

             

            This script gives me errors due to not being able to load the xmp lib.

            I tried to fill in the path but it is not working at all. I'm on a mac osx with CS3 default install locations. Maybe you or somebody might help with this?

             

            Million Thanks

            D

            • 3. Re: help - problem with a function
              Marc Autret MeganK

              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.

              • 4. Re: help - problem with a function
                dugiedugie Community Member

                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?

                • 5. Re: help - problem with a function
                  Marc Autret MeganK

                  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

                  • 6. Re: help - problem with a function
                    dugiedugie Community Member

                    Dear Marc,

                     

                    thank you for all your help. Unfortunatly it seems like the function can not be disabled - maybe I'm doing it wrong. Here again is my latest script:

                     

                    #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) { return myString; } //{ { return 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();
                            }
                        }
                    }

                    • 7. Re: help - problem with a function
                      dugiedugie Community Member

                      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?

                      • 8. Re: help - problem with a function
                        Marc Autret MeganK

                        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

                        • 9. Re: help - problem with a function
                          dugiedugie Community Member

                          Dear Marc,

                           

                          thanks for the idea with the patch. The function is replacing the new lines/hard lines to the strings in quotes.

                          I see no chance to have this working with the function ReplaceReturnWithSpace.

                          Or is there a way to code the "// n" with another code - like "ascii 162/" or "&/&$&%n" or something like this?

                          I think the string value can not transport the code as is.

                           

                          And one more thing: The entire script is not working in cs4? Maybe after correcting the path info to the location of files?

                          I just wonder in case I'm upgrading to cs4.

                          • 10. Re: help - problem with a function
                            dugiedugie Community Member

                            Only one year later I can confirm that the xmp transfer via cs4 works like charme and is correct.

                            I wonder when Adobe will implemet this feature to it's package.

                             

                            There is one thing that is strange:

                             

                            Sometime we get an error: 1000

                            XMP Exception: OpenFile returned false

                             

                            Line 65

                            xmpFile = new XMPFile(iFile.fsName,XMPConst.Unknown, XMPConst.OPEN_FOR_UPDATE);

                             

                            I assume the system is trying to write informations to an image it's already working or or the filesystem is doning something?

                             

                            But besides this error it is great.

                             

                            Another idea to enhnace this script: Is it possible to readout the indesign paragraph style to place text from a selected text box into a specific xmp target? I'm thinking about a way to use character or paragraph styles to format the titel, description and a copyright. So it would be great to parse this formated text to the specific xmp entrie ... just a thought.

                            • 11. Re: help - problem with a function
                              Marijan Tompa MeganK

                              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