Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
1

How to modify this script to select multiple images and a text box?

Guide ,
Apr 19, 2025 Apr 19, 2025

Thanks to FRIdNGE, the great original script provider! 

There's also Robert at ID-Tasker who has been quite helpful.
It is now suitable for the case of one caption for one picture, allowing the caption to be quickly pasted close to the picture.

The original post seems to have sunk.
I'm trying to modify it to a situation where multiple images share a caption, but I don't know how to traverse out the textframe and image with a loop.

066.png

/*
    _FRIdNGE-0766_ImageCaptionAlignment.jsx
    Script written by FRIdNGE, Michel Allio [02/11/2024]
*/
//https://community.adobe.com/t5/indesign-discussions/script-to-match-object-sizes-and-align-captions-in-indesign/m-p/14941759
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.FAST_ENTIRE_SCRIPT, 'Image And Caption Alignment');

function main() {

    var myDoc = app.activeDocument;
    var myRulerOrigin = myDoc.viewPreferences.rulerOrigin;

    if ( app.selection.length != 2 ) {

        alert( "Select 2 items!")
        exit();
        
    } else {

        if ( app.selection[0] instanceof Rectangle && app.selection[1] instanceof TextFrame ) {
            var myGraphicFrame = app.selection[0];
            var myTextFrame = app.selection[1];        
        } else if ( app.selection[1] instanceof Rectangle && app.selection[0] instanceof TextFrame ) {
            var myGraphicFrame = app.selection[1];
            var myTextFrame = app.selection[0];        
        } else {
            alert( "Bad Selection!")
            exit();
        }

        myDoc.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN;

        myTextFrame.geometricBounds = [ myGraphicFrame.geometricBounds[2], myGraphicFrame.geometricBounds[1], myGraphicFrame.geometricBounds[2] + myTextFrame.geometricBounds[2] - myTextFrame.geometricBounds[0], myGraphicFrame.geometricBounds[3] ];
        
        myDoc.viewPreferences.rulerOrigin = myRulerOrigin;

    }

}

 

TOPICS
Bug , Feature request , How to , Scripting
724
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Apr 22, 2025 Apr 22, 2025

Hi @dublove, here is one approach...

- Mark

 

