-
1. Re: Adding two selections in a non regular way
c.pfaffenbichler Aug 29, 2014 7:34 AM (in response to Monstrik)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 Aug 29, 2014 8:24 AM (in response to c.pfaffenbichler)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 Aug 31, 2014 6:28 AM (in response to Monstrik)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 Sep 1, 2014 12:04 AM (in response to Monstrik)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 Sep 1, 2014 12:20 AM (in response to c.pfaffenbichler)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 Sep 1, 2014 12:55 AM (in response to Monstrik)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 Sep 1, 2014 7:03 AM (in response to c.pfaffenbichler)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 Sep 1, 2014 8:16 AM (in response to Monstrik)No, the Script uses the last two Channels in the active file.
-
9. Re: Adding two selections in a non regular way
Monstrik Sep 1, 2014 11:05 PM (in response to c.pfaffenbichler)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..."
-
10. Re: Adding two selections in a non regular way
c.pfaffenbichler Sep 1, 2014 11:06 PM (in response to Monstrik)Change the line
#target "photoshop-70.032"
to
#target photoshop
and try again.
-
11. Re: Adding two selections in a non regular way
Monstrik Sep 1, 2014 11:59 PM (in response to c.pfaffenbichler)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
-
12. Re: Adding two selections in a non regular way
c.pfaffenbichler Sep 2, 2014 12:08 AM (in response to Monstrik)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 Sep 2, 2014 12:43 AM (in response to c.pfaffenbichler)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
-
14. Re: Adding two selections in a non regular way
c.pfaffenbichler Sep 2, 2014 12:47 AM (in response to Monstrik)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 Sep 2, 2014 1:01 AM (in response to c.pfaffenbichler) -
16. Re: Adding two selections in a non regular way
c.pfaffenbichler Sep 2, 2014 1:27 AM (in response to Monstrik)Have you removed the corresponding closing bracket?
-
17. Re: Adding two selections in a non regular way
c.pfaffenbichler Sep 2, 2014 1:28 AM (in response to Monstrik)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 Sep 2, 2014 1:39 AM (in response to c.pfaffenbichler)i did now i didnt know i should follow the line
-
19. Re: Adding two selections in a non regular way
Monstrik Sep 2, 2014 10:03 AM (in response to c.pfaffenbichler)the script works and it works well... thank you very much...






