Skip to main content
This topic has been closed for replies.
Correct answer Marc Autret

Hi Marc,

I tried the modified version of of the script and it gave the same results as we discussed before. for ease, I have already attached a sample document and hope that it will fulfill the purpose for testing. Hope to see this through.

Regards,

Aman


Hi Aman,

1. The sample document contains aboveLine anchors (not only pure inline.) I found that in such case rescaling to the height of the text frame is not sufficient to wake up the ghost object. An advanced product could surely work around this using smart calculations and so. But here I will consider the inline mode as a requirement, so the version below just converts any aboveLine anchor into inline. (Recall that custom anchored objects are ignored.)

2. Smart text reflow is not properly configured in the sample document. AFAIK, the master spread (applied to page 1) should have primary text frames, which should be chained due to facing pages, and the frame on page 1 should instantiate the master frame. The other pages can be removed by the script as a first step.

Then the code below worked for me.

Again, we may provide an automated check-and-repair mechanism regarding the issues above, but it's not technically interesting (and quite boring to implement), so better is to let the user prepare the input document as specified. (A simple document preset would solve this once for all.)

function fixAndDownscaleInlines(  q,doc,t,wso,n,items,chars,z,c,o,aos,k,wh,xy,x,y)

//----------------------------------

// [180621] Force inline anchoring when aboveLine is found.

// [180619] Added `document.recompose()` to force smart reflow to update.

// This function proportionnaly downscale every *inline* or

// *aboveLine* anchored item found in the document, so that:

// 1. Target width does not exceed parent frame width (PFW.)

// 2. Targets whose width is *under* PFW are not touched.

// 3. Objects whose height exceeds the parent frame height (then causing

//    overset issues that SmartTextReflow can't fix) are temporarily

//    downscaled so that the algorithm can eat them. When available back,

//    those objects are adjusted to the frame height unless width adjustment

//    is required instead (to prevent them from violating rule 1.)

// Note: Smart Text Reflow must be turned on and properly set.

