Help getting a script started.

Anyone, especially newbies, asking for help with Photoshop Scripting and Photoshop Automation - as opposed to those contributing to discussion about an aspect of Photoshop Scripting

Moderators: Tom, Kukurykus

j_forrester

Help getting a script started.

Post by j_forrester »

A started to try and write my first script recently. I have researched for hours and hours but with no real luck on how to write what I need and even more so how the script flows from one prompt to another. I have also played around with the Extend script toolkit and scriptlog.jsx file which it spits out. The log itself to include so much extra is quite confusing as it seems info, when I try not to include the parts I don't feel I need the script no longer works.

All I need really is to know the code for

- selecting a specific layer based on it's layer name and if possible to select a layer if it included "xxxx" and "yyyy" in it's layer name. Either would really help me to understand how this is written.

- selecting separate RGB channnels and applying these individual channel selections to existing groups. i.e select a layer "copper mask" select blue channel and apply to a existing group called "copper set". The closest I got was trying "getByName" but obviously if correct I was not adding the correct "pre snippet"or post "snippet" to the rest of the code.

- it would also be very helpful to know how to create a new group and name it.

With all these bits of code I feel I would be able to play around and hopefully put together the final script.


I would really appreciate any help with this. Many thanks in advance
pfaffenbichler

Help getting a script started.

Post by pfaffenbichler »

- it would also be very helpful to know how to create a new group and name it.
Code: Select allvar myDocument = app.activeDocument;
var theSet = myDocument.layerSets.add();
theSet.name = "a layer group";

selecting separate RGB channnels and applying these individual channel selections to existing groups. i.e select a layer "copper mask" select blue channel and apply to a existing group called "copper set".
Code: Select allmyDocument.selection.load(myDocument.channels[2]);
addLayerMask ();
////// add layer mask //////
function addLayerMask () {
var idMk = charIDToTypeID( "Mk  " );
var desc168 = new ActionDescriptor();
var idNw = charIDToTypeID( "Nw  " );
var idChnl = charIDToTypeID( "Chnl" );
desc168.putClass( idNw, idChnl );
var idAt = charIDToTypeID( "At  " );
var ref99 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idChnl = charIDToTypeID( "Chnl" );
var idMsk = charIDToTypeID( "Msk " );
ref99.putEnumerated( idChnl, idChnl, idMsk );
desc168.putReference( idAt, ref99 );
var idUsng = charIDToTypeID( "Usng" );
var idUsrM = charIDToTypeID( "UsrM" );
var idRvlS = charIDToTypeID( "RvlS" );
desc168.putEnumerated( idUsng, idUsrM, idRvlS );
executeAction( idMk, desc168, DialogModes.NO );
};
As for making »copper set« the activeLayer before it would be best if you set it up as a variable on creation and then you could easily select it; in my example that would be:
Code: Select allmyDocument.activeLayer = theSet;

if possible to select a layer if it included "xxxx" and "yyyy" in it's layer name.
Code: Select allvar theLayers = collectLayers (myDocument);
var xxxxLayers = new Array;
for (var m = 0; m < theLayers.length; m++) {
   var thisLayer = theLayers[m];
   if (thisLayer.name.indexOf("xxxx") != -1) {
      xxxxLayers.push(thisLayer);
      };
   };
if (xxxxLayers.length == 1) {
   myDocument.activeLayer = xxxxLayers[0]
   }
else {
   alert ("more than one layer meets the requirement, unclear which one to select")
   };
////// function collect all layers //////
function collectLayers (theParent) {
   if (!allLayers) {
      var allLayers = new Array}
   else {};
   for (var m = theParent.layers.length - 1; m >= 0;m--) {
      var theLayer = theParent.layers[m];
// apply the function to layersets;
      if (theLayer.typename == "ArtLayer") {
         allLayers.push(theLayer)
         }
      else {
         allLayers = allLayers.concat(collectLayers(theLayer))
// this line includes the layer groups;
         allLayers.push(theLayer);
         }
      };
   return allLayers
};

Hope that helps.
Others may possibly be able to provide more concise code, though.
j_forrester

Help getting a script started.

Post by j_forrester »

pfaffenbichler,

Cant thank you enough. I will have a go at putting together the script later today.

Like I said previously with no prior knowledge it can be difficult at first. When I look through a script now I am starting to understand more. My problem is probably the same as most new people which is understanding when and where to use certain characters i.e { } , [ ] , : ;, / \. Each one of these obviously plays a different role in a script and any characters out of place can give back undesired results or errors.

I am trying hard to find useful material, but like most have said, a lot of info out there is HTML based. It would be great to have lots of little code snippets available such as creating a layer, creating a layerset, selecting a layer by name, selecting a channel and maybe a second part too, like applying that selection to another layer or group to see how the code flows. I think it is only then you start to understand it more.

Once again many thanks, I look forward to playing around with your code and producing a useful script.
Mike Hale

Help getting a script started.

Post by Mike Hale »

j_forrester wrote:It would be great to have lots of little code snippets available such as creating a layer, creating a layerset, selecting a layer by name, ...

You might want to download Xbytor's xtools and have a look at his stdlib.js. It contains a large number of functions you can use as is or learn from.
j_forrester

Help getting a script started.

Post by j_forrester »

Thanks for the tip Mike.

I'm slowly building up some useful resources. Lets see what I can now create.... fingers crossed.
j_forrester

Help getting a script started.

Post by j_forrester »

I have since made a script that creates a layerset and names the layerset with the corresponding name as I wanted.

The problem being is that it is still quite manual with having to type in the layerset name into the script each time and selecting which artlayer to use to use as a layer mask on the specific layerset. It's kind of half a step on from using actions, but still something I have enjoyed doing and thankful for all the help.

I was wondering if it was possible to to automate this a lot more.

What I am trying to achieve.

I would need to be able to pick a folder which would contain a mixture of files. I would need it to only pick files which starter with "mk". Example of files below. On bringing the file into the active document I would need to subtract the "mk_" from the start of the file name and the ".tga" from the end of the file name. Then select the incoming files red channel and create a new folder with the new shortened name and apply the red channel as a mask to the new created folder.

i.e mk_stone.tga would create a layerset with the name "stone_set" with "mk_stone.tga" red channel applied as a mask. When the function is complete it searches the folder for the next file beginning with "mk" and runs the function again and again until it has found all files beginning with"mk".


Mask element tiff files (mainly red and black images)

mk_stone.tga
mk_concrete.tga
mk_frames.tga
mk_timber.tga


Create layerset with filename minus "mk_" from the beginning and ".tga" from the end with +"_set at the end

stone_set
concrete_set
frames_set
timber_set


Apply mask to Layerset

stone set + (mk stone used as a layer mask)
concrete set + (mk concrete used as a layer mask)
frames set + (mk frames used as a layer mask)
timber set + (mk timber used as a layer mask)


Below is a full list with code I know where possible

1. Work in the active document - var myDocument = app.activeDocument;

2. Select a folder - var selectedFolder = Folder.selectDialog( "Please select top level folder");

3. Get all files in the selected folder which start with "mk" - getFiles () (not sure how to write such a piece of code) but guess it would need an "if"
command, as in "if filename begins with "mk" load file into scene.

4. Then I would need it to create a layerset with name - var mystr = ('filename.tga')
var filename = mystr.slice (0,3)+(0,-4); // I need mk_stone.tga to become the layest name (stone+_set)
var stone = myDocument.layerSets.add();
var layer.name = "mystr+_set";

