// These macros expand or shrink a selection by a specified 
// distance or by an area percentage. 
// 
// 2005/08/15: Expands and shrinks using EDM instead of
// dilation and erosion. Added  "Make Selection Band" macro.

  var n = 5; 
  var percent = 20; 

  macro 'Expand Selection...' { 
       getPixelSize(unit, pixelWidth, pixelHeight) 
       n = getNumber("Expansion Factor ("+unit+"):", n); 
       pixels = n/pixelWidth; 
       expandUsingEDM(pixels); 
   } 

   macro 'Shrink Selection... [S]' { 
       getPixelSize(unit, pixelWidth, pixelHeight) 
       n = getNumber("Shrink Factor ("+unit+"):", n); 
       pixels = n/pixelWidth; 
       shrinkUsingEDM(pixels); 
   } 

   macro 'Expand by Percentage...' { 
       percent = getNumber("Percent to Expand:", percent); 
       area = (100+percent)*pixelCount()/100; 
       do { 
           resize(1); 
       } while (pixelCount()<area); 
   } 

   macro 'Shrink by Percentage...' { 
       percent = getNumber("Percent to Shrink:", percent); 
       area = (100-percent)*pixelCount()/100; 
       do { 
           resize(-1); 
       } while (pixelCount()>area); 
   } 

  macro 'Make Selection Band...' { 
       getPixelSize(unit, pixelWidth, pixelHeight) 
       n = getNumber("Band Width ("+unit+"):", n); 
       pixels = n/pixelWidth; 
       makeBandUsingEDM(pixels); 
   } 

    function resize(n) { 
       requires("1.33o"); 
       type = selectionType(); 
       if (type==0) { 
           getBoundingRect(x, y, width, height); 
           makeRectangle(x-n, y-n, width+n*2, height+n*2); 
      } else if (type==1) { 
           getBoundingRect(x, y, width, height); 
           makeOval(x-n, y-n, width+n*2, height+n*2); 
      } else 
           resizeMask(n); 
   } 

  function resizeMask(n) { 
       id = getImageID(); 
       setBatchMode(true); 
       getBoundingRect(xbase, ybase, width, height); 
       run("Create Mask"); 
       iterations = abs(n); 
       while (iterations>0) { 
           count = iterations; 
           if (count>25) count = 25; 
           run("Options...", "count=1 iterations="+count); 
           if (n>0) 
               run("Dilate"); 
           else 
               run("Erode"); 
           iterations -= count; 
       } 
       x2=-1; y2=-1; 
       inc = 1; 
       if (width>5 && height>5) 
           inc = 5; 
       for (x=xbase; x<xbase+width; x+=inc) { 
           for (y=ybase; y<ybase+height; y+=inc) { 
               if (getPixel(x,y)==255) { 
                   x2= x; 
                   y2 = y; 
               } 
           } 
       } 
       if (x2==-1) 
           print('Selection is too small'); 
      else 
           doWand(x2, y2); 
       close(); 
       selectImage(id); 
       run("Restore Selection"); 
   } 

   function pixelCount() { 
       getHistogram(values, counts, 256); 
       n = 0; 
       for (i=0; i<256; i++) 
           n += counts[i]; 
       return n; 
   } 

  function expandUsingEDM(n) { 
       if (pixels >255) 
           exit("Cannot resize by more than 255 pixels"); 
       id = getImageID(); 
       setBatchMode(true); 
       getBoundingRect(xbase, ybase, width, height); 
       getSelectionCoordinates(xc,yc); 
       run("Create Mask"); 
       run("Invert"); 
       run("Options...", "iterations=1 count=1"); 
       run("Distance Map"); 
       setThreshold(0, n); 
       x = xbase + width/2; 
       y = ybase + height/2; 
       count = 0; 
       while(getPixel(x,y)>n) { 
           if (count++==10000) 
               exit("Unable to scale selection"); 
           x = xbase + width*random(); 
           y = ybase + height*random(); 
       } 
       doWand(x, y); 
       close(); 
       selectImage(id); 
       run("Restore Selection"); 
   } 

   function shrinkUsingEDM(n) { 
       if (pixels >255) 
           exit("Cannot resize by more than 255 pixels"); 
       id = getImageID(); 
       setBatchMode(true); 
       getBoundingRect(xbase, ybase, width, height); 
       getSelectionCoordinates(xc,yc); 
       run("Create Mask"); 
       run("Options...", "iterations=1 count=1"); 
       run("Distance Map"); 
       setThreshold(0, n); 
       x = xbase + width/2; 
       y = ybase + height/2; 
       count = 0; 
       while(getPixel(x,y)<=n) { 
           if (count++==10000) 
               exit("Unable to scale selection"); 
           x = xbase + width*random(); 
           y = ybase + height*random(); 
       } 
       doWand(x, y); 
       close(); 
       selectImage(id); 
       run("Restore Selection"); 
   } 

   function makeBandUsingEDM(n) { 
        if (pixels >255) 
           exit("Cannot resize by more than 255 pixels"); 
       id = getImageID(); 
       setBatchMode(true); 
       getBoundingRect(xbase, ybase, width, height); 
       getSelectionCoordinates(xc,yc); 
       run("Create Mask"); 
       run("Invert"); 
       run("Options...", "iterations=1 count=1"); 
       run("Distance Map"); 
       setThreshold(0, n); 
       x = xbase + width/2; 
       y = ybase + height/2; 
       count = 0; 
       while(getPixel(x,y)>n) { 
           if (count++==10000) 
               exit("Unable to scale selection"); 
           x = xbase + width*random(); 
           y = ybase + height*random(); 
       } 
       doWand(x, y); 
       setKeyDown('alt'); 
       makeSelection("polygon", xc, yc); 
       close(); 
       selectImage(id); 
       run("Restore Selection"); 
   } 
