return specific coordinates of selection. PathItem?

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

joacampb

return specific coordinates of selection. PathItem?

Post by joacampb »




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!
pfaffenbichler

return specific coordinates of selection. PathItem?

Post by pfaffenbichler »

How many points does the path have?
joacampb

return specific coordinates of selection. PathItem?

Post by joacampb »

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------------------------------------------------------
schroef
Posts: 33
Joined: Sat Apr 11, 2020 6:22 am

Re: return specific coordinates of selection. PathItem?

Post by schroef »

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
schroef
Posts: 33
Joined: Sat Apr 11, 2020 6:22 am

Re: return specific coordinates of selection. PathItem?

Post by schroef »

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
Image

Resulting image
Image
schroef
Posts: 33
Joined: Sat Apr 11, 2020 6:22 am

Re: return specific coordinates of selection. PathItem?

Post by schroef »

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
Image

Result with altered crop function
Image