Image Alt-Text Script - "Custom" Source Issue
I've been working on a script to loop through all the images in a document and set their alt text. The issue I'm running into is that even though the custom alt text is being applied, the "Object Export Options" for those images aren't being set to "Custom." As a result, when I export to PDF, the alt text doesn't appear unless I manually go in and set each image’s export option to "Custom."
I'm looking for a way to programmatically set both the custom alt text and ensure that the "Alt Text Source" in the Object Export Options is set to "Custom," so the PDF export includes the alt text correctly.
Also if I check decorative I need that to display properly in the Object Export Options as well. and that isnt happening.
Any help would be greatly appreciated! My current code is below:
// Image Alt Text Assistant
// This script loops through all images in the InDesign document and
// prompts the user to add alt text or mark images as decorative
// Main function
function main() {
if (app.documents.length === 0) {
alert("Please open a document before running this script.");
return;
}
var doc = app.activeDocument;
var allGraphics = getAllGraphics(doc);
if (allGraphics.length === 0) {
alert("No images found in the document.");
return;
}
// Ask the user if they want to process all images
var startScript = confirm("Alt Text Assistant will process " + allGraphics.length + " images.\nClick Yes to begin or No to exit.");
if (!startScript) {
return; // Exit the script if the user clicks No
}
processGraphics(allGraphics);
}
// Find all graphics in the document, including those in groups and nested frames
function getAllGraphics(doc) {
var allGraphics = [];
// Process all pages in the document
for (var p = 0; p < doc.pages.length; p++) {
var page = doc.pages[p];
// Process all page items on each page
for (var i = 0; i < page.allPageItems.length; i++) {
var item = page.allPageItems[i];
// Check if the item is a graphic or image
if ((item instanceof Rectangle ||
item instanceof Oval ||
item instanceof Polygon) &&
item.graphics.length > 0) {
allGraphics.push(item);
}
}
}
return allGraphics;
}
// Process each graphic and prompt for alt text
function processGraphics(graphics) {
var skippedCount = 0;
var updatedCount = 0;
var decorativeCount = 0;
var processedCount = 0;
// Save the current view state to restore later
var originalPage = app.activeWindow.activePage;
for (var i = 0; i < graphics.length; i++) {
var graphic = graphics[i];
var currentAltText = "";
var isDecorative = false;
// Check if the graphic already has alt text
try {
currentAltText = graphic.objectExportOptions.customAltText || "";
} catch (e) {
// Error handling if properties can't be accessed
}
// Navigate to the page containing the image and select it
try {
// Go to the page with the image
app.activeWindow.activePage = graphic.parentPage;
// Select just this frame to highlight it
app.selection = [];
graphic.select();
// Pause briefly to let InDesign update the display
app.scriptPreferences.enableRedraw = true;
$.sleep(100);
} catch (e) {
// Error handling if we can't navigate to the image
alert("Could not navigate to the image (but will continue): " + e);
}
// Create a preview of the graphic location for the user
var locationInfo = "Page " + graphic.parentPage.name;
// Create dialog using the ScriptUI approach instead of Dialog API
var dialog = new Window('dialog', "Alt Text Assistant - Image " + (i+1) + " of " + graphics.length);
dialog.orientation = 'column';
dialog.alignChildren = ['fill', 'top'];
dialog.spacing = 10;
dialog.margins = 16;
// Image information section
var infoGroup = dialog.add('panel', undefined, 'Image Information');
infoGroup.orientation = 'column';
infoGroup.alignChildren = ['left', 'top'];
infoGroup.margins = [10, 15, 10, 10];
infoGroup.add('statictext', undefined, "Image Location: " + locationInfo);
// Add image file name if available
try {
if (graphic.graphics.length > 0 && graphic.graphics[0].itemLink) {
var fileName = graphic.graphics[0].itemLink.name;
infoGroup.add('statictext', undefined, "File: " + fileName);
}
} catch (e) {
// Silently ignore errors getting filename
}
// Current alt text display (if any)
if (currentAltText) {
infoGroup.add('statictext', undefined, "Current Alt Text: " + currentAltText);
}
// Alt text input section
var altTextGroup = dialog.add('panel', undefined, 'Alternative Text');
altTextGroup.orientation = 'column';
altTextGroup.alignChildren = ['fill', 'top'];
altTextGroup.margins = [10, 15, 10, 10];
altTextGroup.add('statictext', undefined, "Enter alternative text for this image:");
var altTextEntry = altTextGroup.add('edittext', undefined, currentAltText, {multiline: true});
altTextEntry.preferredSize.width = 350;
altTextEntry.preferredSize.height = 100;
// Decorative checkbox
var decorativeCheckbox = altTextGroup.add('checkbox', undefined, "This image is decorative (no alt text needed)");
decorativeCheckbox.value = isDecorative;
// Set up checkbox behavior - disable text field when checked
decorativeCheckbox.onClick = function() {
altTextEntry.enabled = !this.value;
if (this.value) {
altTextEntry.text = "";
}
};
// Help text
dialog.add('statictext', undefined, "The image is currently selected on the page");
// Button group
var buttonGroup = dialog.add('group');
buttonGroup.orientation = 'row';
buttonGroup.alignChildren = ['center', 'center'];
var okButton = buttonGroup.add('button', undefined, 'OK', {name: 'ok'});
var skipButton = buttonGroup.add('button', undefined, 'Skip');
var exitButton = buttonGroup.add('button', undefined, 'Exit Script');
// Set button behavior
skipButton.onClick = function() {
skippedCount++;
dialog.close(0); // Close with cancel code
};
exitButton.onClick = function() {
var confirmExit = confirm("Exit the Alt Text Assistant?\nYour progress so far will be saved.");
if (confirmExit) {
i = graphics.length; // Force exit from the loop
dialog.close(0);
}
};
// Show the dialog
if (dialog.show() == 1) { // 1 = OK button
// User clicked OK
var newAltText = altTextEntry.text;
var isNowDecorative = decorativeCheckbox.value;
// Update the alt text
try {
if (isNowDecorative) {
graphic.objectExportOptions.customAltText = "";
decorativeCount++;
} else if (newAltText) {
graphic.objectExportOptions.customAltText = newAltText;
updatedCount++;
}
// Also try to set the Alt Text Source to Custom
try {
app.doScript(
"app.selection[0].objectExportOptions.exportOption = ExportOption.CUSTOM;",
ScriptLanguage.JAVASCRIPT
);
} catch (e) {
// Silently fail if this property isn't available
}
} catch (e) {
alert("Error setting alt text: " + e);
}
}
processedCount++;
// Check if the user exited early
if (i >= graphics.length) {
break;
}
}
// Restore the original view state
try {
app.activeWindow.activePage = originalPage;
app.selection = [];
} catch (e) {
// Silently ignore errors restoring view
}
// Show summary of changes without any reminders about manually setting options
alert("Alt Text Assistant complete!\n\n" +
"Images processed: " + processedCount + " of " + graphics.length + "\n" +
"Updated with alt text: " + updatedCount + "\n" +
"Marked as decorative: " + decorativeCount + "\n" +
"Skipped: " + skippedCount);
}
// Run the script
main();
