6 Replies Latest reply on Mar 2, 2018 3:46 AM by pseudonym

    Photoshop Scripting - Update Layers

    pseudonym Level 1

      Hi there,

       

      I am writing my first few Photoshop scripts and cannot figure out what would seem trivial tasks to do manually.

       

      Firstly, how do you copy smart filters from sourceLayerRef to destLayerRef?

       

      Secondly, is there a way to update a layer's pixels in place, preserving all other properties like, blend mode, opacity, layer effects, layer masks etc? I was hoping for something like destLayerRef.channels = sourceLayerRef.channels (or .rgb, .pixels, . contents?) but can only see copy & paste which is error prone when a layer mask is present.

       

      Finally, how do you reference a sourceLayerRef's mask (raster)?

       

      As an aside, I am familiar with scripting (javascript, php & maxscript) for other applications but have found the methods exposed to extendscript tend to be rather limited and getting complex tasks done often relies on the use of the ScriptListener plugin to create strange non-human readable actions. Does anyone else think that or am I going about my scripts in the wrong way?

       

      Hope someone can get me on the right track!

       

      Cheers,
      Olly

        • 1. Re: Photoshop Scripting - Update Layers
          r-bin Level 5

          On the first question I can offer

           

          dup_layer_fx(sourceLayerRef.id, destLayerRef.id); // in CS6 does not work (id is undefined)
          
          function dup_layer_fx(src_id, dst_id)
              {
              try
                  {
                  var d = new ActionDescriptor();
          
                  var r = new ActionReference();
                  r.putClass(stringIDToTypeID("filterFX"));
                  r.putIdentifier(stringIDToTypeID("layer"), src_id);
                  d.putReference(stringIDToTypeID("target"), r );
          
                  var r = new ActionReference();
                  r.putIdentifier(stringIDToTypeID("layer"), dst_id );
                  d.putReference(stringIDToTypeID("to"), r);
          
                  executeAction(stringIDToTypeID("duplicate"), d, DialogModes.NO );
                  }
              catch (e) { alert(e) }
              }
          

           

          For the rest I do not understand what you meant.

          Reformulate the questions.

          1 person found this helpful
          • 2. Re: Photoshop Scripting - Update Layers
            pseudonym Level 1

            Thank you r-bin - I will try that.

             

            To try again for question 2 & 3: I am trying to update layers (LayerKind.NORMAL) in a PSD with layers from a render file with the same name. I thought the easiest way to achieve this would be to update the content (pixels) of each layer so all other layer properties remain intact ie opacity, layer mask, blend mode. Maybe it is easier to copy the properties of the old layer to the new layer instead.

             

            I also would like to know how to address a layer's mask so I can copy it from one layer to another, something like oldLayerRef.mask = newLayerRef.mask maybe? If not how do make a layer's mask active so you can paste into it from the clipboard?

             

            All suggestions welcome!

            • 3. Re: Photoshop Scripting - Update Layers
              r-bin Level 5

              On the last question you can also use the code from Action Magager obtained with the ScriptListener plugin.

               

              dup_layer_mask(sourceLayerRef.id, destLayerRef.id); // in CS6 does not work (id is undefined in DOM)
              
              /////////////////////////////////////////////////////////
              function dup_layer_mask(src_id, dst_id)
                  {
                  try
                      {
                      var d = new ActionDescriptor();
                      d.putClass(stringIDToTypeID("new"), stringIDToTypeID("channel"));
              
                      var r = new ActionReference();
                      r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("mask"));
                      r.putIdentifier(stringIDToTypeID("layer"), src_id );
                      d.putReference(stringIDToTypeID("using"), r );
                      d.putBoolean(stringIDToTypeID("duplicate"), true );
              
                      var r = new ActionReference();
                      r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("mask"));
                      r.putIdentifier(stringIDToTypeID("layer"), dst_id);
                      d.putReference(stringIDToTypeID("at"), r );
              
                      executeAction(stringIDToTypeID("make"), d, DialogModes.NO );
                      }
                  catch (e) { alert(e) }
                  }
              
              /////////////////////////////////////////////////////////
              function has_layer_mask(layer_id)
                  {
                  try
                      {
                      var r = new ActionReference();
                      r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("hasUserMask"));    
                      r.putIdentifier(stringIDToTypeID("layer"), layer_id);
              
                      var d = executeActionGet(r);
              
                      if (!d.hasKey(stringIDToTypeID("hasUserMask"))) return false;
                      return d.getBoolean(stringIDToTypeID("hasUserMask"));
                      }
                  catch (e) { throw(e); }
                  }
              
              /////////////////////////////////////////////////////////
              function del_layer_mask(layer_id, apply)
                  {
                  try {
                      if (!has_layer_mask(layer_id)) return;
              
                      select_layer_mask(layer_id); 
              
                      var r = new ActionReference();
                      r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("mask"));
              
                      var d = new ActionDescriptor();
                      d.putReference(stringIDToTypeID("target"), r);
              
                      if (apply) d.putBoolean(stringIDToTypeID("apply"), true);
              
                      executeAction(stringIDToTypeID("delete"), d, DialogModes.NO);
                      }
                  catch (e) { throw(e); }
                  }   
              
              /////////////////////////////////////////////////////////
              function select_layer_mask(layer_id)
                  {
                  try { 
                      var r = new ActionReference();
                      r.putIdentifier(stringIDToTypeID("layer"), layer_id);
              
                      var d = new ActionDescriptor();
                      d.putReference(stringIDToTypeID("target"), r);
                      d.putBoolean(stringIDToTypeID("makeVisible"), false);
              
                      executeAction(stringIDToTypeID("select"), d, DialogModes.NO);
              
                      var r = new ActionReference();
                      r.putEnumerated(stringIDToTypeID("channel"), stringIDToTypeID("channel"), stringIDToTypeID("mask"));
              
                      var d = new ActionDescriptor();
                      d.putReference(stringIDToTypeID("target"), r);
                      d.putBoolean(stringIDToTypeID("makeVisible"), false);
              
                      executeAction(stringIDToTypeID("select"), d, DialogModes.NO);
                      }
                  catch (e) { throw(e); } 
                  }
              

               

               

              In the matter of updating the layer. Unclear. How are you going to update the pixels?

              If this is a smart object, then updating (replacing) the content does not affect the masks and blending modes. If this is a new layer, then you need to copy the mask and effects.

               

              The function copies fx to the clipboard if the layer has effects or a non-standard mode, even the opacity != 100

              If returns 'true' you can use fx_paste()

               

              ////////////////////////////////////////////////////////////////////////////////////////////
              function fx_copy() 
                  {       
                  try { executeAction( stringIDToTypeID("copyEffects"), undefined, DialogModes.NO ); } catch (e) { return false; }
              
                  return true;
                  }
              
              ////////////////////////////////////////////////////////////////////////////////////////////
              function fx_paste()
                  {       
                  try { 
                      var d = new ActionDescriptor();
                      d.putBoolean(stringIDToTypeID( "allowPasteFXOnLayerSet" ), true);
              
                      executeAction(stringIDToTypeID("pasteEffects"), d, DialogModes.NO );
                      }
                  catch (e) { throw(e); }
                  }
              
              1 person found this helpful
              • 4. Re: Photoshop Scripting - Update Layers
                pseudonym Level 1

                Thank you r-bin you are a legend - these are a really big help!

                 

                Is there a way to test if a layer has smart filters before attempting to copy them to the destLayerRef?

                 

                Thanks again,

                Olly

                • 5. Re: Photoshop Scripting - Update Layers
                  r-bin Level 5

                  OK. You can use the following functions.

                   

                  /////////////////////////////////////////////////////////  
                  function get_filter_fx_count(layer_id)  
                      {  
                      try  
                          {  
                          var r = new ActionReference();  
                          r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("smartObject"));      
                          r.putIdentifier(stringIDToTypeID("layer"), layer_id);  
                    
                          var d = executeActionGet(r);  
                    
                          if (!d.hasKey(stringIDToTypeID("smartObject"))) return 0;  
                  
                          d = d.getObjectValue(stringIDToTypeID("smartObject"));
                  
                          if (!d.hasKey(stringIDToTypeID("filterFX"))) return 0;  
                  
                          return d.getList(stringIDToTypeID("filterFX")).count;  
                          }  
                      catch (e) { throw(e); }  
                      }  
                  
                  /////////////////////////////////////////////////////////  
                  function del_filter_fx(layer_id)  
                      {  
                      try  
                          {  
                          if (!get_filter_fx_count(layer_id)) return; 
                  
                          var r = new ActionReference();  
                          r.putClass( stringIDToTypeID("filterFX" ));
                          r.putIdentifier(stringIDToTypeID("layer"), layer_id);  
                  
                          var d = new ActionDescriptor();
                          d.putReference(stringIDToTypeID("target"), r);  
                  
                          executeAction(stringIDToTypeID("delete"), d, DialogModes.NO);  
                          }  
                      catch (e) { throw(e); }  
                      }  
                  
                  1 person found this helpful
                  • 6. Re: Photoshop Scripting - Update Layers
                    pseudonym Level 1

                    Thanks r-bin, you are truly awesome!