14 Replies Latest reply on Aug 9, 2015 1:11 PM by BobXXYB

    Quickly retrieve Exif metadata

    BobXXYB

      I've got a script for Photoshop CC 2014 that makes some exposure value (EV) calculations based on Exif metadata in camera raw files and then adjusts the image exposure to the target EV.  I know that this information is quickly available in Bridge, but when I try to get the metadata in Photoshop, I have to use the Document.open() command, and that opens the file (which takes a long time) instead of just grabbing the Exif metadata.  I can get it quickly in a Bridge script, but I'm having a hard time embedding that stuff in a Photoshop-targeted script (the BridgeTalk stuff is a bit confusing to me, or it isn't working on my computer).

       

      I've also attempted to use "bridge.executeScript()", but the bridge object apparently is not available to scripts targeting Photoshop (or else something is messed up with my installation).  Bridge is available in bridge-targeted scripts only.

       

      Here's how it's working in Photoshop scripting (I include only the relevant part).

          for (var nfile = nstart; nfile < nstop; nfile++){
              var Name = File(testListing[nfile]).name.replace(/\.[^\.]+$/, '');
              var file = File(testListing[nfile].path + "/" + Name + ".JPG");
              if (file.exists){
                  app.open(file);
                  }
              else{
                  app.open(testListing[nfile]);
                  }
              var DocInfo = app.activeDocument.info;
              var docRef = app.activeDocument
             EV[nfile] = CalcEV (DocInfo, BaseISO);
              app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
              }

       

      (FYI, I use the jpeg file if it's there because Photoshop reads the exif from that file more quickly than it does from the raw file)

       

      Here's how it's working in Bridge scripting:

       

       

      firstfile = '7A7A5842.CR2';

      lastfile = '7A7A5843.CR2';

      var ExifProperty = 'exif:DateTimeOriginal';

      var ExifNamespace = 'http://ns.adobe.com/exif/1.0/';

      app.document.deselectAll();

      app.document.selectAll();

      var myThumbs = app.document.getSelection("cr2");

       

      var fstart = -999;

      var fend = -999;

       

      for (var n = 0; n < myThumbs.length; n++){

          if (myThumbs[n].name == firstfile) fstart = n;

          if (myThumbs[n].name == lastfile) fend = n;

      }

       

      var NumFiles = myThumbs.length;

       

      var fileThumbs = myThumbs.slice(fstart,fend);

      flen = fend-fstart+1;

       

      var EVarray = new Array(flen);

       

      for (var n = 0; n < fileThumbs.length; n++){

          var md = fileThumbs[n].metadata;

          ISO = md.read(ExifNamespace,'exif:ISOSpeedRatings');

          SS_string = md.read(ExifNamespace,'exif:ExposureTime');

          var test = SS_string.split("/");

          ShutterSpeed = test[0]/test[1];

          var Aperture_string = md.read(ExifNamespace,'exif:FNumber');

          if (Aperture_string == '') {

              var Aperture = Number(1.4); // assume Samyang set at f1.4

          }

          else {

              var test = Aperture_string.split("/");

              Aperture = test[0]/test[1];

          }

          var ISOadjust = Number(1.);

          EVarray[n] = Math.log(Math.pow(Aperture,2)/(ShutterSpeed*ISOadjust))/Math.LN2;

          $.writeln('ISO ',ISO,' SS ',SS,' Av ',Aperture, ' EV=',EVarray[n]);

      }

       

      app.document.deselectAll();

       

       

      "Done...";

        • 1. Re: Quickly retrieve Exif metadata
          BobXXYB Level 1

          Looks like I'm running up against a problem with BridgeTalk between Photoshop and Bridge.  Bridge is not returning messages for Bridgetalk.OnResult to evaluate.  I can use the supplied SndSendArray.jsx script and see that it works, but I cannot do it backwards.

          • 2. Re: Quickly retrieve Exif metadata
            Philip Cord Level 4

            This example works for me with CS6 (don't have CC)

            Create a "test" folder off the desktop and place a few cr2 files in the folder and try the following script.

             

            #target photoshop;
            main();
            function main(){
            var bt = new BridgeTalk();
            bt.target = "bridge";
            bt.body = "var ftn = " + getInfoFromBridge.toSource() + "; ftn();"; 
            bt.onResult = function( info ) { processInfo(eval( info.body ));}
            bt.send(10);
            };
            function processInfo(info){
            //do whatever to data
            alert(info.join('\n'));
            };
            
            function getInfoFromBridge(){
            var Info = [];
            app.document.thumbnail = Folder("~/desktop/test");
            app.document.deselectAll();
            var thumbs = app.document.getSelection("cr2");
            for(var a in thumbs){
            var t = new Thumbnail(thumbs[a]);    
            var md = t.synchronousMetadata;
            Info.push([[thumbs[a].name],[md.read( "http://ns.adobe.com/exif/1.0/","exif:FNumber")]]);
            }
            return Info.toSource();
            };
            
            
            • 3. Re: Quickly retrieve Exif metadata
              BobXXYB Level 1

              That looks promising.  I'll give it a shot when I'm back at my home desktop this evening.

               

              There's a lot about Javascript I don't know.  Certainly, it might be better to ask questions here much earlier in the process rather than spending most of the weekend frustrated .  Thanks for your help!  I'll let you know how it works.

              • 4. Re: Quickly retrieve Exif metadata
                BobXXYB Level 1

                Philip,

                 

                The script worked mostly as intended.  On the first try, the alert box is empty, but on the second try, it worked.  It seems Bridge needs to be on the folder at the beginning of the script.  If it has to change folders to display /desktop/test in the content pane, it doesn't get the exif info back to Photoshop.  I'm thinking there has to be another function, maybe a call back function, to get Bridge to the right place before getting the info.

                 

                I'll have to look into the Info data type (?) and the "push" and "join" methods, which I have not tried before. For some reason, the values returned from functions I've used did not get back to Photoshop, but there's a lot about the scripting that I don't understand.

                 

                Thanks for your help!

                 

                [edit] I now realize Info is an Array object that has "push" and "join" methods.  Still not sure what I was doing wrong before, but maybe it simply not putting a "return" statement at the end of the function.

                 

                -Bob

                • 5. Re: Quickly retrieve Exif metadata
                  BobXXYB Level 1

                  I was doing the following wrong:

                  1) not making sure the returned object was a string

                  2) not being aware of the timeout value in bt.send(timeout_value)

                  3) using $.writeln commands in the bt.body.  They seem to hang the execution of the function to be evaluated.

                   

                  Now, I'm wondering if there's any way to get the result of the execution of the script back into the main() function.  For now, there seems to be no way of extracting it from the bt.onResult function unless you write it out to a file.

                   

                  -Bob

                  • 6. Re: Quickly retrieve Exif metadata
                    Philip Cord Level 4

                    Hi Bob, if Bridge was closed then no info would be returned, so make sure Bridge is running.

                     

                    Here is the script with slight modifications showing how to process the data in the main function.

                     

                    #target photoshop;
                    main();
                    function main(){
                    var bt = new BridgeTalk();
                    cameraRawData = new Object();
                    bt.target = "bridge";
                    bt.body = "var ftn = " + getInfoFromBridge.toSource() + "; ftn();"; 
                    bt.onResult = function( returnedData ) {  cameraRawData = eval( returnedData.body );}
                    bt.onError = function( sumatWentWrong ) {  alert(sumatWentWrong.body);}
                    bt.send(10);
                    //If you get here all should be well and you can process the data
                    for(var a = 0; a< cameraRawData.Name.length; a++){
                    $.writeln(cameraRawData.Name[a] + " - " + cameraRawData.FNumber[a]);
                    }
                    };
                    
                    function getInfoFromBridge(){
                    /* all comments in this function must be in this format ! */
                    Info = {}; /* new Object, can be written as var Info = new Object(); */
                    /* create new arrays within the object */
                    Info.Name = new Array();
                    Info.FNumber = new Array();
                    /* change folder to */
                    app.document.thumbnail = Folder("~/desktop/test");
                    app.document.deselectAll();
                    /*get  a list of all cr2 documents */
                    var thumbs = app.document.getSelection("cr2");
                    for(var a in thumbs){
                    var t = new Thumbnail(thumbs[a]);    
                    var md = t.synchronousMetadata;
                    /*populate the arrays */
                    Info.Name.push(thumbs[a].name); 
                    Info.FNumber.push(md.read( "http://ns.adobe.com/exif/1.0/","exif:FNumber"));
                    }
                    return Info.toSource();
                    };
                    
                    
                    1 person found this helpful
                    • 7. Re: Quickly retrieve Exif metadata
                      BobXXYB Level 1

                      Thanks!  I'll give that a try.

                      • 8. Re: Quickly retrieve Exif metadata
                        BobXXYB Level 1

                        This definitely works and I've used that style of code.

                         

                        For some reason, Bridge doesn't always want to deliver the information.  However, I can get around that by having my script try again until it successfully retrieves the information.  That seems to work.

                        • 9. Re: Quickly retrieve Exif metadata
                          Philip Cord Level 4

                          You could try increasing the timeout in the bt.send() to see if it improves things Bob, glad you have it working now!

                          • 10. Re: Quickly retrieve Exif metadata
                            BobXXYB Level 1

                            I tried increasing the timeout, but for some reason, Bridge gets in a "Not Responding" mode, so I have to let it timeout, wait a couple seconds, then try again.  When it decides to deliver the information, it's very fast.

                            • 11. Re: Quickly retrieve Exif metadata
                              xbytor2 Level 4

                              I wrote a js file that handles a lot of variant ways of dealing with metadata:

                              http://ps-scripts.cvs.sourceforge.net/viewvc/ps-scripts/xtools/xlib/metadata.js

                               

                              You can pass the Metadata constructor a Document, File, (XML) String, or XMPMeta and retrieve metadata fairly easily.

                              It also has an strf method so you can do stuff like:

                               

                                var doc = app.activeDocument;
                                var md = new Metadata(doc);
                                var str3 = "%X{xap:CreateDate} %I{Author} %X{dc:format}";
                                alert(md.strf(str3));
                              

                               

                               

                              The strf function requires a couple of strf functions from stdlib.js, and I should probably document the interesting stuff, but everything is there.

                               

                              There is not Bridge support because using File is probably as fast or faster and doesn't need to have Bridge running.

                               

                              But I may add Bridge support just because it might be an interesting exercise.

                              1 person found this helpful
                              • 12. Re: Quickly retrieve Exif metadata
                                BobXXYB Level 1

                                Thanks!  I will give that a try and see if it works better than Bridge (Bridge often is slow to respond-- it could be something I'm doing in my script, but Bridge tends to be slow).

                                • 13. Re: Quickly retrieve Exif metadata
                                  xbytor2 Level 4

                                  One quick note: If you want metadata.js to work with Files, you need to first //@include this file:

                                  http://ps-scripts.cvs.sourceforge.net/viewvc/ps-scripts/xtools/xlib/XMPTools.jsx

                                   

                                  If handles all of the code that interfaces with XMPScript.

                                   

                                  -X

                                  1 person found this helpful
                                  • 14. Re: Quickly retrieve Exif metadata
                                    BobXXYB Level 1

                                    I upgraded my O.S. hard drive to a solid state drive, and I also upgraded to Windows 8 (and again to Windows 10 last week).  Bridge seems to pass the information much better now.