/**
 * @file Align Caption Frame To Graphic Frames.js
 *
 * Usage:
 *   1. Select the caption, a text frame
 *   2. Also select one or more graphic frames
 *   3. Run script
 *
 * Script will align the left and right edges of the caption frame
 * to the left and right extremes of the graphic frame(s), and
 * also align the caption frame above or below the graphic frame(s).
 *
 * @author m1b
 * @version 2025-04-23
 * @discussion https://community.adob
...
Translate
Community Expert ,
Apr 19, 2025 Apr 19, 2025

For a start, let's ask Michel.

@FRIdNGE ?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 19, 2025 Apr 19, 2025

Looking forward to FRIdNGE reproducing.
But sadly, he seems to have been too busy to be interested in it. Because I asked twice a long time ago under the original post.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025

@dublove 

 

It would be much easier - if you make a requirement - that "images" are selected FIRST - then TextFrame LAST - or vice versa.

 

Then, script can just check if first / last is a TextFrame and treat the rest as "images".

 

And also, that "images" are selected from left to right.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 20, 2025 Apr 20, 2025

In case of multiple images, the images must have been arranged side by side from left to right.
You need to detect the first picture and the last picture.
Sometimes the text box is not always at the bottom, sometimes it may be above the picture.

That is, the text box is not necessarily at the end.

 

Single image and multiple images should share 1 script, making 2 scripts would be too inconvenient.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025

@dublove

 

I'm not talking how they're placed on the page - but how they're selected.

 

Order of selection can be detected in the script. 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 20, 2025 Apr 20, 2025

No Road Ahead ......

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025

@dublove

 

Just realised, that I've already made something like that - and is available in the free version of my tool: 

 

 

Of course, it would require a few modifications - but the mechanism, overall, would be pretty much the same. 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 20, 2025 Apr 20, 2025

I prefer scripts, they are more free and flexible!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025
quote

I prefer scripts, they are more free and flexible!


By @dublove

 

But this specific functionality is free - and my tool is way more flexible... 

 

Right now, you're waiting for someone to create / convert some script... with my tool - you don't have to wait for anyone... 

 

Just recreate your MANUAL steps - using my tool. 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 20, 2025 Apr 20, 2025

The plugin doesn't work well.
Scripts are more flexible.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025
quote

The plugin doesn't work well.
Scripts are more flexible.


By @dublove

 

My tool isn't a plugin - nor plug-in - it's a tool that connects to indesign externally - and simulates/executes manual operations. 

 

I would even say that my tool is way better than plugins / plug-ins and scripts - it can survive crash of InDesign... 

 

Or, to put it another way - it's bunch of small scripting commands - with a "fancy" UI. 

 

Each "rule" in the Task - command - is a small operation - like cut or copy - you can do it manually by pressing Ctrl+X or Ctrl+C in the InDesign's UI - or through scripting - as app.cut or app.copy. 

 

When you want to create a Rectangle - you can use a specific "rule" with parameters - or you can select specific tool in InDesign and draw a Rectangle - or execute app.activeDocument.rectangles.add() - with either size defined as params or later by using geometricBounds. 

 

Pretty much EVERYTHING you can do / click in the InDesign's UI -> you can do through scripting -> in my tool.

 

I could even add an option in my tool to generate working scripts - either as JavaScript or VisualBasic. 

 

You can't make it simpler...

 

And the basic functionality - INCLUDING complete browsable structure of the Document - is available for free... 

 

I stopped counting how many times a quick load of doc's structure in my tool instantly revealed the problem. 

 

The only thing that you'll pay for - is ability to save on extra clicks - to save a lot of time. 

 

The paid BatchMode - is just automated way of "select next object on the list and hit Play button to execute Task" - instead of doing the above manually. 

 

So even if you don't want to pay me - you still have access to the core functionality - free of charge - just more clicking.

 

And on top of that - it can do the same - at the same time - with Photoshop, Illustrator, WORD, Excel, PowerPoint and many other applications...

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 20, 2025 Apr 20, 2025

There could have been a path ahead and you kept standing in the middle of it.

Pity about my good posting.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025
quote

There could have been a path ahead and you kept standing in the middle of it.


By @dublove

 

I gave you an idea how to make the code more efficient - that objects should be selected in a specific way to make script simpler - instead of code being complicated - and I've offered you even quicker path to the goal - using free version of my tool - not sure how am I standing in your way? 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 21, 2025 Apr 21, 2025

Just kidding.
Still hoping for a big sale of your plugin.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 20, 2025 Apr 20, 2025

@dublove said: "…Sometimes the text box is not always at the bottom, sometimes it may be above the picture.

That is, the text box is not necessarily at the end."

 

What is the rule for the different alignments?

Are the text frames sometimes of different height and are aligned sometimes on the top ( then the text frame moves to the top ) and sometimes the text frames are aligned on the bottom ( then the text frame moves to the bottom ) ?

 

Regards,
Uwe Laubender
( Adobe Community Expert )

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 20, 2025 Apr 20, 2025

Simply differentiate between the text box and the image. Their position may not be important.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 22, 2025 Apr 22, 2025

Hi @dublove, here is one approach...

- Mark

 

/**
 * @file Align Caption Frame To Graphic Frames.js
 *
 * Usage:
 *   1. Select the caption, a text frame
 *   2. Also select one or more graphic frames
 *   3. Run script
 *
 * Script will align the left and right edges of the caption frame
 * to the left and right extremes of the graphic frame(s), and
 * also align the caption frame above or below the graphic frame(s).
 *
 * @author m1b
 * @version 2025-04-23
 * @discussion https://community.adobe.com/t5/indesign-discussions/how-to-modify-this-script-to-select-multiple-images-and-a-text-box/m-p/15282394
 */
