Home > InDesign Scripts > Find/change missing font with scripting

Find/change missing font with scripting

Does this image looks familiar?! Do you want to change missing font through scripting? Then I have good news for you, it can be done really fast and easy! We are going to look easiest way for retrieving missing fonts from document, and also I will share this script integrated into dialog and font selector. This idea came up to me yesterday while I was studying ‘BeforePrint.jsx’ from Scripting guide that you can download from Adobe InDesgin scripting page. Also, Marc Autret posted script on Adobe’s InDesign Scripting forum for changing missing fonts inside styles, so be sure you check it! So, let’s get started!🙂

First, let’s retrieve all used fonts in document like this:

var usedFonts = app.activeDocument.fonts;

Good. Now, the good news is that every font has ‘status’ property so we can loop through fonts and retrieve font’s that don’t have ‘FontStatus.INSTALLED’:

var missingFonts = Array();
for(var i = 0; i < usedFonts.length; i++){
  if(usedFonts[i].status != FontStatus.INSTALLED)missingFonts.push(usedFonts[i]);
}

Great! Now, ‘missingFonts’ holds all font objects that are missing in document. What can we do now? We can simply use find/replace to replace missing font with font available on our system. Let’s first see simple find example:

app.findTextPreferences = NothingEnum.nothing;
app.findTextPreferences.appliedFont = missingFonts[0];
var missingFind = app.activeDocument.findText();

Next, we can do find/replace like this:

app.findTextPreferences = NothingEnum.nothing;
app.changeTextPreferences = NothingEnum.nothing;
app.findTextPreferences.appliedFont = missingFonts[0];
app.changeTextPreferences.appliedFont = "Myriad Pro";
app.activeDocument.changeText();

So, that’s it, fast and simple. Of course, you can for example find/change just in selected frame, story, page or whatever you want. It’s up to you and your needs.

Now, I want to share script that I created yesterday. It’s similar to InDesign’s ‘Type -> Find Font…’ dialog, but it’s all done through scripting. So, I prepared little text box with some fonts missing:

Now we run script. Script shows just missing fonts. We select destination font family and style and click OK:

As we can see, our missing font is replaced:

If we run script again, we can see that missing font is gone:

And here is the script:

//get unique Array elements
Array.prototype.unique = function (){
    var r = new Array();
    o:for(var i = 0, n = this.length; i < n; i++){
        for(var x = 0, y = r.length; x < y; x++){
            if(r[x]==this[i]) continue o;}
        r[r.length] = this[i];}
    return r;
}

//search inside array
Array.prototype.findIn = function(search){
    var r = Array();
    for (var i=0; i<this.length; i++)
        if (this[i].indexOf(search) != -1){
            r.push(this[i].substr(this[i].indexOf("\t") + 1, this[i].length));
        }
    return r;
}

var usedFonts = app.activeDocument.fonts;

var sysFonts = app.fonts.everyItem();
sysFontsList = sysFonts.fontFamily.unique();
sysFontsList.unshift("- Select Font Family -");

var fontsWin = new Window('dialog', 'Document Fonts');
fontsWin.alignChildren = 'center';

var allFonts = fontsWin.add('listbox', undefined, undefined, {numberOfColumns: 5, showHeaders: true, columnTitles: ['Font Name', 'Font Style', 'Font PS Name', 'Font Type', 'Chr count']});
allFonts.minimumSize = [600,150];

var myGrp = fontsWin.add('group');
myGrp.alignChildren = 'center';

var availableFonts = myGrp.add('dropdownlist',undefined,sysFontsList);
var availableStyles = myGrp.add('dropdownlist');
var okButton = myGrp.add('button',undefined,'OK');
var okButton = myGrp.add('button',undefined,'Cancel');

availableStyles.minimumSize = [180,25];
availableFonts.selection = 0;
availableFonts.onChange = function(){
    availableStyles.removeAll();
    var sysFontAvailableStyles = sysFonts.name.findIn(availableFonts.selection);
    for(var i = 0; i < sysFontAvailableStyles.length; i++)availableStyles.add('item',sysFontAvailableStyles[i]);
    availableStyles.selection = 0;
}

//// SHOW JUST MISSING FONTS //// [START]

