15 Replies Latest reply on Mar 28, 2018 7:57 PM by Marc Autret

    Stretch image in one dimension

    stuarth64

      Hi, I need to create a slice of an image and then stretch it either horizontally or vertically by a few millimetres. This would be the same as holding down the Command or Control key while dragging on a handle. Any help would be much appreciated.

      Stuart

        • 1. Re: Stretch image in one dimension
          Peter Kahrel Adobe Community Professional & MVP

          Just set the horizontalScale of the image's container (a rectangle).

           

          P.

          • 2. Re: Stretch image in one dimension
            stuarth64 Level 1

            Thank you Peter.

            • 3. Re: Stretch image in one dimension
              stuarth64 Level 1

              Hi Peter,

               

              I finally got round to trying this but it's not the solution I need. What I'm trying to do is create missing bleed by duplicating a thin slice of the image, just in from each edge and then have the script replicate the action of dragging the centre outer handle out by a couple of millimetres while holding down the Command key.

               

              I would really appreciate any help you or anyone else can offer.

              • 4. Re: Stretch image in one dimension
                Peter Kahrel Adobe Community Professional & MVP

                This is a bit difficult to visualise. Maybe it's time to show us a before and after illustration.

                • 5. Re: Stretch image in one dimension
                  Marc Autret Level 5

                  Hi all,

                   

                  Not sure I clearly understood the goal, but it was really exciting to play with the idea.

                   

                  Here is a first try, and first draft of my AutoFeedSlug script.

                   

                  function nonZero(/*num*/x,  e)
                  //----------------------------------------------------------
                  // EPSILON-aware nonzero test.
                  {
                      e = Math.pow(2,-51);
                      return ( 0 > x ? -x : x ) > e;
                  };
                  
                  function autoFeedSlug(/*?Image[0]*/img,  pge,rec,side,dpg,snap,edge,a,i,t,s,o)
                  //----------------------------------------------------------
                  // Given an Image that should extend up to the slug but has not enough material,
                  // try to feed the missing area by fitting and rescaling a slice of the picture.
                  // [REM] The code autodetects the edge of interest, provided the image presents any
                  // border close to a page edge. (Also, make sure the container has no stroke.)
                  {
                      // Settings and constants.
                      // ---
                      const SNAP = .05;            // 5% of the lowest page dim.
                      const FIT_FACTOR = 2;        // Should be 2 (IMHO) to optimize the joint.
                      const PGE=0, REC=1, IMG=2;   // Simple enum.
                      // ---
                      const CS_SPREAD = +CoordinateSpaces.SPREAD_COORDINATES;
                      const BB_GEO = +BoundingBoxLimits.GEOMETRIC_PATH_BOUNDS;
                      const RM_MULT = +ResizeMethods.MULTIPLYING_CURRENT_DIMENSIONS_BY;
                      const RC_KEEP = +ResizeConstraints.KEEP_CURRENT_VALUE;
                      const PS_LEFT = +PageSideOptions.LEFT_HAND;
                      const PS_RIGHT = +PageSideOptions.RIGHT_HAND;
                  
                      // Checkpoints.
                      // ---
                      if( FIT_FACTOR <= 1 )
                      {
                          alert("The FIT_FACTOR setting must be greater than 1.");
                      }
                      while( (!img) || (1!=img.length) || !((img=img[0]) instanceof Image) )
                      {
                          if( img.hasOwnProperty('images') && (img=img.images).length && ((img=img[0]) instanceof Image) ) break;
                          alert("Select an Image.");
                          return;
                      }
                      if( !(pge=img.properties.parentPage) )
                      {
                          alert("The Image must be on a page.");
                          return;
                      }
                      if( !((rec=img.parent) instanceof Rectangle) || (0 < rec.properties.strokeWeight) )
                      {
                          alert("The Image must belong to a rectangular box having no stroke.");
                          return;
                      }
                  
                      // Metrics.
                      // => `a` :: [ pageTLBR, recTLBR, imgTLBR ]
                      // ---
                      for( a=[pge,rec,img], i=PGE ; i <= IMG ; ++i )
                      {
                          t = a[i].transformValuesOf(CS_SPREAD)[0].matrixValues;
                          if( nonZero(t[0]*t[1]) || nonZero(t[2]*t[3]) )
                          {
                              alert("No weird rotation should be applied to the "+a[i].constructor.name+".");
                              return;
                          }
                          a[i] = (t=a[i].properties[i===PGE?'bounds':'geometricBounds']);
                          a[i].width = t[3]-t[1];
                          a[i].height = t[2]-t[0];
                      }
                  
                      // Page side.
                      // => `side` :: -1_left  |  0_single  |  +1_right
                      // ---
                      side = +(0 < pge.documentOffset && pge.side);
                      side = (side==PS_RIGHT)-(side==PS_LEFT);
                  
                      // Bleed.
                      // => `dpg` :: [-top,-left, +bot,+right]
                      // ---
                      t = resolve(pge.toSpecifier().replace(/\/\/.+/,''));
                      if( !(t instanceof Document) ) throw "Unable to find the parent document."
                      t = t.documentPreferences.properties;
                      dpg = t.documentBleedUniformSize ?
                          ( (t=t.documentBleedTopOffset), [-t,-t,t,t] ) :
                          [
                              -t.documentBleedTopOffset,
                              -t.documentBleedInsideOrLeftOffset,
                              t.documentBleedBottomOffset,
                              t.documentBleedOutsideOrRightOffset
                          ];
                  
                      // Identify the most relevant edge.
                      // => edge :: { 0:TLBR-index, dist:num }, -BLEED < dist < SNAP
                      // ---
                      snap = SNAP*Math.min(a[PGE].width, a[PGE].height);
                      for( (edge=[i=-1]).dist=1/0 ; ++i < 4 ; )
                      {
                          // i :: 0_top ; 1_left ; 2_bot ; 3_right
                          // Calculate the algebraic distance.
                          // ---
                          s = 2 > i ? 1 : -1;
                          t = s*(Math[0<s?'max':'min'](a[REC][i],a[IMG][i])-a[PGE][i]);
                  
                          // Skip this edge if its distance to page > snap zone.
                          // ---
                          if( t > snap ) continue;
                          
                          // Skip this edge if it already reaches the bleed.
                          // ---
                          if( t <= s*dpg[i] ) continue;
                  
                          // Skip this edge if it regards the spine.
                          // ---
                          if( side && side==2-i ) continue;
                  
                          t < edge.dist && (edge[0]=i,edge.dist=t);
                      }
                      
                      if( 0 > (i=edge[0]) )
                      {
                          alert("Unable to find the relevant edge. Make sure the image is in the snap zone.");
                          return;
                      }
                      
                      // ---
                      // Process.
                      // ---
                      
                      // First, duplicate the rec applying the proper shift.
                      // ---
                      edge[0] = edge.dist*(2 > i ? -1 : 1) + dpg[i];
                      edge[(1&i)?'push':'unshift'](0);
                      t = rec.duplicate(void 0,edge);
                      
                      // Make sure autofit is off.
                      // ---
                      t.hasOwnProperty('frameFittingOptions') && t.clearFrameFittingOptions();
                      
                      // Adjust the geometric bounds.
                      // ---
                      o = t.geometricBounds;
                      o[i] = a[PGE][i]+dpg[i];
                      o[2^i] = o[i]-FIT_FACTOR*edge[1-(1&i)];
                      t.geometricBounds = o;
                      
                      // Resize the inner image to fit.
                      // ---
                      img = t.images[0].getElements()[0];
                      
                      // Ok this step is a bit hacky, but basically
                      // we want an anchor point in the form [u,v].
                      // i==0  -->  [u,v]==[.5,0]  i.e center-TOP
                      // i==1  -->  [u,v]==[0,.5]  i.e LEFT-center
                      // i==2  -->  [u,v]==[.5,1]  i.e center-BOTTOM
                      // i==3  -->  [u,v]==[1,.5]  i.e RIGHT-center
                      // ---
                      // It is important to resolve the location of
                      // of that anchor relative to the container `t`,
                      // not relative to the image bounding box, for
                      // the image area may exceed the area of its
                      // container! We must use the correct origin
                      // in the resize transformation.
                      // ---
                      (ap=[.5])[(1&i)?'unshift':'push'](+(i>1));
                      ap = t.resolve([ap,BB_GEO,CS_SPREAD],CS_SPREAD)[0];
                  
                      // Why do I use `resize()`? Because I'm not definitely
                      // sure that 90 or 180 angles and/or reflections
                      // applied to either the frame or the image couldn't
                      // make fail naive methods. Resizing is reliable.
                      // ---
                      (a=[RC_KEEP])[(1&i)?'unshift':'push'](FIT_FACTOR);
                      img.resize(
                          CS_SPREAD,        // In-spread bounding box of the Image.
                          [ap,CS_SPREAD],   // Origin as computed above (in the spread space)
                          RM_MULT,          // Multiply the size by FIT_FACTOR...
                          a);               // ...along the desired dimension.
                  
                      app.select(null);
                  };
                  
                  
                  app.doScript("autoFeedSlug(app.properties.selection)",
                      ScriptLanguage.JAVASCRIPT,void 0,UndoModes.ENTIRE_SCRIPT,"AutoFeedSlug");
                  

                   

                   

                  And here is a quick demo (not sure the link works):

                  AutoFeedSlug - YouTube

                   

                   

                   

                   

                   

                  Best,

                  Marc

                  2 people found this helpful
                  • 6. Re: Stretch image in one dimension
                    Marc Autret Level 5

                    As you have noted I constantly confuse the words 'bleed' and 'slug.'

                    So FeedBleed would probably be a better name for that script…

                    • 7. Re: Stretch image in one dimension
                      stuarth64 Level 1

                      Hi Marc,

                       

                      Wow! Thank you so much, this is exactly the process I had in mind and I'm sure will prove useful to a lot of people. My problem now is that I would like to incorporate this action into a larger script of my own that will do this as part of a larger process. You are clearly a very advanced scripter and I am struggling to identify the relevant parts of your code.

                       

                      In my script I know that part of the image will touch at least one edge. I have replicated slices of the image on all four edges (and would also need to do corner squares) using the duplicate method and then changing the geometric bounds but I haven't been able to figure out how to stretch the image at the same time.

                       

                      Any help is greatly appreciated.

                       

                      Regards

                      Stuart

                      • 8. Re: Stretch image in one dimension
                        Marc Autret Level 5

                        Hi Stuart,

                         

                        (…) I haven't been able to figure out how to stretch the image at the same time.

                         

                        The end of the code treats this part of the question:

                         

                        // . . .

                        img.resize(CS_SPREAD, origin, RM_MULT, a);

                         

                        I prefer using resize over other approaches because that's a very flexible method. In particular, we have to be very careful about the origin of the transformation. Although resizing is applied to the image itself, the origin is calculated with respect to the block edge at this specific moment, keeping in mind that the image bounds may exceed the bounds of the frame. So we cannot blindly perform the transformation from the image edge coordinates, we need to find the exact origin inside the area to get a clean joint. The below animation illustrates this point:

                         

                        FeedBleed.gif

                         

                        @+

                        Marc

                        1 person found this helpful
                        • 9. Re: Stretch image in one dimension
                          Liphou Level 2

                          Merci Marc, c'est toujours un régale de voir vos script et votre méthode de travail.

                          PS j'adore la traduction  du mots 'slug'.

                           

                          Merci

                          • 10. Re: Stretch image in one dimension
                            Laubender Adobe Community Professional & MVP

                            Hi Marc,

                            thank you for that first draft!

                             

                            If you are willing to go on with this I'd say: First check if an image could perhaps reach to fill the bleed without transformation.

                            That would require to move the path points of the container frame to the edge of the bleed area.

                             

                            But perhaps this is better up to the user to decide. The script is running on a selection so the user should be responsible to first check if a "natural" bleed is possible from the start before running any bleed filling script.

                             

                            Thanks,
                            Uwe

                            3 people found this helpful
                            • 11. Re: Stretch image in one dimension
                              Marc Autret Level 5

                              Hi Uwe,

                               

                              Thanks for your feedback.

                               

                              Laubender  a écrit

                               

                              (…) First check if an image could perhaps reach to fill the bleed without transformation.

                               

                              Yes that should be an option (and this is easy to implement from my code). But as illustrated in the anim, even if the image already contains enough material for filling the bleed, the user may want to keep masked that part of the image. For example, in case he deliberately trimmed the frame for removing a graphic border or any undesired element of the picture.

                               

                              So, better is to provide a boolean flag KEEP_FRAME_AS_TRIMMED, isn't it?

                               

                              @+

                              Marc

                              • 12. Re: Stretch image in one dimension
                                Laubender Adobe Community Professional & MVP

                                Ah yes. Of course that will be a valid option.

                                Only the user may decide on showing parts of an image, not an automation per se…

                                 

                                Thanks,
                                Uwe

                                • 13. Re: Stretch image in one dimension
                                  stuarth64 Level 1

                                  Hi Marc,

                                   

                                  Thank you so much for your help with this. I will definitely look into the resize method as I was not aware this existed.

                                   

                                  Regards

                                  Stuart

                                  • 14. Re: Stretch image in one dimension
                                    Marc Autret Level 5

                                    So I made a more advanced script.

                                     

                                    New name: FillBleed. Supports CS4/CS5/CS6/CC and provides localization in EN (default), FR, DE, ES.

                                     

                                    Here is how the UI of version 1.03 beta look like:

                                     

                                    FillBleedUI_en.png

                                     

                                    Download and test: http://indiscripts.com/blog/public/scripts/FillBleed.jsx

                                     

                                    Note: This script is entirely based on IdExtenso's BasicScript module:

                                    IdExtenso/$$.BasicScript.jsxlib at master · indiscripts/IdExtenso · GitHub

                                    This was a perfect example for testing a real-world application of all its features :-)

                                     

                                     

                                    @+

                                    Marc

                                    1 person found this helpful
                                    • 15. Re: Stretch image in one dimension
                                      Marc Autret Level 5

                                      Hi all,

                                       

                                      Something more official now if you're interested in testing FillBleed (1.0 beta):

                                       

                                      Tutorial:

                                       

                                       

                                      Download: Indiscripts :: FillBleed [beta] | Fix Image Frames so they Meet the Bleed Edge

                                       

                                      Best,

                                      Marc