Skip to main content
dublove
Legend
July 27, 2024
Answered

Can you help me modify this script , Change the file name of picture directly to its note.

  • July 27, 2024
  • 1 reply
  • 1369 views


But I just want to modify the content after @, @ and its previous numbers remain unchanged.
For example, this is the end:
P040-001@Great Village Mango Base
Thank you very much ~

 

/*

Links Rename Selected
Copyright 2023 William Campbell
All Rights Reserved
https://www.marspremedia.com/contact

Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

*/

(function () {

    var title = "Rename Selected Links 链接改名";

    if (!/indesign/i.test(app.name)) {
        alert("适用ID", title, false);
        return;
    }

    // Script variables.
    var doc;
    var extension;
    var file;
    var fileNew;
    var i;
    var link;
    var baseName;
    var nameNew;
    var nameOld;
    var selection;

    // SETUP

    if (!app.documents.length) {
        alert("打开文件", title, false);
        return;
    }
    doc = app.activeDocument;

    // EXECUTE

    selection = doc.selection[0];
    if (selection) {
        try {
            if (selection instanceof Rectangle) {
                link = selection.allGraphics[0].itemLink;
            } else {
                link = selection.itemLink;
            }
        } catch (_) {
            // Ignore.
        }
        if (link) {
            nameOld = link.name;
            // Split filename into name and extension.
            baseName = link.name.replace(/\.[^\.]*$/, "");
            extension = String(String(link.name.match(/\..*$/) || "").match(/[^\.]*$/) || "");
            nameNew = prompt("根据需要修改名称\n(扩展保持不变)", baseName, title);
            if (nameNew && nameNew != baseName) {
                // Add back extension.
                nameNew += "." + extension;
                // Test if new name exists.
                fileNew = new File(new File(link.filePath).path + "/" + nameNew);
                if (fileNew.exists) {
                    alert(nameNew + "已经存在", title, true);
                    return;
                }
                // Rename and relink.
                file = new File(link.filePath);
                file.rename(nameNew);
                // Loop through all graphics and relink.
                // Graphic could be placed more than once.
                for (i = 0; i < doc.links.length; i++) {
                    if (doc.links[i].name == nameOld) {
                        doc.links[i].relink(file);
                        doc.links[i].update();
                    }
                }
            }
            return;
        }
    }
    alert("选择放置的图形或其框架", title, false);

})();

 

Correct answer m1b

Hi @dublove I have written a script that I hope does what you ask. Please give it a try and let me know how it goes. I hope you can follow along in the script to see what I am doing: I locate the caption based on it's proximity to the bottom left of the graphic frame, then rename the link.

- Mark

 

 

/**
 * @file Rename Link With Caption.js
 *
 * Usage:
 *   1. Select one or more graphic frames
 *      (non-graphics will be ignored).
 *   2. Run script
 *
 * If the linked file's name contains "@" symbol it
 * Will rename the linked file, replacing text after
 * the "@" with the caption of the image, if found.
 *
 * @author m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/can-you-help-me-modify-this-script-change-the-file-name-of-picture-directly-to-its-note/m-p/14763414
 */
