19 Replies Latest reply on Sep 2, 2014 10:03 AM by Monstrik

    Adding two selections in a non regular way

    Monstrik Level 1

      I want to add A and B selections so the areas which intersect or dont intersect at all - dissapear.

      Only the areas that are within the boundaries of another area (for example area 5 [see images 5 and 6]), or share a common border of another area (for example areas 2 and 3 [see images 5 and 6]) should remain intact after the second selection is added. can this be scripted?Untitled-8.jpg

        • 1. Re: Adding two selections in a non regular way
          c.pfaffenbichler Level 9

          Are the Selections likely to be sharp (with Anti-aliasing maybe, though) or will there be soft ones, too?

           

          One possible approach might be

          • breaking Selection into its parts (via Work Path etc.)

          • making Selections from those individually and evaluating the Histogram  those Selection produce on a Channel based on Selection A – if the Histogram reveals a relevant amount of black or non-white the segment can be "forgotten", if it’s mainly white (here the Anti-aliasing could provide a problem) it will be "collected"

          • selecting the whole of the affected segments from A might be bit unpleasant, but one could use the Magic Wand Tool on the Channel based on A with the coordinates of one pathPoint from the collected subPathItems each

          Edit: Naturally one should, as in the other Script, intersect the new (possibly expanded) Selection with the original Selection A to mitigate edge pixel issues.

           

          Using the Magic Wand Tool would likely result in weak performance with regard to running time, though.

          • 2. Re: Adding two selections in a non regular way
            Monstrik Level 1

            Both selections would always be as sharp as they can be - without anti-aliasing. And the result i would like to get should be the same - no anti-aliasing. In other words, if i filled the selection with black color, the edges should be seen as very pixelated. Can it be scripted according to these terms?

            • 3. Re: Adding two selections in a non regular way
              c.pfaffenbichler Level 9
              Can it be scripted according to these terms?

              I think it can.


              But by now I’m curious – what’s the purpose of these operations anyway?

              • 4. Re: Adding two selections in a non regular way
                c.pfaffenbichler Level 9

                Actually the Magic Wand Tool is not needed, one can simply grow the intersected Selection (edit: of the resulting Path and Channels A and B).

                • 5. Re: Adding two selections in a non regular way
                  Monstrik Level 1

                  Im trying to create this space which i have in my head. It is a part of a design im working on. I havent achieved it yet, so i cannot show it yet. I take photos of things like water bubbles, leaves, and some other things. Having this material i do some crazy masking. Well at least crazy to me. It is quite complicated. Therefore the screenshots i post are only simulations of my problems. In other words they are simplifications of the problems i face.

                  It takes lots of time because i go through plenty of trials and errors. Im trying to be creative and it is annoying when i cannot do something because of my lack of skills. I know one thing -  these scripts would speed up my progress because i had encountered these problems before, while doing some other things. I wrote them down so i could later do some reasearch on them and solve them. But i couldnt solve them, therefore i am here, asking for help.

                  • 6. Re: Adding two selections in a non regular way
                    c.pfaffenbichler Level 9

                    This works on the last two channels in an image.

                    // create selection based on two channels;

                    // only thoseelements from a are maintained which completely enclose an element from b;

                    // channels need to be basically 1-bit, no anti-aliasing, no softe edges, each pixel be either fully white or fully black;

                    // 2014, use it at your own risk;

                    #target "photoshop-70.032"

                    if (app.documents.length > 0) {

                    if (app.activeDocument.channels.length > 2) {

                    var myDocument = app.activeDocument;

                    // define the channels;

                    var channelA = myDocument.channels[myDocument.channels.length - 2];

                    var channelB = myDocument.channels[myDocument.channels.length - 1];

                    // confirm theh two channels;

                    var theCheck = confirm("please confirm\nchannel a is "+channelA.name+"\nchannel b is "+channelB.name);

                    if (theCheck == true) {

                    var thePath = workPathFromChannel (myDocument, channelB);

                    // select channel;

                    myDocument.activeChannels = [channelA];

                    var thePoints = new Array;

                    // process the subPathItems;

                    for (var m = 0; m < thePath.length; m++) {

                    // make selection and get histogram;

                    var thisPath = createPath2012([thePath[m]], "removeThisPath");

                    thisPath.makeSelection(0, false, SelectionType.REPLACE);

                    myDocument.selection.load(channelB, SelectionType.INTERSECT);

                    var theHisto = channelA.histogram;

                    var thePercentage = histogramPercentage(theHisto, 255);

                    // collect if almost fully white;

                    if (thePercentage[0] > 99) {

                    thePoints.push(thePath[m]);

                    };

                    // remove path;

                    thisPath.remove();

                    };

                    // process the resulting path;

                    var anotherPath = createPath2012(thePoints, "removeThisPath");

                    anotherPath.makeSelection(0, false, SelectionType.REPLACE);

                    myDocument.selection.load(channelB, SelectionType.INTERSECT);

                    myDocument.selection.load(channelA, SelectionType.INTERSECT);

                    myDocument.selection.grow(6, false);

                    // remove path;

                    anotherPath.remove()

                    };

                    };

                    };

                    ////// magic wand //////

                    function useMagicWand (theCoord) {

                    // select tool;

                    // =======================================================

                    var idslct = charIDToTypeID( "slct" );

                        var desc2 = new ActionDescriptor();

                        var idnull = charIDToTypeID( "null" );

                            var ref2 = new ActionReference();

                            var idmagicWandTool = stringIDToTypeID( "magicWandTool" );

                            ref2.putClass( idmagicWandTool );

                        desc2.putReference( idnull, ref2 );

                        var iddontRecord = stringIDToTypeID( "dontRecord" );

                        desc2.putBoolean( iddontRecord, true );

                        var idforceNotify = stringIDToTypeID( "forceNotify" );

                        desc2.putBoolean( idforceNotify, true );

                    executeAction( idslct, desc2, DialogModes.NO );

                    // apply tool;

                    // =======================================================

                    var idsetd = charIDToTypeID( "setd" );

                        var desc2 = new ActionDescriptor();

                        var idnull = charIDToTypeID( "null" );

                            var ref2 = new ActionReference();

                            var idChnl = charIDToTypeID( "Chnl" );

                            var idfsel = charIDToTypeID( "fsel" );

                            ref2.putProperty( idChnl, idfsel );

                        desc2.putReference( idnull, ref2 );

                        var idT = charIDToTypeID( "T   " );

                            var desc3 = new ActionDescriptor();

                            var idHrzn = charIDToTypeID( "Hrzn" );

                            var idPxl = charIDToTypeID( "#Pxl" );

                            desc3.putUnitDouble( idHrzn, idPxl, theCoord[0] );

                            var idVrtc = charIDToTypeID( "Vrtc" );

                            var idPxl = charIDToTypeID( "#Pxl" );

                            desc3.putUnitDouble( idVrtc, idPxl, theCoord[1] );

                        var idPnt = charIDToTypeID( "Pnt " );

                        desc2.putObject( idT, idPnt, desc3 );

                        var idTlrn = charIDToTypeID( "Tlrn" );

                        desc2.putInteger( idTlrn, 30 );

                        var idAntA = charIDToTypeID( "AntA" );

                        desc2.putBoolean( idAntA, true );

                    executeAction( idsetd, desc2, DialogModes.NO );

                    };

                    ////// get work path  info from channel //////

                    function workPathFromChannel (myDocument, theChannel) {

                    // load;

                    myDocument.selection.load(theChannel, SelectionType.REPLACE);

                    // use threshold to heighten non black pixels;

                    myDocument.quickMaskMode = true;

                    myDocument.activeLayer.threshold(1);

                    myDocument.quickMaskMode = false;

                    // create work path;

                    // =======================================================

                    var idMk = charIDToTypeID( "Mk  " );

                        var desc16 = new ActionDescriptor();

                        var idnull = charIDToTypeID( "null" );

                            var ref12 = new ActionReference();

                            var idPath = charIDToTypeID( "Path" );

                            ref12.putClass( idPath );

                        desc16.putReference( idnull, ref12 );

                        var idFrom = charIDToTypeID( "From" );

                            var ref13 = new ActionReference();

                            var idcsel = charIDToTypeID( "csel" );

                            var idfsel = charIDToTypeID( "fsel" );

                            ref13.putProperty( idcsel, idfsel );

                        desc16.putReference( idFrom, ref13 );

                        var idTlrn = charIDToTypeID( "Tlrn" );

                        var idPxl = charIDToTypeID( "#Pxl" );

                        desc16.putUnitDouble( idTlrn, idPxl, 1.000000 );

                    executeAction( idMk, desc16, DialogModes.NO );

                    // get information;

                    var theArray = collectPathInfoFromDesc2012 (myDocument, myDocument.pathItems[myDocument.pathItems.length - 1]);

                    return theArray

                    };

                    ////// collect path info from actiondescriptor, smooth added //////

                    function collectPathInfoFromDesc2012 (myDocument, thePath) {

                    var originalRulerUnits = app.preferences.rulerUnits;

                    app.preferences.rulerUnits = Units.POINTS;

                    // based of functions from xbytor’s stdlib;

                    var ref = new ActionReference();

                    for (var l = 0; l < myDocument.pathItems.length; l++) {

                      var thisPath = myDocument.pathItems[l];

                      if (thisPath == thePath && thisPath.name == "Work Path") {

                      ref.putProperty(cTID("Path"), cTID("WrPt"));

                      };

                      if (thisPath == thePath && thisPath.name != "Work Path" && thisPath.kind != PathKind.VECTORMASK) {

                      ref.putIndex(cTID("Path"), l + 1);

                      };

                      if (thisPath == thePath && thisPath.kind == PathKind.VECTORMASK) {

                            var idPath = charIDToTypeID( "Path" );

                            var idPath = charIDToTypeID( "Path" );

                            var idvectorMask = stringIDToTypeID( "vectorMask" );

                            ref.putEnumerated( idPath, idPath, idvectorMask );

                      };

                      };

                    var desc = app.executeActionGet(ref);

                    var pname = desc.getString(cTID('PthN'));

                    // create new array;

                    var theArray = new Array;

                    var pathComponents = desc.getObjectValue(cTID("PthC")).getList(sTID('pathComponents'));

                    // for subpathitems;

                    for (var m = 0; m < pathComponents.count; m++) {

                      var listKey = pathComponents.getObjectValue(m).getList(sTID("subpathListKey"));

                      var operation1 = pathComponents.getObjectValue(m).getEnumerationValue(sTID("shapeOperation"));

                      switch (operation1) {

                      case 1097098272:

                      var operation = 1097098272 //cTID('Add ');

                      break;

                      case 1398961266:

                      var operation = 1398961266 //cTID('Sbtr');

                      break;

                      case 1231975538:

                      var operation = 1231975538 //cTID('Intr');

                      break;

                      default:

                    // case 1102:

                      var operation = sTID('xor') //ShapeOperation.SHAPEXOR;

                      break;

                      };

                    // for subpathitem’s count;

                      for (var n = 0; n < listKey.count; n++) {

                      theArray.push(new Array);

                      var points = listKey.getObjectValue(n).getList(sTID('points'));

                      try {var closed = listKey.getObjectValue(n).getBoolean(sTID("closedSubpath"))}

                      catch (e) {var closed = false};

                    // for subpathitem’s segment’s number of points;

                      for (var o = 0; o < points.count; o++) {

                      var anchorObj = points.getObjectValue(o).getObjectValue(sTID("anchor"));

                      var anchor = [anchorObj.getUnitDoubleValue(sTID('horizontal')), anchorObj.getUnitDoubleValue(sTID('vertical'))];

                      var thisPoint = [anchor];

                      try {

                      var left = points.getObjectValue(o).getObjectValue(cTID("Fwd "));

                      var leftDirection = [left.getUnitDoubleValue(sTID('horizontal')), left.getUnitDoubleValue(sTID('vertical'))];

                      thisPoint.push(leftDirection)

                      }

                      catch (e) {

                      thisPoint.push(anchor)

                      };

                      try {

                      var right = points.getObjectValue(o).getObjectValue(cTID("Bwd "));

                      var rightDirection = [right.getUnitDoubleValue(sTID('horizontal')), right.getUnitDoubleValue(sTID('vertical'))];

                      thisPoint.push(rightDirection)

                      }

                      catch (e) {

                      thisPoint.push(anchor)

                      };

                      try {

                      var smoothOr = points.getObjectValue(o).getBoolean(cTID("Smoo"));

                      thisPoint.push(smoothOr)

                      }

                      catch (e) {thisPoint.push(false)};

                      theArray[theArray.length - 1].push(thisPoint);

                      };

                      theArray[theArray.length - 1].push(closed);

                      theArray[theArray.length - 1].push(operation);

                      };

                      };

                    // by xbytor, thanks to him;

                    function cTID (s) { return cTID[s] || cTID[s] = app.charIDToTypeID(s); };

                    function sTID (s) { return sTID[s] || sTID[s] = app.stringIDToTypeID(s); };

                    // reset;

                    app.preferences.rulerUnits = originalRulerUnits;

                    return theArray;

                    };

                    ////// create a path from collectPathInfoFromDesc2012-array //////

                    function createPath2012(theArray, thePathsName) {

                    var originalRulerUnits = app.preferences.rulerUnits;

                    app.preferences.rulerUnits = Units.POINTS;

                    // thanks to xbytor;

                    cTID = function(s) { return app.charIDToTypeID(s); };

                    sTID = function(s) { return app.stringIDToTypeID(s); };

                     

                     

                        var desc1 = new ActionDescriptor();

                        var ref1 = new ActionReference();

                        ref1.putProperty(cTID('Path'), cTID('WrPt'));

                        desc1.putReference(sTID('null'), ref1);

                        var list1 = new ActionList();

                     

                    for (var m = 0; m < theArray.length; m++) {

                      var thisSubPath = theArray[m];

                     

                        var desc2 = new ActionDescriptor();

                        desc2.putEnumerated(sTID('shapeOperation'), sTID('shapeOperation'), thisSubPath[thisSubPath.length - 1]);

                        var list2 = new ActionList();

                        var desc3 = new ActionDescriptor();

                        desc3.putBoolean(cTID('Clsp'), thisSubPath[thisSubPath.length - 2]);

                        var list3 = new ActionList();

                     

                    for (var n = 0; n < thisSubPath.length - 2; n++) {

                      var thisPoint = thisSubPath[n];

                     

                        var desc4 = new ActionDescriptor();

                        var desc5 = new ActionDescriptor();

                        desc5.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[0][0]);

                        desc5.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[0][1]);

                        desc4.putObject(cTID('Anch'), cTID('Pnt '), desc5);

                        var desc6 = new ActionDescriptor();

                        desc6.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[1][0]);

                        desc6.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[1][1]);

                        desc4.putObject(cTID('Fwd '), cTID('Pnt '), desc6);

                        var desc7 = new ActionDescriptor();

                        desc7.putUnitDouble(cTID('Hrzn'), cTID('#Rlt'), thisPoint[2][0]);

                        desc7.putUnitDouble(cTID('Vrtc'), cTID('#Rlt'), thisPoint[2][1]);

                        desc4.putObject(cTID('Bwd '), cTID('Pnt '), desc7);

                        desc4.putBoolean(cTID('Smoo'), thisPoint[3]);

                        list3.putObject(cTID('Pthp'), desc4);

                     

                      };

                     

                        desc3.putList(cTID('Pts '), list3);

                        list2.putObject(cTID('Sbpl'), desc3);

                        desc2.putList(cTID('SbpL'), list2);

                        list1.putObject(cTID('PaCm'), desc2);

                      };

                     

                        desc1.putList(cTID('T   '), list1);

                        executeAction(cTID('setd'), desc1, DialogModes.NO);

                     

                     

                    if (hasVectorMask() == false) {

                    if (thePathsName != undefined) {app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1].name = thePathsName};

                    var myPathItem = app.activeDocument.pathItems[app.activeDocument.pathItems.length - 1];

                    }

                    else {

                    if (thePathsName != undefined) {app.activeDocument.pathItems[app.activeDocument.pathItems.length - 2].name = thePathsName};

                    var myPathItem = app.activeDocument.pathItems[app.activeDocument.pathItems.length - 2];

                    };

                    app.preferences.rulerUnits = originalRulerUnits;

                    return myPathItem

                    };

                    // from »Flatten All Masks.jsx« by jeffrey tranberry;

                    ///////////////////////////////////////////////////////////////////////////////

                    // Function: hasVectorMask

                    // Usage: see if there is a vector layer mask

                    // Input: <none> Must have an open document

                    // Return: true if there is a vector mask

                    ///////////////////////////////////////////////////////////////////////////////

                    function hasVectorMask() {

                      var hasVectorMask = false;

                      try {

                      var ref = new ActionReference();

                      var keyVectorMaskEnabled = app.stringIDToTypeID( 'vectorMask' );

                      var keyKind = app.charIDToTypeID( 'Knd ' );

                      ref.putEnumerated( app.charIDToTypeID( 'Path' ), app.charIDToTypeID( 'Ordn' ), keyVectorMaskEnabled );

                      var desc = executeActionGet( ref );

                      if ( desc.hasKey( keyKind ) ) {

                      var kindValue = desc.getEnumerationValue( keyKind );

                      if (kindValue == keyVectorMaskEnabled) {

                      hasVectorMask = true;

                      }

                      }

                      }catch(e) {

                      hasVectorMask = false;

                      }

                      return hasVectorMask;

                    };

                    ////// histogram //////

                    function histogramPercentage (theHisto, theNumber) {

                    var theTotal = 0;

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

                    theTotal = theTotal + theHisto[n]

                    };

                    return ([theHisto[theNumber] / theTotal * 100, theTotal])

                    };

                    • 7. Re: Adding two selections in a non regular way
                      Monstrik Level 1

                      Dear Christoph how do i run the script? load selection A, run script, then load B, then run the script again?

                      • 8. Re: Adding two selections in a non regular way
                        c.pfaffenbichler Level 9

                        No, the Script uses the last two Channels in the active file.

                        • 9. Re: Adding two selections in a non regular way
                          Monstrik Level 1

                          So i dont need to load selections?  because i tried running the script in this way but nothing happened

                          Here, i simply run the script having the file with two alpha channels... but it doesnt seem to be working... can you please look at this screeshot below and tell me what im doing wrong?

                          in the first image you can see i have these two channels

                          in the second you can see I open extendscript toolkit and press "play"

                          in the third image i get this warning: Waiting; "press ESC to abort..."

                          It should work on the last two channels The image.jpg

                          • 10. Re: Adding two selections in a non regular way
                            c.pfaffenbichler Level 9

                            Change the line

                            #target "photoshop-70.032"

                            to

                            #target photoshop

                            and try again.

                            • 11. Re: Adding two selections in a non regular way
                              Monstrik Level 1

                              Thank You it worked, but something didnt go very well...

                              image 1: as you can see i run the script.. i am asked to confirm channels... ( would it be possible to get rid of this confirmation window please?...instead i will make sure that selection A always go first and selection B always goes second, so i dont need to confirm it.. please, it would save time)

                              image 2: is what i see after the script has done its work

                              image 3: i save the selection to see what i have

                              image 4: we see the selection saved and it is not what i was expected to get.. What did i do wrong?

                              image 5: the result i was expecting to get

                              Something went wrong the image.jpg

                              • 12. Re: Adding two selections in a non regular way
                                c.pfaffenbichler Level 9

                                Can you provide the file?

                                 

                                I suspect the segment you want to produce a result but does not may overextend.

                                To make the Script more "tolerant" you could reduce the percentage in the line

                                if (thePercentage[0] > 99) {

                                 

                                would it be possible to get rid of this confirmation window please?

                                So remove it and the if-clause that refers to it.

                                • 13. Re: Adding two selections in a non regular way
                                  Monstrik Level 1

                                  How can i provide the file?

                                  Does reducing percentage make the result less accurate? because to me every pixel counts... i would like to see no changes in the areas that remain after the script is run.

                                  So how can i provide the file so you can have a look?

                                  Can you please tell me which step i should remove to get rid of the confirmation window? im afraid to ruin the script by removing something that is necessary

                                   

                                  in the image: those two areas I had achieved in the same way...there should be difference between them in terms of sharing a common border... the right one dont overextend

                                   

                                  these two ares are the same.jpg

                                  • 14. Re: Adding two selections in a non regular way
                                    c.pfaffenbichler Level 9

                                    To abandon the confirmation dialog mark out or delete the lines

                                    // confirm theh two channels;

                                    var theCheck = confirm("please confirm\nchannel a is "+channelA.name+"\nchannel b is "+channelB.name);

                                    if (theCheck == true) {

                                    and the corresponding closing bracket.

                                     

                                    Does reducing percentage make the result less accurate?

                                    Naturally, but possibly not in the sense you mean.

                                    The Selection from the Path is intersected with B and A anyway, so it will not extend beyond those.

                                    • 15. Re: Adding two selections in a non regular way
                                      Monstrik Level 1

                                      since i deleted these lines, the script stops at this point... how can i fix it please?

                                       

                                      // confirm theh two channels;

                                      var theCheck = confirm("please confirm\nchannel a is "+channelA.name+"\nchannel b is "+channelB.name);

                                      if (theCheck == true) {

                                       

                                      the script stops at this point.jpg

                                      • 16. Re: Adding two selections in a non regular way
                                        c.pfaffenbichler Level 9

                                        Have you removed the corresponding closing bracket?

                                        • 17. Re: Adding two selections in a non regular way
                                          c.pfaffenbichler Level 9

                                          How can i provide the file?

                                          That’s up to you, various services are available.

                                          • 18. Re: Adding two selections in a non regular way
                                            Monstrik Level 1

                                            i did now i didnt know i should follow the line

                                            • 19. Re: Adding two selections in a non regular way
                                              Monstrik Level 1

                                              the script works and it works well... thank you very much...