function main() {

    var settings = {

        // distance between the graphic frame(s) and caption frame, in points
        gap: 0,

        // whether to adjust the final positioning to account for text frame insets [T, L, B, R].
        adjustForTextFrameInsets: [false, true, false, true],

    };

    var doc = app.activeDocument,
        items = doc.selection,
        graphicFrames = getThingsWithFilter(items, function (item) { return item.hasOwnProperty('graphics') && item.graphics.length > 0 }, false),
        captionFrame = getThingsWithFilter(items, function (item) { return item.hasOwnProperty('texts') && item.texts.length > 0 }, true);

    if (0 === graphicFrames.length)
        return alert('Please include one or more graphic frames in your selection.');

    if (!captionFrame)
        return alert('Please include one caption text frame in your selection.')

    app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;

    // insets to adjust for text frame insets
    var insets = [
        settings.adjustForTextFrameInsets[0] ? captionFrame.textFramePreferences.insetSpacing[0] : 0,
        settings.adjustForTextFrameInsets[1] ? captionFrame.textFramePreferences.insetSpacing[1] : 0,
        settings.adjustForTextFrameInsets[2] ? captionFrame.textFramePreferences.insetSpacing[2] : 0,
        settings.adjustForTextFrameInsets[3] ? captionFrame.textFramePreferences.insetSpacing[3] : 0,
    ];

    var minimumHeight = captionFrame.texts[0].characters[0].pointSize
        + (captionFrame.textFramePreferences.insetSpacing[2] + captionFrame.textFramePreferences.insetSpacing[0]);

    var left = Infinity,
        right = -Infinity,
        top = Infinity,
        bottom = -Infinity,
        anchor;

    for (var i = 0; i < graphicFrames.length; i++) {
        left = Math.min(graphicFrames[i].geometricBounds[1], left);
        right = Math.max(graphicFrames[i].geometricBounds[3], right);
        top = Math.min(graphicFrames[i].geometricBounds[0], top);
        bottom = Math.max(graphicFrames[i].geometricBounds[2], bottom);
    }

    if (top < captionFrame.geometricBounds[0]) {
        // align caption below graphic frames
        top = bottom + settings.gap;
        bottom = top + minimumHeight;
        anchor = AnchorPoint.TOP_LEFT_ANCHOR;
    }

    else {
        // align caption above graphic frames
        bottom = top - settings.gap;
        top = bottom - minimumHeight;
        anchor = AnchorPoint.BOTTOM_LEFT_ANCHOR;
    }

    // new bounds, adjusting for insets
    captionFrame.geometricBounds = [
        top - insets[0],
        left - insets[1],
        bottom + insets[2],
        right + insets[3],
    ];

    // now expand to fit the caption text
    while (captionFrame.overflows)
        captionFrame.resize(CoordinateSpaces.PARENT_COORDINATES, anchor, ResizeMethods.ADDING_CURRENT_DIMENSIONS_TO, [0, 2]);

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Align Caption To Graphic Frames');

/**
 * Returns any things which pass the `filter` function.
 * @author m1b
 * @version 2025-04-23
 * @param {Array<*>} things - the things to search.
 * @param {Function} filter - a function that, given a thing, returns true when it matches.
 * @param {Boolean} [returnFirstThing] - whether to return the first thing only (default: false).
 * @returns {Array<*>}
 */
function getThingsWithFilter(things, filter, returnFirstThing) {

    var found = [];

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

        if (
            'Group' === things[i].constructor.name
            && things[i].pageItems.length > 0
        ) {
            var moreThings = getThingsWithFilter(things[i].pageItems.everyItem().getElements(), filter, returnFirstThing);

            if (
                returnFirstThing
                && undefined != moreThings
                && 'Array' !== moreThings.constructor.name
            )
                return moreThings;

            if (moreThings.length > 0)
                found = found.concat(moreThings);

            continue;
        }

        if (!filter(things[i]))
            continue;

        if (returnFirstThing)
            return things[i];

        found.push(things[i]);

    }

    if (
        returnFirstThing
        && 0 === found.length
    )
        return;

    return found;

};

Edit 2025-04-22: added support for grouped items.

Edit 2025-04-23: fixed bug relating to minimum height of caption frame, added support for adjusting for text frame insets.

Edit 2025-04-23: added finer control over each text frame inset and fixed another bug relating to minimum height.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 22, 2025 Apr 22, 2025

Hi  m1b.

Thank you.
You're so strong and always invincible going forward.

 

It seems like the text box position can't be higher than the top of the image. This doesn't matter, it can be overcome.

 

The header note annotations aren't right
**/
There seems to be something wrong with the algorithm. The right side of the text box isn't aligned and the top isn't close.

Also, is it possible to recognize the three images if they are already grouped?

01.png02.png

03.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 22, 2025 Apr 22, 2025

Hi @dublove I have updated the script to handle grouped items. However the other problems you show work fine on my computer. Can you post an .indd (not .idml) of those exact files and I will test.

- Mark

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 22, 2025 Apr 22, 2025

Groups are now supported.
Also aligns the bottom edge of the image now.

But the text box is still not aligned to the far right of the image.

 

Also, add the URL of this post to the header,please.

Thank you very much.

05.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 22, 2025 Apr 22, 2025

As I said, the script is working correctly on my system here. Can you post an .indd file for me to test on?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 22, 2025 Apr 22, 2025

I use the InDD version.
Difference of 6mm.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 22, 2025 Apr 22, 2025
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Apr 22, 2025 Apr 22, 2025
    captionFrame.geometricBounds = [top, left, bottom, right];
Change to
    captionFrame.geometricBounds = [top, left, bottom, right+17];
It's just OK.
Why?
for some inexplicable reason.
 
 
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines