4 Replies Latest reply on Mar 3, 2016 1:07 AM by cbuliarca

    create masks at all levels

    Level 1

      Hello to all

      I have a problem I can not solve

      I looked in the forum but have not found answers

       

       

      the problem is the following:

      I have a lot of psd files that have many levels

      I would like to add to all of these levels a white mask

      and if at some level is already present does not have to update it

       

       

      you think you can do it?

       

       

      thank you

        • 1. Re: create masks at all levels
          cbuliarca Level 3

          by level you mean Adjusment Layer Levels? If so this script will create a white mask for every levels layer in you opened document:

          app.activeDocument.suspendHistory("BCM_aMaskForEveryLevels", "main()");
          function main(){
            var currentSlections = getSelectedLayersIds();
            xx = false;
            var ref0 = new ActionReference();
            ref0.putProperty( charIDToTypeID( 'Prpr' ), stringIDToTypeID('numberOfLayers') );
            ref0.putEnumerated( charIDToTypeID( "Dcmn" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
            var desc0 = executeActionGet(ref0);
            var i = desc0.getInteger(stringIDToTypeID('numberOfLayers'));
            var idWithMask = null;
            for(i; i > 0 ; i--){
              ref = new ActionReference();
              ref.putIndex( charIDToTypeID( 'Lyr ' ), i );
              var desc = executeActionGet(ref);
              var layerName = desc.getString(charIDToTypeID( 'Nm  ' ));
              var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));
              var ls = desc.getEnumerationValue(stringIDToTypeID("layerSection"));
              ls = typeIDToStringID(ls);
              var vis = desc.getInteger(stringIDToTypeID( 'visible' ));
             
              if(isAdjusmentLayerLevelsByID(Id) == true){//if it's an levels layer
                if(hasMaskByID(Id) == false){//if it doesn't has a mask
                  if(idWithMask == null){//if it's the first then just select it and create a white mask
                    multiSelectByIDs(Id);
                    makeFirstMask();
                    idWithMask = Id;
                  }else{//duplicate from the first created mask
                    duplicateMaskByID(idWithMask, Id);
                  }
                }
              }
            }
            multiSelectByIDs(currentSlections);
          }
          function doesIdExists( id ){
            var res = true;
            var ref = new ActionReference();
            ref.putIdentifier(charIDToTypeID('Lyr '), id);
              try{var desc = executeActionGet(ref)}catch(err){res = false};
              return res;
          }
          function multiSelectByIDs(ids) {
            if( ids.constructor != Array ) ids = [ ids ];
              var layers = new Array();
              var id54 = charIDToTypeID( "slct" );
              var desc12 = new ActionDescriptor();
              var id55 = charIDToTypeID( "null" );
              var ref9 = new ActionReference();
              for (var i = 0; i < ids.length; i++) {
                if(doesIdExists(ids[i]) == true){// a check to see if the id stil exists
                    layers[i] = charIDToTypeID( "Lyr " );
                    ref9.putIdentifier(layers[i], ids[i]);
                }
              }
              desc12.putReference( id55, ref9 );
              var id58 = charIDToTypeID( "MkVs" );
              desc12.putBoolean( id58, false );
              executeAction( id54, desc12, DialogModes.NO );
          }
          
          
          function getSelectedLayersIds(){
            var idxs = getSelectedLayersIdx();
            var selectedLayersIds = [];
            for( var i=0;i<idxs.length;i++){
              selectedLayersIds.push(getIdfromIdx(idxs[i]));
            }
            return selectedLayersIds;
          }
          
          
          function hasBackground(){
            return app.activeDocument.layers[app.activeDocument.layers.length - 1].isBackgroundLayer;
          }
          function getIdfromIdx( idx ){// get the id from index
            var ref = new ActionReference();
            ref.putIndex(charIDToTypeID('Lyr '), idx);
              var desc = executeActionGet(ref);
                desc = desc.getInteger(charIDToTypeID("LyrI"));
                return desc;
          }
          
          
          function getSelectedLayersIdx(){
              var selectedLayers = new Array;
              var ref = new ActionReference();
              ref.putProperty(charIDToTypeID('Prpr'), stringIDToTypeID('targetLayers'));
              ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
              var desc = executeActionGet(ref);
              var add = 1;
              if(hasBackground()){add = 0}
              if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){
                    desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
                    var c = desc.count
                    var selectedLayers = new Array();
                    for(var i=0;i<c;i++){
                        selectedLayers.push(  (desc.getReference( i ).getIndex()) + add);
                    }
              }else{
                    var ref = new ActionReference();
                    ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'ItmI' ));
                    ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
                    srs = hasBackground()?executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' ))-1:executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' ));
                    selectedLayers.push( srs);
              }
              return selectedLayers;
          }
          
          
          function isAdjusmentLayerLevelsByID( id ){
            var rt = false;
            var ref = new ActionReference();
              ref.putIdentifier( charIDToTypeID ( "Lyr " ), id );
            var desc =  executeActionGet( ref );
            if (desc.hasKey( charIDToTypeID("Adjs")) == true){
                desc = desc.getList(charIDToTypeID('Adjs'));
                desc = desc.getObjectType(0);
                if( typeIDToCharID(desc) == 'Lvls'){
                  rt = true;
                }
            }
            return rt;
          }
          
          
          
          
          function hasMaskByID( id ){
            var ref = new ActionReference();
              ref.putIdentifier( charIDToTypeID ( "Lyr " ), id );
            var desc =  executeActionGet( ref );
            return desc.getBoolean(stringIDToTypeID('hasUserMask'))
          }
          
          
          
          
          function makeFirstMask( id ){
            var desc = new ActionDescriptor();
              desc.putClass( charIDToTypeID( "Nw  " ), charIDToTypeID( "Chnl" ) );
                  var ref = new ActionReference();
                  ref.putEnumerated( charIDToTypeID( "Chnl" ), charIDToTypeID( "Chnl" ), charIDToTypeID( "Msk " ) );
              desc.putReference( charIDToTypeID( "At  " ), ref );
              desc.putEnumerated( charIDToTypeID( "Usng" ), charIDToTypeID( "UsrM" ), charIDToTypeID( "RvlA" ) );
            executeAction( charIDToTypeID( "Mk  " ), desc, DialogModes.NO );
          
          
          }
          
          
          function duplicateMaskByID(sorceID, trgtID){
              var idMk = charIDToTypeID( "Mk  " );
                var desc102 = new ActionDescriptor();
                var idNw = charIDToTypeID( "Nw  " );
                var idChnl = charIDToTypeID( "Chnl" );
                desc102.putClass( idNw, idChnl );
                var idAt = charIDToTypeID( "At  " );
                    var ref90 = new ActionReference();
                    var idChnl = charIDToTypeID( "Chnl" );
                    var idChnl = charIDToTypeID( "Chnl" );
                    var idMsk = charIDToTypeID( "Msk " );
                    ref90.putEnumerated( idChnl, idChnl, idMsk );
                    ref90.putIdentifier(charIDToTypeID("Lyr "), trgtID);
                desc102.putReference( idAt, ref90 );
                var idUsng = charIDToTypeID( "Usng" );
                    var ref91 = new ActionReference();
                    var idChnl = charIDToTypeID( "Chnl" );
                    var idChnl = charIDToTypeID( "Chnl" );
                    var idMsk = charIDToTypeID( "Msk " );
                    ref91.putEnumerated( idChnl, idChnl, idMsk );
                    ref91.putIdentifier(charIDToTypeID("Lyr "), sorceID);
                desc102.putReference( idUsng, ref91 );
                var idDplc = charIDToTypeID( "Dplc" );
                desc102.putBoolean( idDplc, true );
            executeAction( idMk, desc102, DialogModes.NO );
          }
          
          • 2. Re: create masks at all levels
            Level 1

            Thanks for the ride

            unfortunately the levels are varied in nature

            there also levels of saturation color balance and more

            and even levels with images.

            • 3. Re: create masks at all levels
              c.pfaffenbichler Level 9

              You seem to be using the term "level" instead of "Layer".

              If one uses Photoshop in a language other than english and asks for assistance on these Fora it would be prudent to post screenshots right away to help avoid such misunderstandings.

              • 4. Re: create masks at all levels
                cbuliarca Level 3

                Like c.pfaffenbichler said your calling the Adjusment Layers as levels, anyway I understand what you need now, the script I've posted can be modified easily to put a mask to all the Adjusment Layers, but I won't do that..... I see this forum as a forum for people that want to learn and not as a forum where people comes to ask for some scripts. That's why I've taken the time to explain like I understood what each line of the script I've posted it's doing.... The others are more than welcome to complete the description if I didn't explained it well... I know that there are people with a lot experience here from whom I've learned a lot, and for that I'm forever grateful. So here it's the script with the comments for almost every line:

                 

                app.activeDocument.suspendHistory("BCM_aMaskForEveryLevels", "main()");//this line just creates one step in the history named BCM_aMaskForEveryLevels
                function main(){// the main function 
                  var currentSlections = getSelectedLayersIds();// store in a variable the selected layers so at the end of the script they could be reselected
                  // in the next 5 lines I am founding the number of the layers in the document
                  // with AM scripting layers doesn't have parents and childrens, and they have certain attributes that can be read in order to find out what kind of a layers they are
                  // the advantage of using AM in looping throw layers it's the fact that it's fast and you don't have to select the layer in order to find something about it
                  var ref0 = new ActionReference();//an action reference
                  ref0.putProperty( charIDToTypeID( 'Prpr' ), stringIDToTypeID('numberOfLayers') );// define one property for the reference in order to look only for that property later,
                  // without this upper line the resulting descriptor will be filled with a lot of information and if you have a lot of layers in the document this step could take a few seconds
                  ref0.putEnumerated( charIDToTypeID( "Dcmn" ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );// here the refence will be for the selected document, usualy when you use an putEnumerated you are getting the selected object
                  var desc0 = executeActionGet(ref0);//get's the descriptor for the reference
                  var i = desc0.getInteger(stringIDToTypeID('numberOfLayers'));// find the number of the layers in the document and put it to the variable i
                
                
                  var idWithMask = null;// this is a variable that will be used later in the script
                  for(i; i > 0 ; i--){//start the loop, at the start of the loop i is equal with the number of layers in the document, and with each itteration it's substracting 1 from i until, i will get to 0, then the loop will stop
                    ref = new ActionReference();// create a new reference
                    ref.putIndex( charIDToTypeID( 'Lyr ' ), i );// the index it's the position of the layer in the layer pallete, so here the script it's referenceing with each itteration of the loop each layer without selecting it 
                    var desc = executeActionGet(ref);//get the descriptor of the referenced layer
                    var layerName = desc.getString(charIDToTypeID( 'Nm  ' )); //this is how you get the name of the referenced layer
                    var Id = desc.getInteger(stringIDToTypeID( 'layerID' ));//this is how you get the id of the referenced layer, the id's are unique and they doesn't change
                    var ls = desc.getEnumerationValue(stringIDToTypeID("layerSection"));// this is how you can see if the referenced layer it's a group or not
                    ls = typeIDToStringID(ls);// There are 3 values that the layerSection can return: "layerSectionStart", "layerSectionContent", "layerSectionEnd"
                    // with AM you have a group like this:
                    //   ---- "layerSectionStart" -represented in the layer palette as the folder
                    //        "layerSectionContent" - any layer that's inside the group or outside the group
                    //        "layerSectionEnd" - you can't see this layer in the layer palette, but when you find one it means that it's the end of some group, and all the previous layers where inside that group.
                
                
                    var vis = desc.getInteger(stringIDToTypeID( 'visible' ));//how you get the visibility of of the referenced layer
                    
                    if(isAdjusmentLayerLevelsByID(Id) == true){//if it's an levels layer.... go to the decalartion of the function to see what it's doing
                      if(hasMaskByID(Id) == false){//if it doesn't has a mask, ...go to the decalartion of the function to see what it is doing
                        if(idWithMask == null){//when the script finds the first levels layer that doesn't have a mask, it will select it and create a mask for it 
                          multiSelectByIDs(Id);//select the layer by it's id
                          makeFirstMask();//make a mask, this function it's just copied from the scriptListenerLog
                          idWithMask = Id;// change the variable so now it will have the value of the id with the first white mask,
                          // I've done these 3 previous lines because I couldn't found a way to create a white mask by referencing the layer id, the only way it worked was just to create it by selecting it and record the creation of the mask
                          // also I'm storing the id of the first layer with the white mask because I want to duplicate the mask when finding other levels layers, this will make the script faster and it won't need to select the layer 
                        }else{//duplicate from the first created mask
                          duplicateMaskByID(idWithMask, Id);//I'm duplicating the white mask from the first layer, to the referenced layer that we know it's a levels layer because it's in the if
                        }
                      }
                    }
                  }
                  multiSelectByIDs(currentSlections);// now the loop was finished, all the script needs to do is to select back the layers that where selected before satrting the script
                }
                function doesIdExists( id ){//this function test to see if the id exists
                  var res = true;// the returning variable
                  var ref = new ActionReference();// create an reference
                  ref.putIdentifier(charIDToTypeID('Lyr '), id);// reference a layer by it's id
                    try{var desc = executeActionGet(ref)}catch(err){res = false};// if the layer doesn't exists it should give an error, when tring to get the descriptor for it, that's why I've put this in a try and catch
                    return res;// the returned value
                }
                function multiSelectByIDs(ids) { //this function select more than one layer by id's
                  if( ids.constructor != Array ) ids = [ ids ];//if the input it's not an array make an array with that single id
                    var layers = new Array();//create an empty array
                    var desc12 = new ActionDescriptor();// create a descriptor
                    var ref9 = new ActionReference();//create a reference
                    for (var i = 0; i < ids.length; i++) {// for each id in the input array
                      if(doesIdExists(ids[i]) == true){// check to see if the id still exists
                          layers[i] = charIDToTypeID( "Lyr " );//append a layer class to the layers array
                          ref9.putIdentifier(layers[i], ids[i]);//reference each layer by the id
                      }
                    }
                    desc12.putReference( charIDToTypeID( "null" ), ref9 );//put the reference to the descriptor
                    executeAction( charIDToTypeID( "slct" ), desc12, DialogModes.NO );//this executes the select action by using the descriptor that reference the layers by id
                }
                
                
                function getSelectedLayersIds(){// this function get's the selected layers id's
                  var idxs = getSelectedLayersIdx();// first it get's the indexes because in CS4 to CS6 there is no way to get the id's of the selected layers, only the indexes
                  var selectedLayersIds = [];//create an empty Array that willbe the returned array
                  for( var i=0;i<idxs.length;i++){// for each index 
                    selectedLayersIds.push(getIdfromIdx(idxs[i]));//put in the returned array the id's by getting the id from index
                  }
                  return selectedLayersIds;//return the array with id's
                }
                
                
                function hasBackground(){//this function is looking to see if there is a background locked layer in the document
                  return app.activeDocument.layers[app.activeDocument.layers.length - 1].isBackgroundLayer;
                }
                function getIdfromIdx( idx ){// get the id from index
                  var ref = new ActionReference();//create an reference
                  ref.putIndex(charIDToTypeID('Lyr '), idx);//reference layer by index
                    var desc = executeActionGet(ref);//get the descriptor for the referenced layer
                      desc = desc.getInteger(charIDToTypeID("LyrI"));//get the id from the descriptor
                      return desc;//return the id
                }
                
                
                function getSelectedLayersIdx(){//function to get the indexes of the selected layers
                     var selectedLayers = new Array;//create an empty array that will be returned by the function
                     var ref = new ActionReference();//create reference
                     ref.putProperty(charIDToTypeID('Prpr'), stringIDToTypeID('targetLayers'));//put first the property of targetLayers in the reference
                     ref.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );//put the current document as the referenced class
                     var desc = executeActionGet(ref);//get the descriptor of the reefnced current document, but in the descript there is only the targetLayers
                     var add = 1;//this is beacuse when there is no background layer the index of the selected layers has needs an offset of one
                     if(hasBackground()){add = 0}// if there is a background layer the offest is not needed
                     if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){//this is to find out if the document descriptor has the targetLayers key, 
                      //if it doesn't exists it menas that only one layer is selected, even when there is no layer selected, Photoshop retun as selected the first layer in the layers palette
                          desc = desc.getList( stringIDToTypeID( 'targetLayers' ));//get the targetLayers list
                          var c = desc.count //find how many references are in the list
                          for(var i=0;i<c;i++){// for each reference in the list
                               selectedLayers.push(  (desc.getReference( i ).getIndex()) + add);//get the index
                          }
                     }else{// if there's only one selected layer or none
                          var ref = new ActionReference();//create an reference
                          ref.putProperty( charIDToTypeID('Prpr') , charIDToTypeID( 'ItmI' ));//put the index property for the
                          ref.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );//selected layer
                          srs = hasBackground()?executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' ))-1:executeActionGet(ref).getInteger(charIDToTypeID( 'ItmI' ));//if there is a backgorundLayer get the index and substract one, if not just get the index
                          selectedLayers.push( srs);//put the selected index in the array that will be returned
                     }
                     return selectedLayers;//return the array with the indexes for the selected layers
                }
                
                
                function isAdjusmentLayerLevelsByID( id ){//this function is checking to see if the a layer referenced by it's id is a levels adjutment layer
                  var rt = false;//first make the value to be returned false
                  var ref = new ActionReference(); //create a reference
                    ref.putIdentifier( charIDToTypeID ( "Lyr " ), id );//reference a layer by id
                  var desc =  executeActionGet( ref );//get the descriptor for the referenced layer
                  if (desc.hasKey( charIDToTypeID("Adjs")) == true){//if the key "Adjs" is present in the descriptor, it means that the layer is an adjusment layer
                      desc = desc.getList(charIDToTypeID('Adjs'));//here we are digging more in the descriptor to see what kind of an adjusment layer it is
                      desc = desc.getObjectType(0);//we are getting the first value from the list
                      if( typeIDToCharID(desc) == 'Lvls'){//if that value is "Lvls". it means that it is an Levels Adjusment Layer
                        rt = true;//change the returned value to true
                      }
                  }
                  return rt;// return the value
                }
                
                
                
                
                function hasMaskByID( id ){//function to see if the layer referenced by an id has a mask
                  var ref = new ActionReference();//create reference
                    ref.putIdentifier( charIDToTypeID ( "Lyr " ), id );//reference the layer by the id
                  var desc =  executeActionGet( ref );//get the descriptor for the referenced layer
                  return desc.getBoolean(stringIDToTypeID('hasUserMask'))//return true of false if there is a mask or not
                }
                
                
                
                
                function makeFirstMask( id ){//create a white mask for the selected layer, this sript is copyed from the script listener log
                  var desc = new ActionDescriptor();//create a descriptor
                    desc.putClass( charIDToTypeID( "Nw  " ), charIDToTypeID( "Chnl" ) );
                        var ref = new ActionReference();
                        ref.putEnumerated( charIDToTypeID( "Chnl" ), charIDToTypeID( "Chnl" ), charIDToTypeID( "Msk " ) );
                    desc.putReference( charIDToTypeID( "At  " ), ref );
                    desc.putEnumerated( charIDToTypeID( "Usng" ), charIDToTypeID( "UsrM" ), charIDToTypeID( "RvlA" ) );
                  executeAction( charIDToTypeID( "Mk  " ), desc, DialogModes.NO );
                
                
                }
                
                
                function duplicateMaskByID(sorceID, trgtID){//function to duplicate the mask from one id to other, also a function copyed from script listener log, and changed a bit
                    var idMk = charIDToTypeID( "Mk  " );
                      var desc102 = new ActionDescriptor();
                      var idNw = charIDToTypeID( "Nw  " );
                      var idChnl = charIDToTypeID( "Chnl" );
                      desc102.putClass( idNw, idChnl );
                      var idAt = charIDToTypeID( "At  " );
                          var ref90 = new ActionReference();
                          var idChnl = charIDToTypeID( "Chnl" );
                          var idChnl = charIDToTypeID( "Chnl" );
                          var idMsk = charIDToTypeID( "Msk " );
                          ref90.putEnumerated( idChnl, idChnl, idMsk );
                          ref90.putIdentifier(charIDToTypeID("Lyr "), trgtID);//this line I've changed to reference the target layer id, and not the name like it was in the script listener log
                      desc102.putReference( idAt, ref90 );
                      var idUsng = charIDToTypeID( "Usng" );
                          var ref91 = new ActionReference();
                          var idChnl = charIDToTypeID( "Chnl" );
                          var idChnl = charIDToTypeID( "Chnl" );
                          var idMsk = charIDToTypeID( "Msk " );
                          ref91.putEnumerated( idChnl, idChnl, idMsk );
                          ref91.putIdentifier(charIDToTypeID("Lyr "), sorceID);//this line I've changed to reference the source layer id, and not the name like it was in the script listener log
                      desc102.putReference( idUsng, ref91 );
                      var idDplc = charIDToTypeID( "Dplc" );
                      desc102.putBoolean( idDplc, true );
                  executeAction( idMk, desc102, DialogModes.NO );
                }