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])
};