Label Graphic Links

Script for Adobe InDesign

Add a label to placed graphics that lists the file name.

  • Label all graphics or a selected graphic
  • Choose layer, paragraph style, and object style
  • Adapt open source to customize or create other scripts
Download
Label Graphic Links

FREE to download
Please make a contribution

Many scripts are free to download thanks to the support of users. Help me keep developing new scripts by supporting my work. Click the button to make a contribution of any amount. Thank you.

Script adds label with file name to placed graphics as shown.

How-to Video

How to use the script

Set desired options and click the OK button to proceed. Labels are added atop each placed graphic, on the selected layer and styled as described below.

Layer — the layer to which graphic labels are added. A choice of layer is required. The list defaults to a layer named ‘Graphic Labels.’ if it exists. If the layer does not exist, the choice [Create 'Graphic Labels'] appears in the drop-down list. This choice creates the layer. It is recommended to use this layer, or another separate layer without content, so the labels can be hidden or set to non-printing when time to output the document.

Paragraph style — the paragraph style assigned to the text of each label. Choose an existing style or create a new one for label text before launching the script. Or choose the default, [No Paragraph Style], which does not assign any paragraph style. In that case, the text defaults to Arial, 9 points, swatch Black. For other defaults, edit the script code.

Object style — the object style assigned to the frame of each label. Choose an existing style or create a new one for label frames before launching the script. Or choose the default, [None], which does not assign any object style. In that case, the frame fill color is set to 100% Yellow, the swatch for which is created if it does not exist. Whether choosing a style or none, label frames are set to auto-sizing height and width. For other defaults, edit the script code.

PositionCorner puts labels in the top-left corner of each graphic. Center puts labels in the center of each graphic.

Source code

(download button below)

