7 Replies Latest reply on Aug 2, 2013 3:41 AM by mdidish84

    draw line between black pixel : coordinates of selected pixels ?

    mdidish84

      Hi

      I want to build a script which can check a Photoshop file and :

      - find black pixel

      - for each black pixel, look for another black pixel within maximum distance of 5 pixels

      - then draw a line between the two black pixels.

       

      I wrote this script below (my first script ...), but it's VERY slow (and my final image is VERY big), I think because I test the colour for each pixel of the image.

       

      So another solution would be to first select black pixel with magic wand, then the script save all coordinates of selected pixels, then my script wil test only this pixels (less than 1% of the pixels are black in my image).

      Is it possible with JavaScript ?

       

      Thank you for your response !

      Marc

       

       

      function main(){
       var startRulerUnits = app.preferences.rulerUnits;
       app.preferences.rulerUnits = Units.PIXELS;
      
      
       var myHeight = app.activeDocument.height;
       var myWidth = app.activeDocument.width;
      
      
      // Find black pixel
       for(var i=5; i<myWidth; i++) {
        for(var j=5; j<myHeight; j++) {
         activeDocument.colorSamplers.removeAll()
         var sampler = activeDocument.colorSamplers.add([new UnitValue (i, 'px'), new UnitValue (j, 'px')]);
         if (sampler.color.rgb.hexValue === "000000") {
      
      
      // For each black pixel, search another black pixel below left up to 5 pixels
          for (var m=i-5; m<i; m++) {
           for (var n=j+1; n<j+5; n++) {
            activeDocument.colorSamplers.removeAll()
            var test = activeDocument.colorSamplers.add([new UnitValue (m, 'px'), new UnitValue (n, 'px')]);
            if (test.color.rgb.hexValue === "000000") {
      
      
      // Then draw a black line between the two black pixels
             var FillColour = new SolidColor;
             FillColour.rgb.hexValue = '000000';
             var ad=activeDocument;
             ad.selection.select([[m,n],[i,j],[m,n+1],[i,j+1]], SelectionType.REPLACE, 0, true);
             ad.selection.fill(FillColour);
             ad.selection.deselect()
            }
           }
      
      
      // For each black pixel, search another black pixel below right up to 5 pixels
           for (var m=i+1; m<i+5; m++) {
            for (var n=j; n<j+5; n++) {
             activeDocument.colorSamplers.removeAll()
             var test = activeDocument.colorSamplers.add([new UnitValue (m, 'px'), new UnitValue (n, 'px')]);
             if (test.color.rgb.hexValue === "000000") {
      
      
      // Then draw a black line between the two black pixels
              var FillColour = new SolidColor;
              FillColour.rgb.hexValue = '000000';
              var ad=activeDocument;
              ad.selection.select([[i,j],[m,n],[m,n+1],[i,j+1]], SelectionType.REPLACE, 0, true);
              ad.selection.fill(FillColour);
              ad.selection.deselect()
             }
            }
           }
          }
         }
        }
       }
      }
      main();
      
      
        • 1. Re: draw line between black pixel : coordinates of selected pixels ?
          Michael L Hale Level 5

          I think this task will be slow using javascript no matter how it is done.

           

          You could use select color range to select the black pixels. But the selection bounds would include all the black pixels. You will not be able to tell where each black pixel is from the selection directly. You could convert the selection into a path. From the path you could get the x,y position of each subpath point to get the bounds of each pixel. I haven't tested this but you might only have to check the first pathpoint in each subpath to get the top left x,y position of the pixel. And there may be some top left to right bottom order in the subpaths that you could take advantage of.

           

          Once you have the positions of each black point from the path the script should be able to determine if any are within 5px of each other just using those positions.

          • 2. Re: draw line between black pixel : coordinates of selected pixels ?
            mdidish84 Level 1

            Michael L Hale a écrit:

             

            From the path you could get the x,y position of each subpath point to get the bounds of each pixel.

            Thank you for your proposition.

            How can I get the x,y position of each subpath point ? When I try I obtain only the x,y position of each corner for the first subpath only ?

            Marc

            • 3. Re: draw line between black pixel : coordinates of selected pixels ?
              Michael L Hale Level 5

              As I said, I didn't test this approach. I can't get Photoshop CC to convert single pixel selections into a path even when setting the tolerance to its minimum value. Are you sure your converted path has single pixel areas?

               

              But to answer your question about how to get the positions of the path points -

               

              function extractSubPathInfo(pathObj){
                  var pathArray = new Array();
                  var pl = pathObj.subPathItems.length;
                  for(var s=0;s<pl;s++){
                      var pArray = new Array();
                        for(var i=0;i<pathObj.subPathItems[s].pathPoints.length;i++){
                           pArray[i] = new PathPointInfo;
                           pArray[i].kind = pathObj.subPathItems[s].pathPoints[i].kind;
                           pArray[i].anchor = pathObj.subPathItems[s].pathPoints[i].anchor;
                           pArray[i].leftDirection = pathObj.subPathItems[s].pathPoints[i].leftDirection;
                           pArray[i].rightDirection = pathObj.subPathItems[s].pathPoints[i].rightDirection;
                        };
                      pathArray[pathArray.length] = new Array();
                      pathArray[pathArray.length - 1] = new SubPathInfo();
                      pathArray[pathArray.length - 1].operation = pathObj.subPathItems[s].operation;
                      pathArray[pathArray.length - 1].closed = pathObj.subPathItems[s].closed;
                      pathArray[pathArray.length - 1].entireSubPath = pArray;
                  };
                  return pathArray;
              };
              var myPathInfo = extractSubPathInfo(app.activeDocument.pathItems.getByName('Path 1'));
              var xyArray = [];
              // get the first pathPoint.anchor from each subPath
              for(spIndex=0;spIndex<myPathInfo.length;spIndex++){
                  xyArray.push(myPathInfo[spIndex].entireSubPath[0].anchor);
              }
              alert('All the first anchors:\r'+xyArray);
              alert('The first pathPoint from the first subPath:\r'+xyArray[0]);
              
              • 4. Re: draw line between black pixel : coordinates of selected pixels ?
                mdidish84 Level 1

                Thank you for your script, now I can get coordinates of the first pathPoint.anchor from each subPath and not only from the first subPath.

                To be perfect, I would like get coordinates of the entire outline of each subPath; is it possible ? Is there a limit of information for the variable xyArray ?

                • 5. Re: draw line between black pixel : coordinates of selected pixels ?
                  Michael L Hale Level 5

                  The first alert should have shown the first pathPoint.anchors for all the subPaths in the path.

                   

                  The xyArray is just something I added for the alerts. The array 'myPathInfo' should have all the info extracted from the path.

                   

                  myPathInfo.length will tell you how many subPaths are in the Path.

                  myPathInfo[index].entireSubPath.length will tell you how many pathPoints are in that subPath

                  myPathInfo[index].entireSubPath[index].anchor will tell you the position of that pathPoint.

                   

                  The indexes start with zero.

                   

                  The bounding box of the entire subPath can be hard to work out just from the pathPoints. Unless all the point are corner points the path may extend beyond the anchors. One think you can do is create a new path from just one of the subPaths, convert by to a selection, and then get the bounds from the selection. You can make a new path from a subPath using the 'myPathInfo' array from above.

                   

                  app.activeDocument.pathItems.add("myPath1", [myPathInfo[0]]);
                  

                  That line will make a new path from the first subPath. Change the index to use a different subPath.

                   

                  Some other info that may help.

                  app.activeDocument.histogram[0] will tell you how may black pixels are in the document. But its no help determining where they are. If that returns 0 there are no black pixels.

                  If you don't have any luck working with converting the original color range selection into a path and need to go back to searching with the colorSampler it may help to use a grid approach. For example make a square selection, the size depending on how scattered the black pixels are, say 25x25px. Then use color range to select black. With an active selection it will only select pixels in that selected area( if any). You could then check to see if there is a selection. If not make another same size square to the right edge of the last area. If there is a selection, the solid property will tell you if more than one black pixel was selected( unless they are right next to each other ). If solid == true the selection bounds will tell you where the pixel is. If false you have to then search that square. But if there are areas where there are no black pixels checking a square range of pixels at once should be quite a bit faster than checking every pixel. And checking the historgram first will let you know if you should bother searching to start with.

                  • 6. Re: draw line between black pixel : coordinates of selected pixels ?
                    mdidish84 Level 1

                    Sorry for the delay.

                    Thank you for your answer and all the details; unfortunately I can not get my goal with JS and Photoshop. I'll get another software (ImageJ ?).

                    If someone else has a suggestion, let me know.

                    Marc

                    • 7. Re: draw line between black pixel : coordinates of selected pixels ?
                      mdidish84 Level 1

                      If someone wants to do the same thing, the ImageJ software works very well on very large images (1 billion pixels) by the process according to> binary> close