5 Replies Latest reply on Aug 5, 2013 5:42 PM by Michael L Hale

    Storing per project script data ?

    Maxim Veksler

      Hello,

       

      I have configuration for user selections that I need to store on a per project basis, things like files paths and co.

       

      Where this data should be kept, I obviosuly can keep it in a seperate file next to the psd, or inside photoshop registry but I'm looking for a better solution of storing the data inside the psd file itself.

       

      Is there an API solution for this, or should I be looking into hacks such as finding an unused XMP field and storing the data there?

       

      What is important to me is that this data will survive application reboots.

      Second priority is the situation that a user emails the psd to someone else, I would like this data to be present there as well.

       

      Any suggestions?

        • 1. Re: Storing per project script data ?
          Michael L Hale Level 5

          If the goal is keeping the data with the file I would use XMP. And I don't think it would be a 'hack' if you created a custom name space for the data instead of using some existing field. I think the data would be 'safer' in the metadata. It would be less likley to be lost. It still could be removed but the user would have to intend to remove the metadata.

           

          You can use an external file but there would be the problem of keeping that file with it's matching document file. And the user may delete the data file thinking it's un-needed.

           

          You can use Photoshop.customOptions. But that only works with one install of Photoshop and can be lost it the user resets the Photoshop preferences.

          • 2. Re: Storing per project script data ?
            xbytor2 Level 4

            Another option (which should work well if it's not a large amount of data) is to store the data in a hidden text layer. You could also use the layer's xmpMetadata field.

            • 3. Re: Storing per project script data ?
              Michael L Hale Level 5

              The advantage of using the document metadata is it is easier to access without opening the document. But if the data only needs to be access when the document is open a text layer would be eaiser to read. And layer metadata is almost always un-used so there would be more space if you need to store a lot of data.

              • 4. Re: Storing per project script data ?
                Maxim Veksler Level 1

                This is great feedback,

                 

                This is indeed metadata and I do not need, actually prefer, the user to not be exposed to it at all.

                Layer XMP metadata is interesting appraoch, but since I'm not a photoshop user per se, could you please explain how to create a hidden layer in photoshop ?

                 

                I wouldn't care the user accesing this layer, should he chooses too it only needs to be hidden from the "default" interface, to not create clutter on the screen and in the working environment.

                 

                Does CompsLayer can hold the same XMP metadata as Layer (from what I've researched - it can't) ?

                 

                 

                -- EDIT:

                 

                I would appreciate samples of the discuced topics. If there are none I will provide once I work them out for future searches and if there are some I would appreciate them being linked here to shorthen my development time. Thank you.

                • 5. Re: Storing per project script data ?
                  Michael L Hale Level 5

                  Unless Xbytor knows something about layers that I don't I think when he said 'a hidden text layer' he meant a normal text layer with the visibility turned off. The layer would still be in the layers panel.

                   

                  I am not sure what you mean by 'CompsLayer'. If you mean Layer Comps, then no layer comps are not layers so don't have layer metadata.

                   

                  Here is an example of using reading/writing layer metadata.

                   

                  loadXMPLibrary();
                  try{
                  var layerXMP = new XMPMeta( activeDocument.activeLayer.xmpMetadata.rawData );// get the object
                  }catch(e){ 
                      var layerXMP = new XMPMeta();// layer did not have metadata so create new
                  }
                  var lastUpdated = getLayerChangedDate();// get the date. Photoshop updates time so no need to set.
                  setDescMetadata( 'Desc' );// set desc
                  var comment = layerXMP.getProperty( XMPConst.NS_EXIF, "userComment" );// get comment
                  var count = layerXMP.countArrayItems( XMPConst.NS_DC, "description"  );// get the number of items
                  if ( count == 0 ) {
                      layerXMP.getArrayItem( XMPConst.NS_DC, "description", 1 );
                  }
                  setCommMetadata('comment');// set comment
                  lastUpdated = getLayerChangedDate();// get the date. Photoshop updates time so no need to set.
                  alert(lastUpdated);
                  
                  unloadXMPLibrary();
                  
                  // these function adapted from PerLayerMetdata.jsx -Copyright 2008 Adobe Systems Incorporated
                  // to use these functions are from the Photoshop Panel Developer's Guide.
                  function loadXMPLibrary(){
                      if ( !ExternalObject.AdobeXMPScript ){
                          try{
                              ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
                          }catch (e){
                              alert("Can't load XMP Script Library");
                              return false;
                          }
                      }
                      return true;
                  };
                  /**
                      The function unloads the XMP Script Library.
                  */
                  function unloadXMPLibrary(){
                      if( ExternalObject.AdobeXMPScript ) {
                          try{
                              ExternalObject.AdobeXMPScript.unload();
                              ExternalObject.AdobeXMPScript = undefined;
                          }catch (e){
                              alert("Can't unload XMP Script Library");
                          }
                      }
                  };
                  function setDescMetadata(desc){
                      if( app.activeDocument.activeLayer.isBackgroundLayer ){
                          alert( 'Can not place metadata on a background layer.');
                      } else {
                          var xmp;
                          if (desc == "")
                              desc = " ";
                              
                          try{
                              xmp = new XMPMeta( app.activeDocument.activeLayer.xmpMetadata.rawData );
                          } catch( e ) {
                              xmp = new XMPMeta();
                          }
                      
                          try{
                              if( xmp.countArrayItems( XMPConst.NS_DC, "description" ) == 0 ){
                                  xmp.appendArrayItem( XMPConst.NS_DC, "description", null, XMPConst.PROP_IS_ARRAY, XMPConst.ARRAY_IS_ORDERED );
                                  xmp.insertArrayItem( XMPConst.NS_DC, "description", 1, desc );
                              } else {
                                  xmp.setArrayItem( XMPConst.NS_DC, "description", 1, desc );
                              }
                          } catch( e ) {
                              alert( 'Unable to place description metadata on selected layer.\n' + e );
                          }
                          app.activeDocument.activeLayer.xmpMetadata.rawData = xmp.serialize();
                      }
                  };
                  function setCommMetadata(comm){
                      if( app.activeDocument.activeLayer.isBackgroundLayer){
                          alert( 'Can not place metadata on a background layer.' );
                      } else {
                          var xmp;
                          if ( comm == "" )
                              comm = " ";
                              
                          try{
                              xmp = new XMPMeta( app.activeDocument.activeLayer.xmpMetadata.rawData );
                          } catch( e ) {
                              xmp = new XMPMeta();
                          }
                          try{
                              xmp.setProperty( XMPConst.NS_EXIF, "userComment", comm );
                          } catch( e ) {
                              alert( 'Unable to place metadata on selected layer.\n' + e );
                          }
                          app.activeDocument.activeLayer.xmpMetadata.rawData = xmp.serialize();
                      }
                  };
                  function getLayerChangedDate(){
                      var ref = new ActionReference();
                      ref.putProperty( charIDToTypeID( 'Prpr' ), stringIDToTypeID( "metadata" ) );
                      ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
                      var desc = executeActionGet( ref );
                      
                      if ( desc.hasKey( stringIDToTypeID( "metadata" ) ) ){
                          desc = executeActionGet( ref ).getObjectValue( stringIDToTypeID( "metadata" ) );
                          var timeInSeconds = desc.getDouble( stringIDToTypeID("layerTime") );
                          var d = new Date();
                          d.setTime( timeInSeconds * 1000.0 );
                          return d.toLocaleString();
                      }
                  };