Copy link to clipboard
Copied
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.
/*
_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;
}
}
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
...
Copy link to clipboard
Copied
For a start, let's ask Michel.
@FRIdNGE ?
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
No Road Ahead ......
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
I prefer scripts, they are more free and flexible!
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
The plugin doesn't work well.
Scripts are more flexible.
Copy link to clipboard
Copied
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...
Copy link to clipboard
Copied
There could have been a path ahead and you kept standing in the middle of it.
Pity about my good posting.
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
Just kidding.
Still hoping for a big sale of your plugin.
Copy link to clipboard
Copied
@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 )
Copy link to clipboard
Copied
Simply differentiate between the text box and the image. Their position may not be important.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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?
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
As I said, the script is working correctly on my system here. Can you post an .indd file for me to test on?
Copy link to clipboard
Copied
Copy link to clipboard
Copied
Copy link to clipboard
Copied
captionFrame.geometricBounds = [top, left, bottom, right];
captionFrame.geometricBounds = [top, left, bottom, right+17];