for(var i = 0; i < usedFonts.length; i++){
    if(usedFonts[i].status != FontStatus.INSTALLED){
        allFonts.add('item',usedFonts[i].fontFamily);
        allFonts.items[allFonts.items.length-1].image = 'SystemWarningIcon';
        allFonts.items[allFonts.items.length-1].subItems[3].text = findCharacters(usedFonts[i].name);
        allFonts.items[allFonts.items.length-1].subItems[0].text = usedFonts[i].fontStyleName;
        allFonts.items[allFonts.items.length-1].subItems[1].text = usedFonts[i].postscriptName;
        allFonts.items[allFonts.items.length-1].subItems[2].text = usedFonts[i].fontType;
    }
}

//// SHOW JUST MISSING FONTS //// [END]

allFonts.selection = 0;

fontsWin.center();

var fontAnswer = fontsWin.show();

if(fontAnswer == true && availableFonts.selection != 0){
    var sourceFont = allFonts.selection.text + "\t" + allFonts.selection.subItems[0].text;
    var destFont = availableFonts.selection.text + "\t" + availableStyles.selection.text;
    changeFont(sourceFont,destFont);
}else{
    alert('No Actions taken!');
}

function findCharacters(findFont){
    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;
    app.findGrepPreferences.findWhat = ".";
    app.findGrepPreferences.appliedFont = findFont;
    var result = Number(app.activeDocument.findGrep().length);
    
    return result;
}

function changeFont(sourceFont, destinationFont){
    app.findTextPreferences = NothingEnum.nothing;
    app.changeTextPreferences = NothingEnum.nothing;
    app.findTextPreferences.appliedFont = sourceFont;
    app.changeTextPreferences.appliedFont = destinationFont;
    app.activeDocument.changeText();
}

Also, if you want to see all document fonts in dialog change loop between comments with this one:

//// SHOW ALL FONTS //// [START]

for(var i = 0; i < usedFonts.length; i++){
    if(usedFonts[i].status == FontStatus.INSTALLED){
        allFonts.add('item',usedFonts[i].fontFamily);
    }else{
        allFonts.add('item',usedFonts[i].fontFamily);
        allFonts.items[i].image = 'SystemWarningIcon';
        allFonts.items[i].subItems[3].text = findCharacters(usedFonts[i].name);
    }
    allFonts.items[i].subItems[0].text = usedFonts[i].fontStyleName;
    allFonts.items[i].subItems[1].text = usedFonts[i].postscriptName;
    allFonts.items[i].subItems[2].text = usedFonts[i].fontType;
}

//// SHOW ALL FONTS //// [END]

Yeah, that’s it!

Have fun!😀

  1. zixind
    May 6, 2011 at 10:54

    Any news on this?
    It doesn’t seem to work in CS5 or CS4. At least not on my computer – I have OS X Snow Leopard, and also Universal Type Client.
    Replacing active fonts with other fonts works, but not replacing missing fonts. If you don’t clean up the search window after replacing, you can try the same search/replace manually, it is already set up for you. Doesn’t work.
    When going into the “Find format” setting and selecting the missing font there (it is marked with square brackets), it works though. The text in the “Find format” field looks the same.

    Something has changed in InDesign, perhaps? If you want example files to try it out on, I can supply you with multiple.

  2. zixind
    May 6, 2011 at 12:52

    Some more info: this seems to happen mostly (only?) when there are conflicting fonts on the computer. A client like UTC should handle this, but there are still loads of fonts being installed in the system, whether you want to or not. I recently had a case where a “Garamond” was to be changed to an Adobe Garamond Pro. It turned out, there is a “Garamond” somewhere in one of the system’s “Fonts” folders on this computer (perhaps it is a default OS X font, haven’t looked into that yet). However, the font *variant* was named differently, so in InDesign it looked like this:
    Garamond [Regular]
    If I wouldn’t have had any Garamond font at all in my system, it would have looked like this:
    [Garamond] [Regular]
    and then the script would have worked. It seems it confuses InDesign when the font (or a similar one) exists, but not the variant.

    The system folder really shouldn’t have any fonts at all, that would be the best for all DTP:ers… but, alas, we can’t have it that way.

    Would there be a way of working around this?

  1. October 31, 2011 at 18:18

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: