I was hoping to get some help regarding a script which malfunctions in my situation.
Also I would like to add that the people using the script flawlessly were using it on a macOS and I am on a Windows PC.
I use Adobe InDesign 2025 version with all updates installed.
(function () {
if (parseInt(app.version) < 6) {
alert('This script requires InDesign CS4 or later.');
exit();
}
if (app.documents.length == 0) {
alert('Please open a document');
exit();
}
function find_fonts() {
var known = {};
var typefaces = [];
var fontfamilies = app.fonts.everyItem().fontFamily;
for (var i = 0; i < fontfamilies.length; i++) {
if (!known[fontfamilies[i]]) {
known[fontfamilies[i]] = true;
typefaces.push(fontfamilies[i]);
}
}
return typefaces;
}
function buildListCharacterStyles(scope, list, str, path) {
var styles = scope.characterStyles.everyItem().getElements();
for (var i = 0; i < styles.length; i++) {
if (styles[i] != app.documents[0].characterStyles[0]) {
var temp = list.add('item', styles[i].name + (str == '' ? '' : ' (' + str + ')'));
temp.id = styles[i].id;
temp.path = path + styles[i].name;
}
}
for (var j = 0; j < scope.characterStyleGroups.length; j++) {
buildListCharacterStyles(
scope.characterStyleGroups[j],
list,
str + (str == '' ? '' : ':') + scope.characterStyleGroups[j].name,
path + scope.characterStyleGroups[j].name + '%%'
);
}
}
function get_data() {
var fontnames = find_fonts();
var w = new Window('dialog {text: "Missing glyphs", properties: {closeButton: false}}');
var main = w.add('panel {alignChildren: "left"}');
var fontgroup = main.add('group');
var replacefonts = fontgroup.add('checkbox {text: "Replace missing glyphs with font:"}');
var replacement_font = fontgroup.add('dropdownlist', undefined, fontnames);
var cstylegroup = main.add('group');
var applyStyle = cstylegroup.add('checkbox {text: "Apply character style: "}');
var charStyles = cstylegroup.add('dropdownlist');
charStyles.preferredSize.width = 200;
var display = main.add('checkbox {text: "Display missing glyphs and fonts"}');
var buttons = w.add('group {alignment: "right"}');
buttons.add('button {text: "OK", name: "ok"}');
buttons.add('button {text: "Cancel", name: "cancel"}');
replacefonts.onClick = function () {
applyStyle.value = !replacefonts.value;
};
replacement_font.onChange = function () {
if (!replacefonts.value) {
replacefonts.notify();
}
};
applyStyle.onClick = function () {
replacefonts.value = !applyStyle.value;
};
charStyles.onChange = function () {
if (!applyStyle.value) {
applyStyle.notify();
}
};
display.onClick = function () {
if (display.value) {
replacefonts.value = applyStyle.value = false;
}
};
var minion = replacement_font.find('Minion Pro');
replacement_font.selection = minion ? minion : 0;
replacefonts.value = 1;
var buffer = '';
var current = replacement_font.selection.text;
replacement_font.onActivate = function () {
buffer = '';
current = replacement_font.selection.text;
};
replacement_font.addEventListener('keydown', function (k) {
if (k.keyName == 'Backspace') {
buffer = buffer.replace(/.$/, '');
if (buffer.length == 0) {
buffer = current;
}
} else {
buffer += k.keyName.toLowerCase();
}
var i = 0;
while (i < fontnames.length - 1 && fontnames[i].toLowerCase().indexOf(buffer) != 0) {
++i;
}
if (fontnames[i].toLowerCase().indexOf(buffer) == 0) {
replacement_font.selection = i;
}
});
w.onShow = function () {
buildListCharacterStyles(app.activeDocument, charStyles, '', '');
if (charStyles.items.length > 0) {
charStyles.selection = 0;
}
};
if (w.show() == 2) {
return null;
}
// 🛠️ Prevent null reference
if ((applyStyle.value || (!replacefonts.value && !display.value)) && !charStyles.selection) {
alert("Please select a character style.");
return null;
}
return {
replace: replacefonts.value,
replacement_font: replacement_font.selection ? replacement_font.selection.text : "",
applyStyle: applyStyle.value,
character_style: charStyles.selection
? app.documents[0].characterStyles.itemByID(charStyles.selection.id)
: null,
display: display.value,
};
}
function replace_missing_glyphs(data) {
var docFonts = app.activeDocument.fonts.everyItem().getElements();
var errormsg = '';
app.findGlyphPreferences = null;
for (var i = 0; i < docFonts.length; i++) {
if (docFonts[i].status == FontStatus.INSTALLED && docFonts[i].isValid) {
app.findGlyphPreferences.glyphID = 0;
app.findGlyphPreferences.appliedFont = docFonts[i].fontFamily;
app.findGlyphPreferences.fontStyle = docFonts[i].fontStyleName;
var found = app.activeDocument.findGlyph();
for (var j = 0; j < found.length; j++) {
if (data.replace) {
found[j].appliedFont = data.replacement_font;
} else if (data.applyStyle && data.character_style) {
found[j].appliedCharacterStyle = data.character_style;
}
}
} else {
try {
errormsg += docFonts[i].fontFamily + '\r';
} catch (_) {}
}
}
if (errormsg.length > 1) {
errormsg = 'The following fonts are not installed\n(or have an illegal font style specified)\nand were skipped:\n\n' + errormsg;
alert(errormsg);
}
}
function list_missing_glyphs() {
var docFonts = app.activeDocument.fonts.everyItem().getElements();
var report = '';
for (var i = 0; i < docFonts.length; i++) {
if (docFonts[i].status != FontStatus.INSTALLED) {
report += '[' + docFonts[i].name + ']\r';
} else {
app.findGlyphPreferences = null;
app.findGlyphPreferences.glyphID = 0;
app.findGlyphPreferences.appliedFont = docFonts[i].fontFamily;
app.findGlyphPreferences.fontStyle = docFonts[i].fontStyleName;
var found = app.activeDocument.findGlyph();
if (found.length > 0) {
var known = {};
report += docFonts[i].fontFamily + ' (' + docFonts[i].fontStyleName + ')\r';
for (var j = 0; j < found.length; j++) {
var miss = get_hex(found[j]);
if (!known[miss]) {
report += found[j].contents + '\t' + miss + '\r';
known[miss] = true;
}
}
report += '\r';
}
}
}
display_missing_glyphs(report);
}
function get_hex(ch) {
function pad(n) {
return ('0000' + n).slice(-4);
}
try {
if (ch.contents.length === 2) {
var H = parseInt(ch.contents.charCodeAt(0).toString(16), 16);
var L = parseInt(ch.contents.charCodeAt(1).toString(16), 16);
var s = ((H - 0xD800) * 0x400) + (L - 0xDC00) + 0x10000;
return '\\x{' + s.toString(16).toUpperCase() + '}';
}
var s = ch.contents.charCodeAt(0).toString(16);
return '\\x{' + pad(s).toUpperCase() + '}';
} catch (_) {
return 'U+????';
}
}
function display_missing_glyphs(s) {
var w = new Window('dialog {text: "Missing glyphs", properties: {closeButton: false}}');
var e = w.add('edittext', undefined, s.length == 0 ? 'No missing glyphs.' : s, {
multiline: true,
scrolling: true,
});
e.maximumSize.height = w.maximumSize.height - 150;
var b = w.add('group');
b.add('button {text: "Close", properties: {name: "ok"}}');
var save = b.add('button {text: "Save"}');
save.onClick = function () {
var outfile = File('~/Desktop/' + app.activeDocument.name.replace(/\.indd$/, '_missing_glyphs.txt'));
outfile.encoding = 'UTF-8';
outfile.open('w');
outfile.write(e.text);
outfile.close();
outfile.execute();
};
w.show();
}
function main() {
app.findChangeGlyphOptions.includeFootnotes = true;
var data = get_data();
if (!data) return;
if (data.replace || data.applyStyle) {
replace_missing_glyphs(data);
}
if (data.display) {
list_missing_glyphs();
}
}
main();
})();
Niven Wadke.