Skip to main content
Participant
June 28, 2013
Question

how to get font properties like line height, ascend, descend, ideographic top etc..?

  • June 28, 2013
  • 1 reply
  • 4382 views

I would like to know if we can access font properties like line-height, ascend, descend etc. through scripting.

I have been trying to get this now by applying a font to sample text as mentioned below.

var fontLists = app.fonts.everyItem().getElements();

var applicationDocument = app.documents.add();

var appPage = applicationDocument.pages.item(0);

var appTextFrame = appPage.textFrames.add();

appTextFrame.contents = "sample";

var appParagraphText = appTextFrame.paragraphs[0];

for (var i=0; i<fontLists.length; i++){

     var xfont = app.fonts;

    //alert('font name '+xfont.name);

    appParagraphText.appliedFont = app.fonts.item(xfont.name);

    var line = appParagraphText.lines[0];

    var myLineheight = line.ascent + line.descent

    alert('font name '+xfont.name +' \n baselineShift -'+appParagraphText.baselineShift+' \n fontStyle - '+appParagraphText.fontStyle

    +' \n fontAscent - ' + appParagraphText.ascent+' \n descent - '+appParagraphText.descent) + ' \n line height '+myLineheight;

}  

Is there any other better way to get this?

This topic has been closed for replies.

1 reply

Inspiring
July 8, 2013

Hi,

A couple of months ago I wrote script to set type based on the cap height in mm, inches or pts – which is the way I work in signage projects.

Cap height (ref is letter 'H'), x-height (ref is letter 'x'), ascender (ref could be 'h') and descender (no sharp ref, but 'y' will do) are values defined when designing the actual font. In the font-design program they are relative to each other. So, lets say:

• the x-height is 500 units,

• the ascender height is 700,

• the descender height is -200,

• the cap height is 650.

These units don't mean much in InDesign, but you can establish proportions between them. So what you could do is:

0. use 12pts as ref

1. create a temp text frame (like you did)

2. 'type' the letter 'x' (this will give a ref to x-height)

3. set it to 12pts

3. convert to outlines

4. get the height of the outlined 'x' (var xHeight will be 'y2 - y1')

5. remove the outlined 'x'

Then do it with cap height ('H'), ascender ('h') and descender ('y'). And establish proportional relations between them. Keep in mind that xHeight has a relation to 12pts (or whatever size you define for the em-square).

The major issue is that each font has its own relationships and the design of some fonts won't give 100% sharp heights (mostly serifed fonts). So you need to run this routine every time you want values for different fonts. The script I wrote asks the user to choose a font and then it writes a completely new script with the proportions of the selected font – the new script is created in the same folder as the main one.

I am not sure whether this will work for you, but run the script and have a look on the code to see if there's something that can help you:

Best,

ps.: sorry for the long code... couldn't get my ftp working on this one...

//

// This script finds out the proportion between a font

// and its cap height.

// The user chooses the font and a new script is created

// considering that proportion.

// Type can then be set for the cap height in mm, inches

// or pts.

//

// Made with parts of other scripts.

// Many thanks to all of you who share your work.

//

// Gustavo Soares

// ttid.com.br

//

#target InDesign

var myDoc = app.documents.add(false);

myDoc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;

myDoc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;

//get total of installed fonts

var fontCount = app.fonts.count();

//alerts if too many fonts are installed

if (fontCount > 300) {

    alert ("You have too many fonts installed (" + fontCount + "). It may take a while to compile the list.");

}

//creates the dropdown list of fonts

var fontList = new Array();

//creates the progress bar

var progress = new progressBar ("Compiling Font List");

//call function progress bar

//requirements (title)

progress.text("Processing ", fontCount);

for (i = 0; i < app.fonts.count(); i++) {

    fontList.push(app.fonts.postscriptName);

    progress.hit(app.fonts.postscriptName);

          $.sleep (0.5);

}

progress.close();

//ref to the dialog

var myDialog = app.dialogs.add({name:"Choose a font", canCancel:true});

//creates the dialog box

with(myDialog){

    with(dialogColumns.add()){

        with(borderPanels.add()){

            with(dialogColumns.add()){

                staticTexts.add({staticLabel:"Font:"});

            }

            with(dialogColumns.add()){

                var fontMenu = dropdowns.add({stringList:fontList, selectedIndex:0});

            }

        }

    }

}

//main action

//check functions for details

if(myDialog.show() == true){

    var myFontIndex = fontMenu.selectedIndex;

    var myFontName = fontList[myFontIndex];

    var myFontFamily = app.fonts[myFontIndex].fontFamily;

    var capHeightProportion;

    myDialog.destroy();

    getCapHeight(myFontIndex, myFontName);

    generateScript(myFontFamily, capHeightProportion);

}

else{

    myDialog.destroy()

}

myDoc.close(SaveOptions.NO);

app.activate();

//————————————————————————————//

//    Functions start here    //

