Simulated hand-writing in Adobe® InDesign™

Submitted by Jim Zaun on Fri, 06/11/2021 - 06:51

How can hand-writing fonts be rendered to look truly hand written?

Adobe Creative Cloud subscription
Adobe InDesign installed
Working knowledge of JavaScript
Knowledge of Adobe InDesign workflows



While I was at the Western Institute in Computer Science (WICS) headed by Dr. William McKeeman and Dr. Sharon Sickel in 1979, Donald Knuth presented his TEX typesetting system. Knuth was unhappy with the way his 2nd volume of the Art of Computer Programming series was typeset with the typesetting software Addison-Wesley was using at the time. (His 1st volume was hand typeset.) So, Knuth did an in-depth study of typesetting through the ages with an emphasis on beautifully typeset mathematics going all the way back to Medieval times. From that, he came up with the weighted reward-penalty system that forms the basis of the TEX typesetting system. Following those lectures, I set about learning the ins and outs of the TEX system.

During his lectures on TEX, he demonstrated a way of simulating the way Medieval woodblock and movable type was typeset in which no two glyphs for a given letter were exactly the same since each block was painstakingly carved by hand. Knuth simulated this in TEX by slightly randomizing various glyph properties such that no two glyphs of the same letter were perfectly duplicated. And, that demo never left me.

Much later on, I decided to write a non-mathematical holiday letter with graphics that looked truly Medieval or hand-written. And, with Knuth's demo in the back of my head, I discovered that Adobe® InDesign™ could vary font glyphs in the same manner that TEX could. I chose InDesign over TEX because it integrated nicely with other Adobe tools, had access to Adobe's massive library of typefaces, could perform mail address merges and was optimized for Internet printing (such as PDFs and eBooks).

The randomize text script

I created two scripts for InDesign™. The first script randomizes the glyphs of the selected text and the second script undoes the first. This do/undo approach allows you play around with the first script's randomization parameters on the same text until you get just the effect you want. The scripts are quite short. Here's the first script.

var len = app.selection[0].length;
for (var i=0; i<len; i++) {
  var charObj = app.selection[0].characters[i];
  charObj.baselineShift = Math.random() - 0.5;
  charObj.characterRotation = 4.0*Math.random() - 2.0;
  charObj.horizontalScale = 100.0 + (30.0*Math.random() - 15.0);
  var cv = charObj.fillColor.colorValue; // [C,M,Y,K]
  tint = 40 + Math.round(60.0*Math.random());
  charObj.fillTint = tint;

The first line obtains the length in characters of the text selected. Then the script iterates over each character in the selected text obtaining a reference to the character object to be modified. Then several randomized character object operations are performed including a vertical shift, a rotation change, a horizontal scale change and a tint change. The constants shown in the script are the parameters you can tune to increase or decrease the magnitude of the randomization. The randomization parameters shown are rather modest (with the exception of tint).

Tint vs. color changes

Even though the color property in the script is obtained, it is not changed. Instead, just the tint is changed. The tint property just makes the same color a bit lighter or darker. Whereas, the color property changes to a different color. I wanted to simulate variations in inking where less ink yields a lighter tint of the same color. Therefore, the tint randomization is set to only lighten, never darken the glyph color. This also happens in handwriting when the pen isn't inking perfectly. Due to the higher contrast and gamma of my color laser printer, aggressive tint randomizations were needed to see any tint variation in the printed output at all. Therefore, the tint variations may look too extreme when viewed on a computer monitor. If you would rather change the glyph color rather than just the tint, just apply your modifications to the cv value and then save back the fill color property. There are 4 sub-values: C, M, Y and K for color property.

The unrandomize text script

The undo script is even shorter.

var len = app.selection[0].length;
for (var i=0; i<len; i++) {
  var charObj = app.selection[0].characters[i];
  charObj.baselineShift = 0.0;
  charObj.characterRotation = 0.0;
  charObj.horizontalScale = 100.0
  charObj.fillTint = 100;

This script just forces all the modified character object properties back to their default values. Thus, all the glyphs in the selected region are re-rendered without modification. Because both scripts modify absolute character object properties, they can both be run multiple times over the same text selection without causing issues.


Copy-paste the code above into your favorite text editor and save/name as indicated above into any writable user folder. I created a folder in my Documents folder called Adobe/Adobe_Scripts/InDesign for this purpose. On MacOS, the script files must be copied to the local Library folder in order for InDesign™ to find them. However, Apple® has flagged that local Library folder with an access denied property which prevents the Finder application from entering it (unless you unlock using your administrator privileges). To get around that, open the Terminal application and cd to ~/Library/Preferences then find out which version of InDesign™ is installed. If there is more than one, pick the highest version. At the time of this writing, the latest was Version 16.0. Cd into that folder and then cd to the Scripts Panel folder as shown in this Terminal window. (Note: the username and hostname will be specific to your environment.)

Terminal window
username@hostname ~ % cd ~/Library/Preferences
username@hostname Preferences % ls Adobe\ InDesign/
Version 16.0
username@hostname Preferences % cd Adobe\ InDesign/Version\ 16.0/
username@hostname Version 16.0 % cd en_US/Scripts/Scripts\ Panel/
username@hostname Scripts Panel %

Once in the Scripts Panel folder, copy the scripts into this folder as shown here:

Terminal window
username@hostname Scripts Panel % cp ~/Documents/Adobe/Adobe_Scripts/InDesign/*.jsx .
username@hostname Scripts Panel % ls -l
-rw-rw-r--@ 1 username  groupname  411 Mon DD HH:MM randomizeText.jsx
-rw-rw-r--@ 1 username  groupname  242 Mon DD HH:MM unrandomizeText.jsx
username@hostname Scripts Panel %

When a newer version of InDesign™ comes out, you may have to do these steps again although the Adobe® Creative Cloud™ installer should auto-migrate these scripts to the newer version. That is why I keep the original scripts in my Documents folder tree. These scripts should work with any version of InDesign™ from CS 6 onward. (Note: In the ls printout above, the date/time, username and groupname will be specific to your environment.)

Running the scripts

Now launch InDesign™ and create a project. In the main menu bar, select Window ► Utilities ► Scripts as shown in this screen shot.

InDesign Windows -> Utilities -> Scripts menu

The Scripts dialog will appear and if you expand the User scripts section, your installed scripts should appear as shown in this screen shot.

InDesign Scripts Dialog randomizeText

Create a text block and enter some characters such as two strings of the same character. I used the Bradley Hand font for this example. Then select the second string of characters and double-click on the randomizeText.jsx script to randomize the selected string, as shown in this screen shot.

InDesign Scripts applying randomizeText.jsx

Unselect the second line of text to see how the normal and randomized text strings compare as shown in this screen shot.

InDesign compare normal and randomized text

You have now created a document that looks truly handwritten where no two glyphs of the same character are exactly the same. You can undo the effect by selecting the text again, then double-click on the unrandomizeText.jsx script. As mentioned before, the tint variations are much less pronounced when printed.