{

    // Cache and constants.

    // ---

    q = (callee.Q||callee.Q={});

    const EPSILON = 1e-3,

          DOWN = 100, // Downscaling factor

          ANCH = +AnchorPosition.ANCHORED,

          ABOV = +AnchorPosition.ABOVE_LINE,

          INLN = +AnchorPosition.INLINE_POSITION,

          // ---

          CPAR = +CoordinateSpaces.parentCoordinates,

          CINN = +CoordinateSpaces.innerCoordinates,

          BVSB = +BoundingBoxLimits.outerStrokeBounds,

          // ---

          PAR0 = [+AnchorPoint.topLeftAnchor, BVSB],

          PAR1 = [+AnchorPoint.bottomRightAnchor, BVSB],

          INN0 = PAR0.concat(CPAR),

          INN1 = PAR1.concat(CPAR),

          MATX = [1,0,0,1, 0,0];

    // Checkpoint.

    // ---

    if( !(doc=app.properties.activeDocument) )

        { alert("No document!"); return; }

    if( !(t=doc.textPreferences).properties.smartTextReflow )

        { alert("SmartTextReflow must be turned on!"); return; }

    if( !(t=doc.pages[0].appliedMaster) )

    {

        if( !confirm("No applied master on first page. Fix this?") ) return;

        t = doc.pages[0].appliedMaster = doc.masterSpreads[0];

    }

    if( !t.primaryTextFrame )

        { alert("No primary frame on spread "+t.name+"."); return; }

    // [ADD180621] Prepare text reflow.

    // ---

    doc.pages.itemByRange(1,-1).remove();

    t.properties = {

        addPages:                 +AddPageOptions.END_OF_STORY,

        deleteEmptyPages:          true,

        limitToMasterTextFrames:   true,

        preserveFacingPageSpreads: true,

    };

    // Get anchored items from all stories, and the respective parent char.

    // ---

    t = doc.stories.everyItem().texts.everyItem().pageItems;

    if( !t.length ){ alert("No anchored item."); return; }

    items = (t=t.everyItem()).getElements(); // array of anchored items

    chars = t.parent;                        // array of anchor characters

    // Safe scaling options are definitely needed.

    // ---

    t = +WhenScalingOptions.ADJUST_SCALING_PERCENTAGE;

    wso = +app.transformPreferences.whenScaling;

    wso==t ? (wso=0) : (app.transformPreferences.whenScaling=t);

    // [180618] Patch. Looping here from top to bottom (in

    // each story stream) we try to restore missing bounding boxes

    // due to 'formal heights' being higher than the parent frame.

    // A flag is then set in q[_id] to save those special cases.

    // ---

    for( n=items.length, z=-1 ; ++z < n ; )

    {

        // `o` is a PageItem which typically contains

        // a Graphic which typically controls a Link.

        // ---

        o = items;

        if( o.properties.visibleBounds ) continue;

       

        // `o` has no parent text frame because it's too high!

        // Let's temporarily apply a hard downscaling to it.

        // ---

        if( !(x=o.properties.horizontalScale) ) continue;

        if( !(y=o.properties.verticalScale) ) continue;

        o.horizontalScale = x/DOWN; // 1%

        o.verticalScale = y/DOWN;   // 1%

        q['_'+o.id] = 1; // flag

    }

    // [180619] Force recomposition now.

    // ---

    doc.recompose();

    // Scan each anchor character and its respective parent frame (if any!)

    // [REM] Original reason for looping upwards: "Get as many parent frames

    // as possible while rescaling." Sounds pointless now, but keeping the

    // logic won't hurt.

    // ---

    for( z=0 ; (c=chars.pop()) && (o=items.pop()) ; )

    {

        // c in overset text -> no parent available.

        // ---

        if( !(t=(c.parentTextFrames||0)[0]) ) continue;

        // Filtering conditions on `o` (you may add your own.)

        // Here we check that the anchor is of inline/aboveLine kind.

        // ---

        aos = o.properties.anchoredObjectSettings||0;

        if( (!aos) || ANCH==+aos.anchoredPosition ) continue;

       

        // [FIX180621] Force inline.

        // ---

        aos.anchoredPosition = INLN;

        // Visible width and height of the text frame (if not in cache yet.)

        // ---

        if( !(wh=q[k=t.id]) )

        {

            wh = q = t.resolve(PAR1,CINN)[0];

            xy = t.resolve(PAR0,CINN)[0];

            wh[0] -= xy[0];

            wh[1] -= xy[1];

        }

        // Temporarily store the (w,h) of `o` (in parent space.)

        // ---

        t = o.resolve(INN1,CPAR)[0].concat(o.resolve(INN0,CPAR)[0]);

        t[0] -= t[2];

        t[1] -= t[3];

        t.length = 2;

        // The x factor is required in either case.

        // ---

        x = wh[0]/t[0];

       

        // If `o` has been previously downscaled to make it show up,

        // we need to find the *smallest fit factor*.

        // ---

        y = q['_'+o.id] ? wh[1]/t[1] : false;

       

        // If `o` hasn't been downscaled, prevent it from being upscaled.

        // ("Width shorter than the frame width -> do nothing.")

        // ---

        if( (!y) && 1 <= x+EPSILON ) continue;

        // Rescale.

        // ---

        y && y < x && (x=y);

        MATX[0] = MATX[3] = x;

        o.transform(CPAR,INN0,MATX);

        ++z;

    }

    wso && (app.transformPreferences.whenScaling=wso);

    alert( "Processed items: " + z);

};

app.doScript(fixAndDownscaleInlines, void 0, void 0, UndoModes.entireScript, "FixAndDownscaleInlines");

@+

Marc

3 replies

amanm5143Author
Inspiring
June 23, 2018

There are two Correct answers to the thread, now.