//————————————————————————————//

//build the progress bar

function progressBar (title) {

 

          var w = new Window ("palette", title, {x:0, y:0, width:340, height:60});

          var pb = w.add ("progressbar", {x:20, y:12, width:300, height:12}, 0, 100);

          var st = w.add("statictext", {x:20, y:36, width:320, height:20}, "");

          w.center();

          w.show();

 

          this.text = function (msg, maxValue) {

                    st.text = msg;

                    pb.value = 0;

                    pb.maxvalue = maxValue;

                    w.center;

                    w.show();

          }

          this.hit = function(file) {

                    st.text = "Processing: " + file;

                    ++pb.value;

          };

 

          this.close = function() {w.close()};

 

}

//1. create a temp text frame of 100 x 100pts

//2. set 'H' on the chosen font at 100pts

//3. create outline

//4. get the proportion between the 100pts text frame and the outline 'H'

function getCapHeight(myFontIndex, myFontName) {

    var myPage = myDoc.pages[0];

    var myTextFrame = myPage.textFrames.add({geometricBounds:[0, 0, 100, 100]});

    myTextFrame.contents = "H";

    with (myTextFrame.characters[0]){

        pointSize = 100;

        appliedFont = app.fonts.item(myFontIndex);

    }

    myTextFrame.createOutlines();

    var myCap = myPage.pageItems[0];

    myCap.move([0, 0]);

    var capBounds = myCap.geometricBounds;

    var capHeight = capBounds[2];

    capHeightProportion = capHeight / 100;

    capHeightProportion = capHeightProportion.toFixed(3);

    alert ("The cap height ratio for " + myFontName + " is: " + capHeightProportion);

    return capHeightProportion;

}

//write a new script file for using with the chosen font/proportions