/*

Label Graphic Links
Copyright 2022 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 = "Label Graphic Links";

    if (!/indesign/i.test(app.name)) {
        alert("Script for InDesign", title, false);
        return;
    }

    // Script variables.
    var count;
    var doc;
    var doneMessage;
    var error;
    var font;
    var layer;
    var layerNames;
    var objectStyle;
    var objectStyleNames;
    var paragraphStyle;
    var paragraphStyleNames;
    var progress;
    var swatchFrameFill;
    var swatchFrameStroke;
    var swatchText;

    // Reusable UI variables.
    var g; // group
    var gc1; // group (column)
    var gc2; // group (column)
    var p; // panel
    var w; // window

    // Permanent UI variables.
    var btnCancel;
    var btnOk;
    var listLayers;
    var listObjectStyles;
    var listParagraphStyles;
    var rbAll;
    var rbCenter;
    var rbCorner;
    var rbSelected;

    // SETUP

    // Script requires open document.
    if (!app.documents.length) {
        alert("Open a document", title, false);
        return;
    }
    doc = app.activeDocument;
    // Get layer names.
    layerNames = doc.layers.everyItem().name;
    // Add 'Create Graphic Labels' if no layer 'Graphic Labels'.
    (function () {
        var i;
        for (i = layerNames.length - 1; i > -1; i--) {
            if (layerNames[i] == "Graphic Labels") {
                break;
            }
        }
        if (i < 0) {
            layerNames.unshift("[Create 'Graphic Labels']");
        }
    })();
    // Get style names.
    paragraphStyleNames = getStyleNames(doc.allParagraphStyles);
    objectStyleNames = getStyleNames(doc.allObjectStyles);

    // CREATE PROGRESS WINDOW

    progress = new Window("palette", "Progress", undefined, {
        "closeButton": false
    });
    progress.t = progress.add("statictext");
    progress.t.preferredSize = [450, -1];
    progress.b = progress.add("progressbar");
    progress.b.preferredSize = [450, -1];
    progress.display = function (message) {
        message && (this.t.text = message);
        this.show();
        this.update();
    };
    progress.increment = function () {
        this.b.value++;
    };
    progress.set = function (steps) {
        this.b.value = 0;
        this.b.minvalue = 0;
        this.b.maxvalue = steps;
    };

    // CREATE USER INTERFACE

    w = new Window("dialog", title);
    w.alignChildren = "fill";
    // Panel.
    p = w.add("panel");
    // Group of 2 columns.
    g = p.add("group");
    // Groups, columns 1 and 2.
    gc1 = g.add("group");
    gc1.orientation = "column";
    gc1.alignChildren = "left";
    gc2 = g.add("group");
    gc2.orientation = "column";
    gc2.alignChildren = "left";
    // Rows.
    gc1.add("statictext", undefined, "Graphics:").preferredSize = [-1, 23];
    g = gc2.add("group");
    g.margins = [0, 3, 0, -3];
    rbAll = g.add("radiobutton", undefined, "All");
    rbAll.preferredSize = [-1, 23];
    rbSelected = g.add("radiobutton", undefined, "Selected");
    rbSelected.preferredSize = [-1, 23];
    gc1.add("statictext", undefined, "Layer:").preferredSize = [-1, 23];
    listLayers = gc2.add("dropdownlist", undefined, layerNames);
    listLayers.preferredSize = [170, 23];
    gc1.add("statictext", undefined, "Paragraph style:").preferredSize = [-1, 23];
    listParagraphStyles = gc2.add("dropdownlist", undefined, paragraphStyleNames);
    listParagraphStyles.preferredSize = [170, 23];
    gc1.add("statictext", undefined, "Object style:").preferredSize = [-1, 23];
    listObjectStyles = gc2.add("dropdownlist", undefined, objectStyleNames);
    listObjectStyles.preferredSize = [170, 23];
    gc1.add("statictext", undefined, "Position:").preferredSize = [-1, 23];
    g = gc2.add("group");
    g.margins = [0, 3, 0, -3];
    rbCorner = g.add("radiobutton", undefined, "Corner");
    rbCorner.preferredSize = [-1, 23];
    rbCenter = g.add("radiobutton", undefined, "Center");
    rbCenter.preferredSize = [-1, 23];
    // Action Buttons.
    g = w.add("group");
    g.alignment = "center";
    btnOk = g.add("button", undefined, "OK");
    btnCancel = g.add("button", undefined, "Cancel");
    // Panel Copyright.
    p = w.add("panel");
    p.add("statictext", undefined, "Copyright 2022 William Campbell");

    // SET DEFAULT VALUES

    if (doc.selection.length) {
        // Something is selected.
        rbSelected.enabled = true;
        rbAll.value = false;
        rbSelected.value = true;
    } else {
        rbSelected.enabled = false;
        rbAll.value = true;
        rbSelected.value = false;
    }
    listLayers.selection = listLayers.find("Graphic Labels") || 0;
    listParagraphStyles.selection = 0;
    listObjectStyles.selection = 0;
    rbCenter.value = true;

    // UI ELEMENT EVENT HANDLERS

    btnOk.onClick = function () {
        w.close(1);
    };

    btnCancel.onClick = function () {
        w.close(0);
    };

    // DISPLAY THE DIALOG

    if (w.show() == 1) {
        doneMessage = "";
        try {
            app.doScript(process, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, title);
            doneMessage = count + " graphic links labeled";
        } catch (e) {
            error = error || e;
            doneMessage = "An error has occurred.\nLine " + error.line + ": " + error.message;
        }
        progress.close();
        doneMessage && alert(doneMessage, title, error);
    }

    //====================================================================
    //               END PROGRAM EXECUTION, BEGIN FUNCTIONS
    //====================================================================

    function itemByName(o, name) {
        var i;
        for (i = 0; i < o.length; i++) {
            if (name == o[i].name) {
                return o[i];
            }
        }
        return null;
    }

    function getStyleNames(o) {
        var a1 = [];
        var a2 = [];
        var i;
        var name;
        for (i = 0; i < o.length; i++) {
            name = o[i].name;
            if (/^\[/.test(name)) {
                // Name begins with bracket.
                a1.push(name);
            } else {
                a2.push(name);
            }
        }
        // Sort names that do not begin with bracket.
        a2.sort(function (a, b) {
            // Case-insensitive.
            var aLow = a.toLowerCase();
            var bLow = b.toLowerCase();
            if (aLow < bLow) return -1;
            if (aLow > bLow) return 1;
            return 0;
        });
        // Combine names with brackets + names without sorted.
        return a1.concat(a2);
    }

    function process() {
        var graphic;
        var graphics;
        var i;
        var link;
        var selection;
        // Preserve preferences.
        var preserve = {
            rulerOrigin: doc.viewPreferences.rulerOrigin
        };
        app.scriptPreferences.userInteractionLevel = UserInteractionLevels.NEVER_INTERACT;
        app.scriptPreferences.measurementUnit = MeasurementUnits.POINTS;
        doc.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN;
        try {
            // Get (or make) layer.
            if (/\[Create /.test(listLayers.selection.text)) {
                doc.activeLayer = doc.layers[0];
                layer = doc.layers.add();
                layer.name = "Graphic Labels";
            } else {
                layer = doc.layers.item(listLayers.selection.text);
            }
            doc.activeLayer = layer;
            // Unlock layer and make visible.
            layer.locked = false;
            layer.visible = true;
            if (listParagraphStyles.selection > 0) {
                paragraphStyle = itemByName(doc.allParagraphStyles, listParagraphStyles.selection.text);
            } else {
                font = app.fonts.itemByName("Arial\tRegular");
                try {
                    font.fullName;
                } catch (_) {
                    // Couldn't get font by name. Use font from [Basic Paragraph]
                    font = doc.paragraphStyles[1].appliedFont;
                }
                swatchText = doc.swatches.itemByName("Black");
                if (!swatchText.isValid) {
                    // Couldn't get swatch by name. Try index 3, usual position for 'Black'.
                    swatchText = doc.swatches[3];
                }
            }
            if (listObjectStyles.selection > 0) {
                objectStyle = itemByName(doc.allObjectStyles, listObjectStyles.selection.text);
            } else {
                swatchFrameFill = doc.swatches.itemByName("C=0 M=0 Y=100 K=0");
                if (!swatchFrameFill.isValid) {
                    // Couldn't get swatch by name. Create it.
                    swatchFrameFill = doc.colors.add();
                    swatchFrameFill.name = "C=0 M=0 Y=100 K=0";
                    swatchFrameFill.space = ColorSpace.CMYK;
                    swatchFrameFill.colorValue = [0, 0, 100, 0];
                    swatchFrameFill.model = ColorModel.PROCESS;
                }
                swatchFrameStroke = doc.swatches.itemByName("Black");
                if (!swatchText.isValid) {
                    // Couldn't get swatch by name. Try index 3, usual position for 'Black'.
                    swatchText = doc.swatches[3];
                }
            }
            count = 0;
            if (rbAll.value) {
                // Label all graphics.
                graphics = doc.allGraphics;
                progress.set(graphics.length);
                for (i = graphics.length - 1; i > -1; i--) {
                    graphic = graphics[i];
                    try {
                        link = graphic.itemLink;
                        if (link) {
                            progress.display(link.name);
                            if (processGraphic(graphic, link.name)) {
                                count++;
                            }
                        }
                    } finally {
                        progress.increment();
                    }
                }
            } else {
                // Label selected graphic(s).
                for (i = 0; i < doc.selection.length; i++) {
                    selection = doc.selection[i];
                    if (!(selection instanceof Rectangle || selection.parent instanceof Rectangle)) {
                        // Selection is not a graphic or its frame.
                        continue;
                    }
                    if (selection instanceof Rectangle) {
                        graphic = selection.allGraphics[0];
                    } else {
                        graphic = selection;
                    }
                    link = graphic.itemLink;
                    if (link) {
                        processGraphic(graphic, link.name);
                        count++;
                    }
                }
            }
        } catch (e) {
            error = e;
            throw e;
        } finally {
            // Reset script preferences.
            app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL;
            // Restore preferences.
            doc.viewPreferences.rulerOrigin = preserve.rulerOrigin;
        }
    }

    function processGraphic(graphic, name) {
        var gb1; // geometric bounds graphic
        var gb2; // geometric bounds text frame
        var parent;
        var textFrame;
        var x;
        var y;
        // Test if graphic is overset.
        try {
            gb1 = graphic.parent.geometricBounds;
        } catch (_) {
            // Probably overset.
            // Ignore.
            return false; // Failed
        }
        // Get parent page or spread.
        parent = graphic.parentPage || graphic.parent.parent;
        // Create and configure text frame.
        textFrame = parent.textFrames.add();
        textFrame.itemLayer = layer;
        // Character style 'None' must precede adding contents.
        textFrame.insertionPoints[0].appliedCharacterStyle = doc.characterStyles[0];
        textFrame.contents = name;
        // Set styles.
        if (paragraphStyle) {
            textFrame.paragraphs[0].appliedParagraphStyle = paragraphStyle;
        } else {
            textFrame.paragraphs[0].appliedParagraphStyle = doc.paragraphStyles[0];
            // Style paragraph manually.
            textFrame.paragraphs[0].appliedFont = font;
            textFrame.paragraphs[0].fillColor = swatchText;
            textFrame.paragraphs[0].pointSize = 9; // points
        }
        // These paragraph properties always set manually.
        textFrame.paragraphs[0].justification = Justification.LEFT_ALIGN;
        textFrame.paragraphs[0].alignToBaseline = false;
        if (objectStyle) {
            textFrame.appliedObjectStyle = objectStyle;
        } else {
            textFrame.appliedObjectStyle = doc.objectStyles[0];
            // Style frame manually.
            textFrame.fillColor = swatchFrameFill;
            textFrame.strokeColor = swatchFrameStroke;
            textFrame.strokeWeight = 1; // points
            textFrame.textFramePreferences.verticalJustification = VerticalJustification.CENTER_ALIGN;
            textFrame.textFramePreferences.insetSpacing = 6;
        }
        // These frame properties always set manually.
        textFrame.textFramePreferences.autoSizingReferencePoint = AutoSizingReferenceEnum.TOP_LEFT_POINT;
        textFrame.textFramePreferences.autoSizingType = AutoSizingTypeEnum.HEIGHT_AND_WIDTH;
        textFrame.textFramePreferences.useNoLineBreaksForAutoSizing = true;
        textFrame.textFramePreferences.ignoreWrap = true;
        textFrame.textWrapPreferences.textWrapMode = TextWrapModes.NONE;
        if (rbCorner.value) {
            // Move text frame to top-left corner of graphic.
            // But not beyond page edge.
            x = Math.max(0, gb1[1]);
            y = Math.max(0, gb1[0]);
        } else {
            // Center text frame within graphic.
            gb2 = textFrame.geometricBounds;
            x = (gb1[1] + ((gb1[3] - gb1[1]) / 2)) - ((gb2[3] - gb2[1]) / 2);
            y = (gb1[0] + ((gb1[2] - gb1[0]) / 2)) - ((gb2[2] - gb2[0]) / 2);
        }
        textFrame.move([x, y]); // Absolute coordinates.
        return true; // Success
    }

})();
Many scripts are free to download thanks to the support of users. Help me keep developing new scripts by supporting my work. Click the button to make a contribution of any amount. Thank you.
Download
Label Graphic Links

For help installing scripts, see How to Install and Use Scripts in Adobe Creative Cloud Applications.

Also available for hire to program custom solutions. Contact William for more information.

IMPORTANT: by downloading any of the scripts on this page you agree that the software is provided without any warranty, express or implied. USE AT YOUR OWN RISK. Always make backups of important data.