Post 22 and Post 34 are both correct answers to the query as provided by great people -

Marc Autret

vinny38

Big thank you to both of you! Stay blessed! Stay awesome!

Regards,

Aman

vinny38
Brainiac
June 21, 2018

Hi there,

I'm "branching" this thread Scale all images at once in InDesign here... No need to have 2 similar threads...

So this message is the continuation of my previous attempts to handle this question.

Please note I'm learning scripting so be indulgent ^^ This interesting question is a good exercise for me.

So my suggested scenario was:

- change all inline objects to custom positioned ones. This trick, suggest by the OP, should prevent objects from over-flowing.

- then check width and height  for each object and columns

- use a couple of conditions to scale (or not) objects vertically or horizontally in regard of OP's requirements.

- reassign INLINE positioning to all objects

Sounded pretty much straightforward, But, in the last episode, a JavaScript error was thrown.

After a lot of thinking, I couldn't reproduce it... And I couldn't open the shared file since I use CS6...

I was stuck until I read Marc's remark:

"The sample document contains aboveLine anchors (not only pure inline.)"

Then I realized aboveLine anchors were not handled in my latest attempt.

So, please find below version 7 of the script that starts by changing all aboveLine anchors to Inline anchors.

I don't know why but sometimes script does not work properly, just like if it would need a "break" between the 2 instructions "app.findObjectPreferences". For now, I just put an alert() but this is a very unsatisfactory tweak and I would appreciate javascript experts advice on this issue.

Now Aman, please try this one:

If still not working, can you please share an idml file? Thanks

//FitAnchorToColumn v7 

//by Vinny       

if (parseFloat(app.version) < 6)

    main();

else

    app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "FitAnchorToColumn");

function main() {

    if (app.documents.length > 0) {

        var

            myDoc = app.activeDocument,

            myFound;

        // Let's transform ABOVE_LINE to INLINE for all objects

        app.findObjectPreferences.anchoredPosition = AnchorPosition.ABOVE_LINE;

        app.findChangeObjectOptions.objectType = ObjectTypes.GRAPHIC_FRAMES_TYPE;

        myFound = myDoc.findObject();

       

        for (i = 0; i < myFound.length; i++) {

            myFound.anchoredObjectSettings.anchoredPosition = AnchorPosition.INLINE_POSITION;

        }

       

        //reset query

        myFound = [];

        app.findObjectPreferences = null;

        alert("let's go"); //need a pause here

        // Let's now transform INLINE to CUSTOM for all objects

        app.findObjectPreferences.anchoredPosition = AnchorPosition.INLINE_POSITION;

        app.findChangeObjectOptions.objectType = ObjectTypes.GRAPHIC_FRAMES_TYPE;

        myFound = myDoc.findObject();

        for (i = 0; i < myFound.length; i++) {

            myFound.anchoredObjectSettings.anchoredPosition = AnchorPosition.ANCHORED;

        }

        //then check and transform 

        for (i = 0; i < myFound.length; i++) {

            var

                columnWidth = myFound.parent.parentTextFrames[0].textFramePreferences.textColumnFixedWidth,

                columnHeight = myFound.parent.parentTextFrames[0].geometricBounds[2] - myFound.parent.parentTextFrames[0].geometricBounds[0],

                myObjectWidth = myFound.geometricBounds[3] - myFound.geometricBounds[1],

                myObjectHeight = myFound.geometricBounds[2] - myFound.geometricBounds[0],

                myScaleFactorH = columnWidth / myObjectWidth,

                myScaleFactorV = columnHeight / myObjectHeight,

                myScaleMatrixH = app.transformationMatrices.add({

                    horizontalScaleFactor: myScaleFactorH,

                    verticalScaleFactor: myScaleFactorH

                }),

                myScaleMatrixV = app.transformationMatrices.add({

                    horizontalScaleFactor: myScaleFactorV,

                    verticalScaleFactor: myScaleFactorV

                });

            if (myObjectWidth > columnWidth && myObjectHeight <= columnHeight) {

                myFound.transform(

                    CoordinateSpaces.INNER_COORDINATES,

                    AnchorPoint.TOP_LEFT_ANCHOR,

                    myScaleMatrixH);

            } else if (myObjectWidth < columnWidth && myObjectHeight > columnHeight) {

                myFound.transform(

                    CoordinateSpaces.INNER_COORDINATES,

                    AnchorPoint.TOP_LEFT_ANCHOR,

                    myScaleMatrixV);

            } else if (myObjectWidth / myObjectHeight > columnWidth / columnHeight) {

                myFound.transform(

                    CoordinateSpaces.INNER_COORDINATES,

                    AnchorPoint.TOP_LEFT_ANCHOR,

                    myScaleMatrixH);

            } else if (myObjectWidth / myObjectHeight < columnWidth / columnHeight) {

                myFound.transform(

                    CoordinateSpaces.INNER_COORDINATES,

                    AnchorPoint.TOP_LEFT_ANCHOR,

                    myScaleMatrixV);

            } else {

                // nothing happens;   

            }

        }

        // change back to inline  position   

        for (i = 0; i < myFound.length; i++) {

            myFound.anchoredObjectSettings.anchoredPosition = AnchorPosition.INLINE_POSITION;

            // and (delete line below if not wanted), reset Y position to 0

            myFound.anchoredObjectSettings.anchorYoffset = 0;

        }

    } else {

        alert("Open a document");

    }

}

