Skip to main content
Participating Frequently
February 25, 2018
Answered

Stretch image in one dimension

  • February 25, 2018
  • 2 replies
  • 6585 views

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

This topic has been closed for replies.
Correct answer Peter Kahrel

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

P.

2 replies

Marc Autret
Legend
March 3, 2018

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.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.constructor.name+".");

            return;

        }

        a = (t=a.properties[i===PGE?'bounds':'geometricBounds']);

        a.width = t[3]-t[1];

        a.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],a[IMG])-a[PGE]);

        // 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 ) 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;

    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 = a[PGE]+dpg;

    o[2^i] = o-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

Marc Autret
Legend
March 3, 2018

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

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

stuarth64Author
Participating Frequently
March 4, 2018

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

Peter Kahrel
Community Expert
Peter KahrelCommunity ExpertCorrect answer
Community Expert
February 26, 2018

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

P.

stuarth64Author
Participating Frequently
February 26, 2018

Thank you Peter.

stuarth64Author
Participating Frequently
March 3, 2018

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.