5. Applying mask to layerset - Not sure what would be needed here but would need to select the red channel from the
imcoming file (i.e mk_stone.tga and apply that to the "stone_set" layerset. If no pixels
are selected to apply, search for next file which begins with "mk" and run again.

6. If layermask has been applied, find the next "mk" file again not sure at all what I would need here.



As you can probably see, I'm a little bit out of my depth here but it would make the script so much quicker and more intelligent than the manual way I am have currently been able to stitch together with a little help.


Any help with this problem would be much appreciated.
Mike Hale

Help getting a script started.

Post by Mike Hale »

For step 3 getFiles() accepts wildcards so you could do something like getFiles('mk_*.tga');

For step 5 because the layerSet is the activeLayer you could do something like this.

Code: Select allfunction createLayerMask(){
    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 applyRedChannelAsMask() {
   var desc = new ActionDescriptor();
        var channelDesc = new ActionDescriptor();
            var channelRef = new ActionReference();
            channelRef.putEnumerated( charIDToTypeID('Chnl'), charIDToTypeID('Chnl'), charIDToTypeID('Rd  ') );
            channelRef.putProperty( charIDToTypeID('Lyr '), charIDToTypeID('Bckg') );
        channelDesc.putReference( charIDToTypeID('T   '), channelRef );
        channelDesc.putBoolean( charIDToTypeID('PrsT'), true );
    desc.putObject( charIDToTypeID('With'), charIDToTypeID('Clcl'), channelDesc );
    executeAction( charIDToTypeID('AppI'), desc, DialogModes.NO );
};

createLayerMask();// create a white mask
applyRedChannelAsMask();// apply the red channel to the layer maskBut I am not sure what you mean by 'if no pixels are selected'
j_forrester

Help getting a script started.

Post by j_forrester »

Thanks for your hep Mike,

In response to you question "But I am not sure what you mean by 'if no pixels are selected'".

When you select a channel with no active pixels in that channel you receive a warning saying "warning no pixels selected" .i.e no red pixels in the red channel.

I have attached some sample .tga files and probably some of the worst code you have even seen. In all honesty it's more pseudo code, explaining the process I am looking to achieve with a rough idea of coding where possible. I have also attached some "blank black" files which would stop the creation function and restart with the next file. All explained in the pseudo code attached.

I am both new to coding and this forum but I am very pleased with the help shown. I know how it can be a little annoying having to show "newbies" repeated tasks. I have bought a basic coding book, but it doesn't go anywhere to explain the things I am after. I always try knocking my head against the wall for many days before posting for help.

If yourself or anyone else has a bit of time to have a quick look and a probably a little laugh at my code I would be very appreciative.

Have a good weekend

sample files and pseudo code script.zip (44.63 KiB) Downloaded 6 times
Mike Hale

Help getting a script started.

Post by Mike Hale »

Let me ask a few questions. First the steps as I understand them.

1. You want to open a file and check the red channel to see if there are any non-black pixels
2a. If there are non-black pixels in the red channel you want to create a layerSet and apply the red channel as a mask.
2b. If the red channel is all black you don't want to make the layerSet or mask.

I am not clear on what the next step should be. Is the script done with the first file? You just want an empty layerSet with a mask? Should the script save the file if it creates the layerSet before moving on to the next file. If the red channel is all black should the script just close the file and process the next one?
j_forrester

Help getting a script started.

Post by j_forrester »

Sorry for any confusion and thanks for your patience.

As I render off a lot off CG mask files (RGB images with black elsewhere) I wanted a script to automatically build my photoshop stack with a named layerset with mask.

In my 3D application I attach a render element to an object which in turn renders that element red against a black background. Depending on the angle of the camera it may be visible in one view but not another view. If the render "mk_" file is completely black it means that the object is not seen in that view, therefor it does not need to make a named layerset because it is irrelevant in this view.

Maybe I was over complicating the process before. A simpler process below.

The script could load all files beginning "mk_" from a chosen folder. (a bit like load files into stack but only with "mk_" start to filename)
Once all files are loaded. It isolates each artlayer and checks for any none black pixels in the red channel. If there are it creates a named layerset as described before and applies the layermask to that layerset. "mk_stone.tga" becomes a named layerset "stone set" or "stone_set" not sure if you can leave a space, if not an underscore would be fine?!
If no non-black pixels are selected it doesn't create a named layerset and moves onto the next artlayer until all have been checked and processed.

If there are 30 "mk_" artlayers loaded in total and 18 have non-black pixels then 12 named layersets will be created. (ideally all layersets would have a red colour applied). At the end of the script all artlayers should be deleted from the active file as they are no longer need to exist in this file.

I have attached a layered PSD file showing the final outcome from the script. I have left the artlayers at the bottom of this file just to show how and where the layermasks are applied, these artlayers would ideally be deleted after all have been checked.

I have also attached another badly coded script to give you an idea of what I am trying to achieve, this does work until it finds an artlayer with no non-black pixels in the red channel, I've since realized a lot this script could have been shortened, but was my very first attempt. With this script I also had to manually tell it what artlayer to use as a mask and what to name the empty layerset. Alot of setting up.

If you open the finished PSD file. delete all the layersets once you have understood the structure and then run the atached script it will show you roughly what I am trying to achieve, but with a more automated process.

Mike, thanks again for your help and time.

sample files and BAD coding.zip (70.86 KiB) Downloaded 6 times