Marc Autret
Brainiac
June 21, 2018

Hi Vinny,

Welcome to this subbranch of the original thread ;-)

I'm sure your code does a great job—in particular, it deals with text columns, which mine purely ignores.

In fact, I think the main problem (= the interesting problem) is solved in both cases. But in addition we have to address refreshing time issues. Indeed, while smart reflow is processing, layout components are created (additional text frames for receiving the flow) but we don't know exactly when this new stuff is ready to operate.

So, for example, the code

myFound.parent.parentTextFrames…

in your script might go to nowhere if myFound.parent still is in overset zone.

Reminder: myFound is an object whose parent is a Character. This specific character, at a specific time, may have no parent text frame. A character instance always have a parentStory, but it doesn't necessarily have a host text frame. So I think you should check that before further processing. This may explain the undefined or invalid object errors you have observed.

Best,

Marc

amanm5143Author
Inspiring
June 22, 2018

Hey Marc,

Thank you for sending the IDML file. I tried the script n the sample document and it worked for all the frames and processed all the 7 items. However, when I followed the same properties for the master page and Text Reflow and tried to run the script in the original document, it gave the earlier results. It processed the first two images and turn the rest of the images to dots.

I tried the script with another document and it worked like a charm. It left all the in-bound images to the original state and rescaled the out-of-bound images to the size of the frame.

vinny38 An update regarding the script. It worked perfectly on other document as well. It rescaled out-of-bound images and gave them their anchor back. However, it rescaled all the in-bound images which was taken care of by Marc.

Both, versions (yours and Marc) complement each other. I guess the scripts could be considered as a generic one as

  1. They solve the problem of overset text due to images
  2. Help in reducing the labour hours required to run ‘sort’ and ‘rescale’ tasks for images in small and large documents, alike.

These scripts cater to such a problem which is experienced by every InDesign user one time or the other.

Therefore, Thank you for all the hard work and for being such an amazing help and bringing out the best in things.

Kudos to Marc, Uwe and Vinny for being such great sports.

Regards,

Aman Mittal

Community Expert
June 15, 2018

You should let InDesign do all the work:

links = app.documents[0].links.everyItem().getElements();

for (i = 0; i < links.length; i++) {

  links.parent.parent.fit (FitOptions.CONTENT_TO_FRAME);

}

P.

amanm5143Author
Inspiring
June 16, 2018

Hello Mr. Kahrel,

