return specific coordinates of selection. PathItem?
return specific coordinates of selection. PathItem?
above is an image that shows what i need via two red arrows. they both point to the specific points i need coordinates for. the green guides in the image represent the bounds of a selection, even though the selection is rotated as represented by the white rectangle.
So what i need is to return the coordinates of the top left and top right corners of the selection (white rectangle), and NOT the bounds(green guides). I have been working with the PathItem.anchor options but cant figure out how to get those exact coordinates.
So right now my script:
1. opens an image
2. applies a threshold
3. uses the magic wand to select the black of the threshold results
4. inverts the selection to only have the white selected
..and this is where i really need to know the coordinates of the top two points of the selection
the final goal is to use those points to do some math to find how rotated the selection is....and then use that to adjust the angle and straighten via crop().
I really appreciate the help i have received in the past. I have read various posts already but nothing really hit home yet. Thank you for taking the time to read this!
return specific coordinates of selection. PathItem?
How many points does the path have?
return specific coordinates of selection. PathItem?
Hello!
Sooo.... I am finally getting back to respond to this. @pfaffenbichler, your one comment asking how many points my selection had made me realize i needed to understand how selections were defined by photoshop better. Long story short it lead me down a series of inquiries in the reference guide and google. Now I have a working script that im fairly proud of for what it is...as well as a better understanding of photoshop.
To sum up the core features of the script it:
1. prompts user for source image folder and then where to save resulting TIFF files.
2. applies threshold to image to determine what is object vs what is background(white vs black)
3. creates a selection based off of threshold data using magic wand, and saves the bounds of that selection
4. converts selection to working path
5. does comparisons and finds the smallest and largest X and Y values ( tells us where and when the object starts and stops )
6. uses that data to determine which direction the object is rotated ( down to the right, or down to the left)
7. take point and bounds data and returns the amount in degrees of rotation on top side
8. based on which direction its rotated, rotate the selection
9. crop the image
10. save and close
thanks for the hint! here is the code:
--------------------------------------------------------------------------------------------------------------------------------------
Code: Select all//select the input folder for the files that will be scripted
var inputFolder = Folder.selectDialog("Please select the folder that contains the files you wish to OPEN");
var outputFolder = Folder.selectDialog("Please select the folder where you want to SAVE the edited images");
//store list of images from chosen folder into a List
var imageList = inputFolder.getFiles();
//pick default threshold value // this determines the selection and crop
var thresholdValue = 15;
//prompt user to declare threshold value prompt ( message to user, default value )
var thresholdInput = prompt('Enter a threshold value between 1 and 255','15');
//make sure that the prompt received a value input. if not then keep defaults
if (thresholdInput != null){
var thresholdValue = thresholdInput;
}
//save tolerance value of selection with magic wand, default is zero
//it is passed to the function 'selectSelect'
var tolR = 0;
//variable to store the dpi of the current doc for later use
var curRes = 0;
//store var j for main loop
var j = 0;
//variable that stores one eighth of dpi
var dpiFrac = 0;
//store angle for crop
var cropAngle = 0;
//variable to change cropAngle from positive to negative
var negPos = 1;
//loop through the imageList
while( j<imageList.length){
if(j != imageList.length){
//open images
open(File(imageList[j]));
//assign a name to the original open document
var currentDoc = activeDocument;
//remove dialogs
displayDialogs = DialogModes.NO;
//store the ruler unit for later use
var originalUnit = preferences.rulerUnits;
//change document ruler to pixels
preferences.rulerUnits = Units.PIXELS;
//return the dpi of the current document
curRes = currentDoc.resolution;
//save the width of the currentDoc
var currentWidth = currentDoc.width;
//save the height of the currentDoc
var currentHeight = currentDoc.height;
//divide the resolution by eight
dpiFrac = (curRes/8);
//apply threshold to current image using function
applyThreshold (thresholdValue);
//create selection using magic wand
selectSelect (currentWidth/2, currentHeight/2);
//smooth selection
currentDoc.selection.smooth(3);
//store bounds of selection
var boundsLeft = activeDocument.selection.bounds[0] ;
var boundsTop = activeDocument.selection.bounds[1] ;
var boundsRight= activeDocument.selection.bounds[2] ;
var boundsBottom= activeDocument.selection.bounds[3] ;
// Turn the selection into a work path and give it reference
currentDoc.selection.makeWorkPath();
var wPath = currentDoc.pathItems['Work Path'];
//set up variables and store x and y anchor values
var pathLength = wPath.subPathItems[0].pathPoints.length;
//this is the first item in the list of anchor points
var origAnchor = wPath.subPathItems[0].pathPoints[0].anchor;
var testX = 0;
var testY = 0;
//starting point is originalAnchor
var smallX = 0;
var smallY = 0;
var largeX = 0;
var largeY = 0;
//return the smallest X value
smallX = findSmallestX(pathLength, origAnchor);
//alert(smallX + "smallX");
//return the smallest Y value
smallY = findSmallestY(pathLength, origAnchor);
//alert(smallY + "smallY");
//return the largest X value
largeX = findLargestX(pathLength, origAnchor);
//alert(largeX+ "largeX");
//return the largest Y value
//largeY = findLargestY(pathLength, origAnchor);
//alert(largeY + "largeY");
//what side of the document is anchor[0] on and
//find the angle to adjust the crop to straighten
if (smallY[0] > (currentWidth/2)){
//rightAnchor (smallX, smallY)
cropAngle = rightAnchor (smallX, smallY);
}else if( smallY[0] < (currentWidth/2)){
//leftAnchor (largeX, smallY)
cropAngle = leftAnchor (largeX, smallY);
//make negative to move counter clock wise
negPos = (-1*negPos);
}//else if
//return to original history sate
revertHistory();
//crop image based on earlier selection bounds
if(negPos*cropAngle > -5 && negPos*cropAngle < 5){
currentDoc.crop(new Array(boundsLeft - dpiFrac, boundsTop - dpiFrac, boundsRight + dpiFrac, boundsBottom + dpiFrac), (negPos*cropAngle), undefined, undefined);
}else{
currentDoc.crop(new Array(boundsLeft - (dpiFrac*2), boundsTop - (dpiFrac*2), boundsRight + (dpiFrac*2), boundsBottom + (dpiFrac*2)), undefined, undefined, undefined);
}
//save image
currentDoc.saveAs(new File(outputFolder), TiffSaveOptions);
//close the document
currentDoc.close(SaveOptions.DONOTSAVECHANGES);
//keep loop running
j = j + 1;
//reset negPos multiplier
negPos = 1;
}//end If
}//end While
/////////////////////////FUNCTIONS/////////////////////////////////////////////////////
//include the function in the script file
function applyThreshold(value)
{
var idThrs = charIDToTypeID( "Thrs" );
var desc2 = new ActionDescriptor();
var idLvl = charIDToTypeID( "Lvl " );
desc2.putInteger( idLvl, value );
executeAction( idThrs, desc2, DialogModes.NO );
}//end applyThreshold----------------------------------------------
//if selection anchor[0] is on left side of document
function leftAnchor(largeX, smallY){
var opSide = largeX[1] - smallY[1];
var adSide = largeX[0] - smallY[0];
var hySide = Math.sqrt((opSide*opSide) + (adSide*adSide));
var invSin = Math.asin(opSide/hySide);
var angle = invSin * (180/Math.PI);
//alert(angle);
return angle;
}//end function-------------------------------------------------------
//if selection is on right side of document
function rightAnchor(smallX, smallY){
var opSide = smallX[1] - smallY[1];
var adSide = smallY[0]- smallX[0];
var hySide = Math.sqrt((opSide*opSide) + (adSide*adSide));
var invSin = Math.asin(opSide/hySide);
var angle = invSin * (180/Math.PI);
//alert(angle);
return angle;
}//end function------------------------------------------------------
//find the smallest x anchor in selection path
function findSmallestX(pathLength, smallXF){
for (var i=0; i<pathLength; i++) {
//store the X coordinate for current anchor in loop
var xTemp = wPath.subPathItems[0].pathPoints.anchor;
//only if y value is in top half of document
//find the smallest X coordinate anchor
if(smallXF[0] >= xTemp[0]){
smallXF = xTemp;
}//if x small
}//for y small
return smallXF;
}//end function------------------------------------------------------
//find the smallest y anchor in selection path
function findSmallestY(pathLength, smallYF){
for (var h=0; h<pathLength; h++) {
//store the X coordinate for current anchor in loop
var yTemp = wPath.subPathItems[0].pathPoints[h].anchor;
//find the smallest Y coordinate anchor
if(smallYF[1] >= yTemp[1]){
smallYF = yTemp;
}//if x small
}//for y small
return smallYF;
}//end function------------------------------------------------------
//find the largest x anchor in selection path
function findLargestX(pathLength, largeXF){
for (var m=0; m<pathLength; m++) {
//store the X coordinate for current anchor in loop
var xTemp = wPath.subPathItems[0].pathPoints[m].anchor;
//find the smallest X coordinate anchor
if(largeXF[0] <= xTemp[0]){
largeXF = xTemp;
}//if x small
}//for y small
return largeXF;
}//end function------------------------------------------------------
//find the largest y anchor in selection path
function findLargestY(pathLength, largeYF){
for (var n=0; n<pathLength; n++) {
//store the X coordinate for current anchor in loop
var yTemp = wPath.subPathItems[0].pathPoints[n].anchor;
//find the smallest X coordinate anchor
if(largeYF[1] <= yTemp[1]){
largeYF = yTemp;
}//if x small
}//for y small
return largeYF;
}//end function------------------------------------------------------
function selectSelect(pntX, pntY)
{
var idsetd = charIDToTypeID( "setd" );
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref1 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idfsel = charIDToTypeID( "fsel" );
ref1.putProperty( idChnl, idfsel );
desc2.putReference( idnull, ref1 );
var idT = charIDToTypeID( "T " );
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID( "Hrzn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( idHrzn, idPxl, pntX);////width point (X)
var idVrtc = charIDToTypeID( "Vrtc" );
var idPxl = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( idVrtc, idPxl, pntY);////height point (Y)
var idPnt = charIDToTypeID( "Pnt " );
desc2.putObject( idT, idPnt, desc3 );
var idTlrn = charIDToTypeID( "Tlrn" );
desc2.putInteger( idTlrn, tolR );
var idAntA = charIDToTypeID( "AntA" );
desc2.putBoolean( idAntA, true );
executeAction( idsetd, desc2, DialogModes.NO );
}//end function-------------------------------------------------------
//restore image to original
function revertHistory(){
executeAction( charIDToTypeID( "Rvrt" ), undefined, DialogModes.NO );
}// end function------------------------------------------------------
Sooo.... I am finally getting back to respond to this. @pfaffenbichler, your one comment asking how many points my selection had made me realize i needed to understand how selections were defined by photoshop better. Long story short it lead me down a series of inquiries in the reference guide and google. Now I have a working script that im fairly proud of for what it is...as well as a better understanding of photoshop.
To sum up the core features of the script it:
1. prompts user for source image folder and then where to save resulting TIFF files.
2. applies threshold to image to determine what is object vs what is background(white vs black)
3. creates a selection based off of threshold data using magic wand, and saves the bounds of that selection
4. converts selection to working path
5. does comparisons and finds the smallest and largest X and Y values ( tells us where and when the object starts and stops )
6. uses that data to determine which direction the object is rotated ( down to the right, or down to the left)
7. take point and bounds data and returns the amount in degrees of rotation on top side
8. based on which direction its rotated, rotate the selection
9. crop the image
10. save and close
thanks for the hint! here is the code:
--------------------------------------------------------------------------------------------------------------------------------------
Code: Select all//select the input folder for the files that will be scripted
var inputFolder = Folder.selectDialog("Please select the folder that contains the files you wish to OPEN");
var outputFolder = Folder.selectDialog("Please select the folder where you want to SAVE the edited images");
//store list of images from chosen folder into a List
var imageList = inputFolder.getFiles();
//pick default threshold value // this determines the selection and crop
var thresholdValue = 15;
//prompt user to declare threshold value prompt ( message to user, default value )
var thresholdInput = prompt('Enter a threshold value between 1 and 255','15');
//make sure that the prompt received a value input. if not then keep defaults
if (thresholdInput != null){
var thresholdValue = thresholdInput;
}
//save tolerance value of selection with magic wand, default is zero
//it is passed to the function 'selectSelect'
var tolR = 0;
//variable to store the dpi of the current doc for later use
var curRes = 0;
//store var j for main loop
var j = 0;
//variable that stores one eighth of dpi
var dpiFrac = 0;
//store angle for crop
var cropAngle = 0;
//variable to change cropAngle from positive to negative
var negPos = 1;
//loop through the imageList
while( j<imageList.length){
if(j != imageList.length){
//open images
open(File(imageList[j]));
//assign a name to the original open document
var currentDoc = activeDocument;
//remove dialogs
displayDialogs = DialogModes.NO;
//store the ruler unit for later use
var originalUnit = preferences.rulerUnits;
//change document ruler to pixels
preferences.rulerUnits = Units.PIXELS;
//return the dpi of the current document
curRes = currentDoc.resolution;
//save the width of the currentDoc
var currentWidth = currentDoc.width;
//save the height of the currentDoc
var currentHeight = currentDoc.height;
//divide the resolution by eight
dpiFrac = (curRes/8);
//apply threshold to current image using function
applyThreshold (thresholdValue);
//create selection using magic wand
selectSelect (currentWidth/2, currentHeight/2);
//smooth selection
currentDoc.selection.smooth(3);
//store bounds of selection
var boundsLeft = activeDocument.selection.bounds[0] ;
var boundsTop = activeDocument.selection.bounds[1] ;
var boundsRight= activeDocument.selection.bounds[2] ;
var boundsBottom= activeDocument.selection.bounds[3] ;
// Turn the selection into a work path and give it reference
currentDoc.selection.makeWorkPath();
var wPath = currentDoc.pathItems['Work Path'];
//set up variables and store x and y anchor values
var pathLength = wPath.subPathItems[0].pathPoints.length;
//this is the first item in the list of anchor points
var origAnchor = wPath.subPathItems[0].pathPoints[0].anchor;
var testX = 0;
var testY = 0;
//starting point is originalAnchor
var smallX = 0;
var smallY = 0;
var largeX = 0;
var largeY = 0;
//return the smallest X value
smallX = findSmallestX(pathLength, origAnchor);
//alert(smallX + "smallX");
//return the smallest Y value
smallY = findSmallestY(pathLength, origAnchor);
//alert(smallY + "smallY");
//return the largest X value
largeX = findLargestX(pathLength, origAnchor);
//alert(largeX+ "largeX");
//return the largest Y value
//largeY = findLargestY(pathLength, origAnchor);
//alert(largeY + "largeY");
//what side of the document is anchor[0] on and
//find the angle to adjust the crop to straighten
if (smallY[0] > (currentWidth/2)){
//rightAnchor (smallX, smallY)
cropAngle = rightAnchor (smallX, smallY);
}else if( smallY[0] < (currentWidth/2)){
//leftAnchor (largeX, smallY)
cropAngle = leftAnchor (largeX, smallY);
//make negative to move counter clock wise
negPos = (-1*negPos);
}//else if
//return to original history sate
revertHistory();
//crop image based on earlier selection bounds
if(negPos*cropAngle > -5 && negPos*cropAngle < 5){
currentDoc.crop(new Array(boundsLeft - dpiFrac, boundsTop - dpiFrac, boundsRight + dpiFrac, boundsBottom + dpiFrac), (negPos*cropAngle), undefined, undefined);
}else{
currentDoc.crop(new Array(boundsLeft - (dpiFrac*2), boundsTop - (dpiFrac*2), boundsRight + (dpiFrac*2), boundsBottom + (dpiFrac*2)), undefined, undefined, undefined);
}
//save image
currentDoc.saveAs(new File(outputFolder), TiffSaveOptions);
//close the document
currentDoc.close(SaveOptions.DONOTSAVECHANGES);
//keep loop running
j = j + 1;
//reset negPos multiplier
negPos = 1;
}//end If
}//end While
/////////////////////////FUNCTIONS/////////////////////////////////////////////////////
//include the function in the script file
function applyThreshold(value)
{
var idThrs = charIDToTypeID( "Thrs" );
var desc2 = new ActionDescriptor();
var idLvl = charIDToTypeID( "Lvl " );
desc2.putInteger( idLvl, value );
executeAction( idThrs, desc2, DialogModes.NO );
}//end applyThreshold----------------------------------------------
//if selection anchor[0] is on left side of document
function leftAnchor(largeX, smallY){
var opSide = largeX[1] - smallY[1];
var adSide = largeX[0] - smallY[0];
var hySide = Math.sqrt((opSide*opSide) + (adSide*adSide));
var invSin = Math.asin(opSide/hySide);
var angle = invSin * (180/Math.PI);
//alert(angle);
return angle;
}//end function-------------------------------------------------------
//if selection is on right side of document
function rightAnchor(smallX, smallY){
var opSide = smallX[1] - smallY[1];
var adSide = smallY[0]- smallX[0];
var hySide = Math.sqrt((opSide*opSide) + (adSide*adSide));
var invSin = Math.asin(opSide/hySide);
var angle = invSin * (180/Math.PI);
//alert(angle);
return angle;
}//end function------------------------------------------------------
//find the smallest x anchor in selection path
function findSmallestX(pathLength, smallXF){
for (var i=0; i<pathLength; i++) {
//store the X coordinate for current anchor in loop
var xTemp = wPath.subPathItems[0].pathPoints.anchor;
//only if y value is in top half of document
//find the smallest X coordinate anchor
if(smallXF[0] >= xTemp[0]){
smallXF = xTemp;
}//if x small
}//for y small
return smallXF;
}//end function------------------------------------------------------
//find the smallest y anchor in selection path
function findSmallestY(pathLength, smallYF){
for (var h=0; h<pathLength; h++) {
//store the X coordinate for current anchor in loop
var yTemp = wPath.subPathItems[0].pathPoints[h].anchor;
//find the smallest Y coordinate anchor
if(smallYF[1] >= yTemp[1]){
smallYF = yTemp;
}//if x small
}//for y small
return smallYF;
}//end function------------------------------------------------------
//find the largest x anchor in selection path
function findLargestX(pathLength, largeXF){
for (var m=0; m<pathLength; m++) {
//store the X coordinate for current anchor in loop
var xTemp = wPath.subPathItems[0].pathPoints[m].anchor;
//find the smallest X coordinate anchor
if(largeXF[0] <= xTemp[0]){
largeXF = xTemp;
}//if x small
}//for y small
return largeXF;
}//end function------------------------------------------------------
//find the largest y anchor in selection path
function findLargestY(pathLength, largeYF){
for (var n=0; n<pathLength; n++) {
//store the X coordinate for current anchor in loop
var yTemp = wPath.subPathItems[0].pathPoints[n].anchor;
//find the smallest X coordinate anchor
if(largeYF[1] <= yTemp[1]){
largeYF = yTemp;
}//if x small
}//for y small
return largeYF;
}//end function------------------------------------------------------
function selectSelect(pntX, pntY)
{
var idsetd = charIDToTypeID( "setd" );
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref1 = new ActionReference();
var idChnl = charIDToTypeID( "Chnl" );
var idfsel = charIDToTypeID( "fsel" );
ref1.putProperty( idChnl, idfsel );
desc2.putReference( idnull, ref1 );
var idT = charIDToTypeID( "T " );
var desc3 = new ActionDescriptor();
var idHrzn = charIDToTypeID( "Hrzn" );
var idPxl = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( idHrzn, idPxl, pntX);////width point (X)
var idVrtc = charIDToTypeID( "Vrtc" );
var idPxl = charIDToTypeID( "#Pxl" );
desc3.putUnitDouble( idVrtc, idPxl, pntY);////height point (Y)
var idPnt = charIDToTypeID( "Pnt " );
desc2.putObject( idT, idPnt, desc3 );
var idTlrn = charIDToTypeID( "Tlrn" );
desc2.putInteger( idTlrn, tolR );
var idAntA = charIDToTypeID( "AntA" );
desc2.putBoolean( idAntA, true );
executeAction( idsetd, desc2, DialogModes.NO );
}//end function-------------------------------------------------------
//restore image to original
function revertHistory(){
executeAction( charIDToTypeID( "Rvrt" ), undefined, DialogModes.NO );
}// end function------------------------------------------------------
Re: return specific coordinates of selection. PathItem?
I was curious for this script but does seem to work no more in PS 22. It stops at the first image just after the path is created. On Windows i dont get any error nor feedback?
I ran a check with alerts and it stops after the function "smallX = findSmallestX(pathLength, origAnchor);"
I found some of the functions seem to have lost some declarations
In the function findSmallestX it misses in the for loop when the var is declared. I ran the script on a couple images but im not sure what it does. I cant see the original image in the first post. My guess it straightens the image bases on those colors you stated. On my test images it did nothing, only saved out TIF files
I ran a check with alerts and it stops after the function "smallX = findSmallestX(pathLength, origAnchor);"
I found some of the functions seem to have lost some declarations
In the function findSmallestX it misses in the for loop when the var is declared. I ran the script on a couple images but im not sure what it does. I cant see the original image in the first post. My guess it straightens the image bases on those colors you stated. On my test images it did nothing, only saved out TIF files
Re: return specific coordinates of selection. PathItem?
I ran another test, it seems to stop on PSD files as well as if there are subolders in the source folder. I created a test image with a green rotated rectangle. It does seem to find bound edges, not sure what the rotate should do. Perhaps i got the wrong threshold.
Its an interesting script, i alway like to learn and see what other people do
Source image

Resulting image

Its an interesting script, i alway like to learn and see what other people do

Source image

Resulting image

Re: return specific coordinates of selection. PathItem?
Its fun trying to figure this one out. I cant seem to figure out how the original image should look. But with my example it always seems to crop it.
If i alter that second crop function and change you method of cropping. I did get it to almost straighten this image. Thats pretty impressive
But i think this is just eye balling what im doing. I removed that negPos * cropAngle and changed it to (cropAngle / 10)
The angle was always completly off, but it looks like a number which was a multiplied. The real angle of that rectangle is 3deg, the crop angle result i get is 37. something. Si divide it by 10 and i get these. Im gonna check more image, see if its working haha
Source image

Result with altered crop function

If i alter that second crop function and change you method of cropping. I did get it to almost straighten this image. Thats pretty impressive
But i think this is just eye balling what im doing. I removed that negPos * cropAngle and changed it to (cropAngle / 10)
The angle was always completly off, but it looks like a number which was a multiplied. The real angle of that rectangle is 3deg, the crop angle result i get is 37. something. Si divide it by 10 and i get these. Im gonna check more image, see if its working haha
Source image

Result with altered crop function