function main() {

    if (0 === app.documents.length)
        return alert('Please open a document and try again.');

    var doc = app.activeDocument,
        items = doc.selection,
        stats = { total: 0, counter: 0 };

    for (var i = items.length - 1, item; i >= 0; i--)
        items[i] = renameLinkWithCaption(items[i], items, stats) || items[i];

    // alert('Renamed ' + stats.counter + ' out of ' + stats.total + ' graphics.');

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Rename Linked File By Caption');

/**
 * Renames the linked graphic file
 * incorporating the graphic's caption.
 * @author m1b
 * @version 2024-07-29
 * @param {Graphic} item - the linked graphic.
 * @param {Array<PageItem>} [items] - the items to search for caption frame (default: all items on page).
 * @param {Object} stats - an object for collecting statistics.
 * @returns {Graphic} - the updated graphic.
 */
function renameLinkWithCaption(item, items, stats) {

    stats = stats || { total: 0, counter: 0 };

    if (
        item
        && !item.hasOwnProperty('itemLink')
        && item.allGraphics
        && item.allGraphics.length
    )
        item = item.allGraphics[0];

    if (
        !item
        || !item.hasOwnProperty('itemLink')
    )
        return;

    stats.total++;

    if (LinkStatus.LINK_MISSING === item.itemLink.status)
        return alert('The graphic is missing. Please re-link and try again.');

    // get the caption for this linked graphic
    var captionFrame = getCaptionTextFrame(item, items);

    if (!captionFrame)
        return alert('Could not locate caption for this link.');

    // clean up the caption suitable for filenaming
    var link = item.itemLink,
        forbiddenChars = /[:\/\\]/g,
        afterTheAtSymbol = /\@(.*)(\.[^\.]+)$/,
        newName = captionFrame.contents
            // sanitize filename
            .replace(forbiddenChars, '')
            // remove file extension, if any
            .replace(/\.[^\.]+$/, '');

    if (!afterTheAtSymbol.test(link.name))
        return alert('Linked file name did not match the expected format (no @ symbol).');

    // incorporate into the existing name
    newName = link.name.replace(afterTheAtSymbol, '@' + newName + '$2');

    if (newName === link.name)
        return;

    // rename the link, get new reference to link and item
    link = renameLink(link, newName);

    if (
        !link
        || !link.isValid
    )
        return;

    item = link.parent;

    stats.counter++;

    return item;

};

/**
 * Renames the a link's *file* and
 * re-links to the renamed file.
 * @author m1b
 * @version 2024-07-28
 * @param {Link} link - the link to rename.
 * @param {String} newName - the name to apply.
 * @return {Link?} - the updated link.
 */
function renameLink(link, newName) {

    var file = File(link.filePath);

    if (!file.exists)
        return;

    var newPath = link.filePath.replace(link.name, newName);

    file.rename(newName);

    link.relink(File(newPath));

    if (link.isValid)
        return link;

};

/**
 * Returns a caption frame, given a page item.
 * @author m1b
 * @version 2024-07-29
 * @param {Page Item} graphic - a linked graphic.
 * @param {Array<PageItem>} [items] - the items to search for caption frame (default: all items on page).
 * @param {Anchor} [graphicAnchor] - an Indesign Anchor (default: AnchorPoint.BOTTOM_CENTER_ANCHOR).
 * @param {Anchor} [captionAnchor] - an Indesign Anchor (default: AnchorPoint.TOP_CENTER_ANCHOR).
 * @returns {TextFrame?}
 */
function getCaptionTextFrame(graphic, items, graphicAnchor, captionAnchor) {

    items = items.slice() || graphic.parent.parentPage.allPageItems;
    graphicAnchor = graphicAnchor || AnchorPoint.BOTTOM_CENTER_ANCHOR;
    captionAnchor = captionAnchor || AnchorPoint.TOP_CENTER_ANCHOR;

    var point = getPointFromBounds(graphic.parent.geometricBounds, graphicAnchor),
        captionFrame;

    // sort by distance from bottom left of graphic frame
    items.sort(sortByDistanceFrom(point, captionAnchor));

    // bypass items with no contents
    do {

        captionFrame = items.shift();

        if (!captionFrame)
            return;

    } while (
        'TextFrame' !== captionFrame.constructor.name
        || !captionFrame.contents
        || captionFrame === graphic.parent
    );

    return captionFrame;

};

/**
 * Returns a sort function which sorts page items by the
 * distance from `point` to an item's anchor point.
 * @param {point} point - [x,y].
 * @param {Anchor} [anchor] - an Indesign Anchor (default: top-left).
 * @returns {Number}
 */
function sortByDistanceFrom(point, anchor) {

    anchor = anchor || AnchorPoint.TOP_LEFT_ANCHOR;

    return function sortByDistanceFromPoint(a, b) {
        var distanceA = mDist(getPointFromBounds(a.geometricBounds, anchor), point),
            distanceB = mDist(getPointFromBounds(b.geometricBounds, anchor), point);
        return distanceA - distanceB;
    };

};

/**
 * Returns the "Manhattan" distance between two points.
 * @param {point} p0 - a point array [x,y].
 * @param {point} p1 - a point array [x,y].
 * @returns {Number}
 */
function mDist(p0, p1) {
    var dx = Math.abs(p1[0] - p0[0]),
        dy = Math.abs(p1[1] - p0[1]);
    return dx + dy;
};

/**
 * Returns a point, given `bounds` and an `anchor`.
 * @author m1b
 * @version 2024-07-28
 * @param {Array<Number>} bounds - bounds [T, L, B, R].
 * @param {Anchor} anchor - an Indesign Anchor.
 * @returns {point} - [x, y].
 */
function getPointFromBounds(bounds, anchor) {

    switch (anchor) {

        case AnchorPoint.TOP_LEFT_ANCHOR:
            return [bounds[1], bounds[0]];

        case AnchorPoint.TOP_CENTER_ANCHOR:
            return [bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[0]];

        case AnchorPoint.TOP_RIGHT_ANCHOR:
            return [bounds[3], bounds[0]];

        case AnchorPoint.CENTER_ANCHOR:
            return [bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[0] + (bounds[2] - bounds[0]) / 2];

        case AnchorPoint.LEFT_CENTER_ANCHOR:
            return [bounds[1], bounds[0] + (bounds[2] - bounds[0]) / 2];

        case AnchorPoint.RIGHT_CENTER_ANCHOR:
            return [bounds[3], bounds[0] + (bounds[2] - bounds[0]) / 2];

        case AnchorPoint.BOTTOM_CENTER_ANCHOR:
            return [bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[2]];

        case AnchorPoint.BOTTOM_LEFT_ANCHOR:
            return [bounds[1], bounds[2]];

        case AnchorPoint.BOTTOM_RIGHT_ANCHOR:
            return [bounds[3], bounds[2]];

        default:
            break;
    }

};

 

 

Edit 2024-07-28: changed structure slightly so that multiple graphics could be selected and renamed at once, and added feedback alert.

 

Edit 2024-07-28: added `getPointFromBounds` function to make it easier for OP to set the measurement points as desired. Edit this line:

 

bottomCenter = getPointFromBounds(bounds, AnchorPoint.BOTTOM_CENTER_ANCHOR),

 

and/or this line:

 

items.sort(sortByDistanceFrom(bottomCenter, AnchorPoint.TOP_CENTER_ANCHOR));

 

 

Edit 2024-07-29: Based on OP feedback, I turned the error alerts back on, I turned off the final stats alert, and now, if the caption contains a file extension, it will remove it before renaming link. Also in this version you must select the caption(s) along with the graphic(s)—script will no longer search for captions outside of the selected page items. To revert this behaviour,  change this line:

 

items[i] = renameLinkWithCaption(items[i], items, stats) || items[i];

 

to:

 

items[i] = renameLinkWithCaption(items[i], undefined, stats) || items[i];

 

 

Edit 2024-07-30: fixed bug where `items` array was being mutated by `getCaptionTextFrame`.

1 reply

m1b
Community Expert
Community Expert
July 27, 2024

Hi @dublove, is that a Live Caption, or normal text in the frame under the image?

- Mark

dublove
dubloveAuthor
Legend
July 27, 2024

Normal text in the frame under the image. It turned out to be generated by static caption, But later modified Several times, it has nothing to do with the original Caption.

m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
July 28, 2024

Hi @dublove I have written a script that I hope does what you ask. Please give it a try and let me know how it goes. I hope you can follow along in the script to see what I am doing: I locate the caption based on it's proximity to the bottom left of the graphic frame, then rename the link.

- Mark

 

 

/**
 * @file Rename Link With Caption.js
 *
 * Usage:
 *   1. Select one or more graphic frames
 *      (non-graphics will be ignored).
 *   2. Run script
 *
 * If the linked file's name contains "@" symbol it
 * Will rename the linked file, replacing text after
 * the "@" with the caption of the image, if found.
 *
 * @author m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/can-you-help-me-modify-this-script-change-the-file-name-of-picture-directly-to-its-note/m-p/14763414
 */
function main() {

    if (0 === app.documents.length)
        return alert('Please open a document and try again.');

    var doc = app.activeDocument,
        items = doc.selection,
        stats = { total: 0, counter: 0 };

    for (var i = items.length - 1, item; i >= 0; i--)
        items[i] = renameLinkWithCaption(items[i], items, stats) || items[i];

    // alert('Renamed ' + stats.counter + ' out of ' + stats.total + ' graphics.');

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Rename Linked File By Caption');

/**
 * Renames the linked graphic file
 * incorporating the graphic's caption.
 * @author m1b
 * @version 2024-07-29
 * @param {Graphic} item - the linked graphic.
 * @param {Array<PageItem>} [items] - the items to search for caption frame (default: all items on page).
 * @param {Object} stats - an object for collecting statistics.
 * @returns {Graphic} - the updated graphic.
 */
function renameLinkWithCaption(item, items, stats) {

    stats = stats || { total: 0, counter: 0 };

    if (
        item
        && !item.hasOwnProperty('itemLink')
        && item.allGraphics
        && item.allGraphics.length
    )
        item = item.allGraphics[0];

    if (
        !item
        || !item.hasOwnProperty('itemLink')
    )
        return;

    stats.total++;

    if (LinkStatus.LINK_MISSING === item.itemLink.status)
        return alert('The graphic is missing. Please re-link and try again.');

    // get the caption for this linked graphic
    var captionFrame = getCaptionTextFrame(item, items);

    if (!captionFrame)
        return alert('Could not locate caption for this link.');

    // clean up the caption suitable for filenaming
    var link = item.itemLink,
        forbiddenChars = /[:\/\\]/g,
        afterTheAtSymbol = /\@(.*)(\.[^\.]+)$/,
        newName = captionFrame.contents
            // sanitize filename
            .replace(forbiddenChars, '')
            // remove file extension, if any
            .replace(/\.[^\.]+$/, '');

    if (!afterTheAtSymbol.test(link.name))
        return alert('Linked file name did not match the expected format (no @ symbol).');

    // incorporate into the existing name
    newName = link.name.replace(afterTheAtSymbol, '@' + newName + '$2');

    if (newName === link.name)
        return;

    // rename the link, get new reference to link and item
    link = renameLink(link, newName);

    if (
        !link
        || !link.isValid
    )
        return;

    item = link.parent;

    stats.counter++;

    return item;

};

/**
 * Renames the a link's *file* and
 * re-links to the renamed file.
 * @author m1b
 * @version 2024-07-28
 * @param {Link} link - the link to rename.
 * @param {String} newName - the name to apply.
 * @return {Link?} - the updated link.
 */
function renameLink(link, newName) {

    var file = File(link.filePath);

    if (!file.exists)
        return;

    var newPath = link.filePath.replace(link.name, newName);

    file.rename(newName);

    link.relink(File(newPath));

    if (link.isValid)
        return link;

};

/**
 * Returns a caption frame, given a page item.
 * @author m1b
 * @version 2024-07-29
 * @param {Page Item} graphic - a linked graphic.
 * @param {Array<PageItem>} [items] - the items to search for caption frame (default: all items on page).
 * @param {Anchor} [graphicAnchor] - an Indesign Anchor (default: AnchorPoint.BOTTOM_CENTER_ANCHOR).
 * @param {Anchor} [captionAnchor] - an Indesign Anchor (default: AnchorPoint.TOP_CENTER_ANCHOR).
 * @returns {TextFrame?}
 */
function getCaptionTextFrame(graphic, items, graphicAnchor, captionAnchor) {

    items = items.slice() || graphic.parent.parentPage.allPageItems;
    graphicAnchor = graphicAnchor || AnchorPoint.BOTTOM_CENTER_ANCHOR;
    captionAnchor = captionAnchor || AnchorPoint.TOP_CENTER_ANCHOR;

    var point = getPointFromBounds(graphic.parent.geometricBounds, graphicAnchor),
        captionFrame;

    // sort by distance from bottom left of graphic frame
    items.sort(sortByDistanceFrom(point, captionAnchor));

    // bypass items with no contents
    do {

        captionFrame = items.shift();

        if (!captionFrame)
            return;

    } while (
        'TextFrame' !== captionFrame.constructor.name
        || !captionFrame.contents
        || captionFrame === graphic.parent
    );

    return captionFrame;

};

/**
 * Returns a sort function which sorts page items by the
 * distance from `point` to an item's anchor point.
 * @param {point} point - [x,y].
 * @param {Anchor} [anchor] - an Indesign Anchor (default: top-left).
 * @returns {Number}
 */
function sortByDistanceFrom(point, anchor) {

    anchor = anchor || AnchorPoint.TOP_LEFT_ANCHOR;

    return function sortByDistanceFromPoint(a, b) {
        var distanceA = mDist(getPointFromBounds(a.geometricBounds, anchor), point),
            distanceB = mDist(getPointFromBounds(b.geometricBounds, anchor), point);
        return distanceA - distanceB;
    };

};

/**
 * Returns the "Manhattan" distance between two points.
 * @param {point} p0 - a point array [x,y].
 * @param {point} p1 - a point array [x,y].
 * @returns {Number}
 */
function mDist(p0, p1) {
    var dx = Math.abs(p1[0] - p0[0]),
        dy = Math.abs(p1[1] - p0[1]);
    return dx + dy;
};

/**
 * Returns a point, given `bounds` and an `anchor`.
 * @author m1b
 * @version 2024-07-28
 * @param {Array<Number>} bounds - bounds [T, L, B, R].
 * @param {Anchor} anchor - an Indesign Anchor.
 * @returns {point} - [x, y].
 */
function getPointFromBounds(bounds, anchor) {

    switch (anchor) {

        case AnchorPoint.TOP_LEFT_ANCHOR:
            return [bounds[1], bounds[0]];

        case AnchorPoint.TOP_CENTER_ANCHOR:
            return [bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[0]];

        case AnchorPoint.TOP_RIGHT_ANCHOR:
            return [bounds[3], bounds[0]];

        case AnchorPoint.CENTER_ANCHOR:
            return [bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[0] + (bounds[2] - bounds[0]) / 2];

        case AnchorPoint.LEFT_CENTER_ANCHOR:
            return [bounds[1], bounds[0] + (bounds[2] - bounds[0]) / 2];

        case AnchorPoint.RIGHT_CENTER_ANCHOR:
            return [bounds[3], bounds[0] + (bounds[2] - bounds[0]) / 2];

        case AnchorPoint.BOTTOM_CENTER_ANCHOR:
            return [bounds[1] + (bounds[3] - bounds[1]) / 2, bounds[2]];

        case AnchorPoint.BOTTOM_LEFT_ANCHOR:
            return [bounds[1], bounds[2]];

        case AnchorPoint.BOTTOM_RIGHT_ANCHOR:
            return [bounds[3], bounds[2]];

        default:
            break;
    }

};

 

 

Edit 2024-07-28: changed structure slightly so that multiple graphics could be selected and renamed at once, and added feedback alert.

 

Edit 2024-07-28: added `getPointFromBounds` function to make it easier for OP to set the measurement points as desired. Edit this line:

 

bottomCenter = getPointFromBounds(bounds, AnchorPoint.BOTTOM_CENTER_ANCHOR),

 

and/or this line:

 

items.sort(sortByDistanceFrom(bottomCenter, AnchorPoint.TOP_CENTER_ANCHOR));

 

 

Edit 2024-07-29: Based on OP feedback, I turned the error alerts back on, I turned off the final stats alert, and now, if the caption contains a file extension, it will remove it before renaming link. Also in this version you must select the caption(s) along with the graphic(s)—script will no longer search for captions outside of the selected page items. To revert this behaviour,  change this line:

 

items[i] = renameLinkWithCaption(items[i], items, stats) || items[i];

 

to:

 

items[i] = renameLinkWithCaption(items[i], undefined, stats) || items[i];

 

 

Edit 2024-07-30: fixed bug where `items` array was being mutated by `getCaptionTextFrame`.