Thank you for taking out time from your busy schedule and replying to the thread. I saved the script and tried to run it in InDesign, however, I regret (because your reputation in InDesign community precedes you) to tell you that it did not affect a single image. All the out of bound images remained of the same size and did not fit to the text frame size.

I know your schedule remains too busy but I would really appreciate if you could help me out regarding the request. Hope to receive a positive reply.

Regards,

Aman Mittal

New Participant
March 22, 2021

Hi Aman,

If your goal is to proportionnally re-scale inline containers with respect to the width of the text frame they belong to, here is a possible approach:

function rescaleInlines(  q,t,wso,items,chars,z,c,o,aos,k,w,x)

//----------------------------------

// This function proportionnaly re-scales every *inline* or

// *aboveLine* anchored item found in the document so that

// it fits the parent frame width.

{

    // Cache and constants.

    // ---

    q = (callee.Q||callee.Q={});

    const EPSILON = 1e-3,

          ANCH = +AnchorPosition.ANCHORED,

          // ---

          CPAR = +CoordinateSpaces.parentCoordinates,

          CINN = +CoordinateSpaces.innerCoordinates,

          BVSB = +BoundingBoxLimits.outerStrokeBounds,

          // ---

          PAR0 = [+AnchorPoint.topLeftAnchor, BVSB],

          PAR1 = [+AnchorPoint.bottomRightAnchor, BVSB],

          INN0 = PAR0.concat(CPAR),

          INN1 = PAR1.concat(CPAR),

          MATX = [1,0,0,1, 0,0];

   

    // Get anchored items from all stories, and the respective parent char.

    // ---

    if( !(t=app.properties.activeDocument) ){ alert("No document!"); return; }

    t = t.stories.everyItem().texts.everyItem().pageItems;

    if( !t.length ){ alert("No anchored item."); return; }

    items = (t=t.everyItem()).getElements(); // array of anchored items

    chars = t.parent;                        // array of anchor characters

    // Safer scaling options.

    // ---

    t = +WhenScalingOptions.ADJUST_SCALING_PERCENTAGE;

    wso = +app.transformPreferences.whenScaling;

    wso==t ? (wso=0) : (app.transformPreferences.whenScaling=t);

    // Scan each anchor character and its respective parent frame (if any!)

    // (Loop from the end to get as many parent frames as possible while rescaling.)

    // ---

    for( z=0 ; (c=chars.pop()) && (o=items.pop()) ; )

    {

        // c in overset text -> no parent available.

        // ---

        if( !(t=(c.parentTextFrames||0)[0]) ) continue;

        // Filtering conditions on `o` (you may add your own.)

        // ---

        aos = o.properties.anchoredObjectSettings||0;

        if( (!aos) || ANCH==+aos.anchoredPosition ) continue;

       

        // If needed, do fitting jobs now.

        o.fit(FitOptions.FRAME_TO_CONTENT);

       

        // Use box coordinates to determine the scaling factor.

        // ---

        w = q[k=t.id]||(q=t.resolve(PAR1,CINN)[0][0]-t.resolve(PAR0,CINN)[0][0]);

        x = w/(o.resolve(INN1,CPAR)[0][0]-o.resolve(INN0,CPAR)[0][0]);

        if( Math.abs(x-1) < EPSILON ) continue; // matches already.

       

        // Rescale.

        // ---

        MATX[0] = MATX[3] = x;

        o.transform(CPAR,INN0,MATX);

        ++z;

    }

   

    wso && (app.transformPreferences.whenScaling=wso);

    alert( "Processed items: " + z);

};

app.doScript(rescaleInlines, void 0, void 0, UndoModes.entireScript, "RescaleInlines");

@+

Marc


Hi Marc, 

I just wanted to give you a big thank you as I needed a script to resize inline graphics proportionally as we have changed trim size on our products. The one above worked perfectly and in seconds. I went through about 20 scripts before I found this one and it did the trick, so thank you!