1 Reply Latest reply on Jul 7, 2013 7:11 PM by GusSoares

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

    Naveeth_J

      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[i];

          //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?

        • 1. Re: how to get font properties like line height, ascend, descend, ideographic top etc..?
          GusSoares

          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[i].postscriptName);
              progress.hit(app.fonts[i].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[i].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[i].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[i].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");
              }
          }