function generateScript(myFontFamily, capHeightProportion) {

    var scriptFolder = app.scriptPreferences.scriptsFolder.fsName;

    try {

        var writeTest = File (scriptFolder + "/CapHeightOnTheFly-" + myFontFamily + ".jsx");

        writeTest.open("w");

        writeTest.write(

        "\n//" +

        "\n// This script allows the user to set type based" +

        "\n// on the cap height" +

        "\n//" +

        "\n// Made with parts of many other scripts." +

        "\n// Thanks to all of you who share your work." +

        "\n//" +

        "\n// by Gustavo Soares" +

        "\n// ttid.com.br" +

        "\n//" +

        "\n#target InDesign" +

        "\n" +

        "\nif (app.documents.length != 0){" +

            "\n\tvar myDoc = app.activeDocument;" +

            "\n" +

            "\n\tmyDoc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.MILLIMETERS;" +

            "\n\tmyDoc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.MILLIMETERS;" +

            "\n" +   

            "\n\t//If the selection contains more than one item, the selection is not text selected with the Type tool." +

            "\n\tif (myDoc.selection.length == 1){" +

                "\n\t\t//Evaluate the selection based on its type." +

                "\n\t\tswitch (app.selection[0].constructor.name){" +

                    "\n\t\t\tcase 'InsertionPoint':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'Character':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'Word':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'TextStyleRange':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'Line':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'Paragraph':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'TextColumn':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'Text':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'Story':" +

                        "\n\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tcase 'TextFrame':" +

                        "\n\t\t\t\tif (app.selection[0].characters.count() != 0) {" +

                            "\n\t\t\t\t\tcreateDialog(1, " + capHeightProportion + ");" +

                        "\n\t\t\t\t}" +

                        "\n\t\t\t\telse {" +

                            "\n\t\t\t\t\talert('The selected object contains no text. Select some text and try again.');" +

                            "\n\t\t\t\t\tmyDoc.select(NothingEnum.NOTHING);" +

                        "\n\t\t\t\t}" +

                        "\n\t\t\t\tbreak;" +

                    "\n\t\t\tdefault:" +

                        "\n\t\t\t\talert('The selected object is not a text object. Select some text and try again.');" +

                        "\n\t\t\t\tbreak;" +

                "\n\t\t}" +

            "\n\t}" +

            "\n\telse if (myDoc.selection.length >= 1) {" +       

                "\n\t\tfor (i = 0; i < myDoc.selection.length; i++) {" +

                    "\n\t\t\tif (app.selection.constructor.name != 'TextFrame') {" +

                        "\n\t\t\t\talert('One of the selected objects is not a text object. Select only text and try again.');" +

                        "\n\t\t\t\tmyDoc.select(NothingEnum.NOTHING);" +

                    "\n\t\t\t}" +

                    "\n\t\t\telse if (app.selection.characters.count() == 0) {" +

                        "\n\t\t\t\talert('One of the selected objects contains no text. Select only text and try again.');" +

                        "\n\t\t\t\tmyDoc.select(NothingEnum.NOTHING);" +

                    "\n\t\t\t}" +

                "\n\t\t}" +

                "\n\t\tif (myDoc.selection.length != 0) {" +

                    "\n\t\t\tcreateDialog(myDoc.selection.length, " + capHeightProportion + ");" +

                "\n\t\t}" +

            "\n\t}" +

            "\n\telse {" +

                "\n\t\talert('Please select some text and try again.');" +

            "\n\t}" +

        "\n}" +

        "\n" +

        "\nelse {" +

            "\n\talert('Open a document and try again.');" +

        "\n}" +

        "\n" +

        "\n" +

        "\n//———Functions start here" +

        "\n" +

        "\nfunction createDialog(selectionLenght, capHeightProportion) {" +

            "\n\tvar myDialog = app.dialogs.add({name:'Cap Height On The Fly', canCancel:true});" +

            "\n" +

            "\n\twith(myDialog){" +

                "\n\t\t//Add a dialog column." +

                "\n\t\twith(dialogColumns.add()){" +

                    "\n\t\t\t//Create another border panel." +

                    "\n\t\t\twith(borderPanels.add()){" +

                        "\n\t\t\t\twith(dialogColumns.add()){" +

                            "\n\t\t\t\t\tstaticTexts.add({staticLabel:'Cap Height:'});" +

                        "\n\t\t\t\t}" +

                        "\n\t\t\t\twith(dialogColumns.add()){" +

                            "\n\t\t\t\t\t//Create a number entry field. Note that this field uses editValue" +

                            "\n\t\t\t\t\tvar capHeightField = measurementEditboxes.add();" +

                        "\n\t\t\t\t}" +

                    "\n\t\t\t}" +

                    "\n\t\t\t//Create another border panel." +

                    "\n\t\t\twith(borderPanels.add()){" +

                        "\n\t\t\t\tstaticTexts.add({staticLabel:'Units:'});" +

                        "\n\t\t\t\tvar buttonGroup = radiobuttonGroups.add();" +

                        "\n\t\t\t\twith(buttonGroup){" +

                            "\n\t\t\t\t\tvar button_pt = radiobuttonControls.add({staticLabel:'Points'});" +

                            "\n\t\t\t\t\tvar button_mm = radiobuttonControls.add({staticLabel:'Millimeters', checkedState:true});" +

                            "\n\t\t\t\t\tvar button_in = radiobuttonControls.add({staticLabel:'Inches'});" +

                        "\n\t\t\t\t}" +

                    "\n\t\t\t}" +

                "\n\t\t}" +

            "\n\t}" +

            "\n" +

            "\n\t//Display the dialog box." +

            "\n\tif(myDialog.show() == true){" +

                "\n\t\tvar userUnit, capHeight, measurementUnit" +

                "\n\t\t//If the user didn't click the Cancel button," +

                "\n\t\t//then get the values back from the dialog box." +

                "\n" +

                "\n\t\t//Get the point size from the point size field." +

                "\n\t\tcapHeight = capHeightField.editValue;" +

                "\n" +           

                "\n\t\t//Get the measurement unit from the radiobutton group." +

                "\n\t\tif(buttonGroup.selectedButton == 0){" +

                    "\n\t\t\tuserUnit = 1;" +

                    "\n\t\t\tmeasurementUnit = MeasurementUnits.POINTS;" +

                "\n\t\t}" +

                "\n\t\telse if(buttonGroup.selectedButton == 1){" +

                    "\n\t\t\tuserUnit = 0.35278;" +

                    "\n\t\t\tmeasurementUnit = MeasurementUnits.MILLIMETERS;" +

                "\n\t\t}" +

                "\n\t\telse{" +

                    "\n\t\t\tuserUnit = 0.0139;" +

                    "\n\t\t\tmeasurementUnit = MeasurementUnits.INCHES;" +

                "\n\t\t}" +

                "\n\t\tmyDialog.destroy();" +

                "\n\t\tchangeCapHeight(selectionLenght, userUnit, capHeight, measurementUnit, capHeightProportion);" +

                "\n\t\t}" +

                "\n\t\telse{" +

                "\n\t\tmyDialog.destroy();" +

                "\n\t\t}" +

            "\n\t}" +

        "\n" +

        "\nfunction changeCapHeight(selectionLenght, userUnit, capHeight, measurementUnit, capHeightProportion) {" +

            "\n\tfor (i = 0; i < selectionLenght; i++) {" +

                "\n\t\tvar myCharacters = app.selection.characters.everyItem();" +

                "\n\t\tmyCharacters.pointSize = (capHeight / userUnit) / capHeightProportion" +

            "\n\t}" +

            "\n\tmyDoc.viewPreferences.horizontalMeasurementUnits = measurementUnit;" +

            "\n\tmyDoc.viewPreferences.verticalMeasurementUnits = measurementUnit;" +

            "\n\tmyDoc.select(NothingEnum.NOTHING);" +

        "\n}");

        writeTest.close();

    }

    catch (err) {

        alert ("Ops");

    }

}