Skip to main content
Participant
January 4, 2024
Answered

Script for randomized selecting of stylistic set with each letter

  • January 4, 2024
  • 1 reply
  • 309 views

Dear community,

 

I am looking for a InDesign script to randomly select a stylstic set for each letter. Can anyone help?

 

Best, Finn

This topic has been closed for replies.
Correct answer m1b

Hi Finn, Here's my attempt. The script sets each selected character to a random stylistic set number, which you must specify in the script. Let me know how it goes and post a screen shot if the result looks cool!

- Mark

 

 

/**
 * Apply a random OpenType Stylistic Set to each selected character.
 * Usage: first determine which stylistic set numbers you want
 * the script to randomly choose from, eg [2,4,5] means script
 * will assign set 2 or 4 or 5 to each character. Set the value
 * of `stylisticSetNumbers` below.
 * @7111211 m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/script-for-randomized-selecting-of-stylistic-set-with-each-letter/m-p/14334161
 */
function main() {

    // you must edit these to suit your font
    var stylisticSetNumbers = [1, 2, 3];


    if (0 === app.documents.length)
        return alert('Please select some text and try again.');

    var things = app.activeDocument.selection;

    for (var i = 0, characters; i < things.length; i++) {

        if (!things[i].hasOwnProperty('characters'))
            continue;

        characters = things[i].characters.everyItem().getElements();

        for (var j = 0, r; j < characters.length; j++) {

            // random index
            r = Math.ceil(Math.random() * stylisticSetNumbers.length);

            // set the stylistic set
            setStylisticSets(characters[j], r);

        }

    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Randomize Stylistic Set');

/**
 * Set active Opentype stylistic sets.
 * @7111211 m1b
 * @version 2022-12-24
 * @9397041 {TextFrame|TextRange} text - the text.
 * @9397041 {Array<Number>} stylisticSetIndices - indices of the stylistic sets to activate.
 */
function setStylisticSets(text, stylisticSetIndices) {

    if (
        'Array' === text.constructor.name
        && text.length > 0
    )
        text = text[0];

    if (text.hasOwnProperty('textRange'))
        text = text.textRange;

    else if (text.hasOwnProperty('texts'))
        text = text.texts[0];

    if ('Array' !== stylisticSetIndices.constructor.name)
        stylisticSetIndices = [stylisticSetIndices];

    if (-1 === app.name.search(/indesign/i))
        // convert to zero-based indexing
        for (var i = 0; i < stylisticSetIndices.length; i++)
            stylisticSetIndices[i]--;

    if (text.hasOwnProperty('characterAttributes'))
        text.characterAttributes.stylisticSets = getBinaryCodedDecimalForArray(stylisticSetIndices);

    else if (text.hasOwnProperty('otfStylisticSets'))
        text.otfStylisticSets = getBinaryCodedDecimalForArray(stylisticSetIndices);

    else
        return alert('Please select some text and try again.');

};

/**
 * Returns a binary coded decimal number (BCD) representing binary bits.
 * Examples:
 * In Indesign and Illustrator, characterAttributes.stylisticSets are stored as a BCD.
 * stylistic sets 1 and 5: indices [0,4] returns 17 (10001 in binary).
 * stylistic sets 3, 4 and 5: indices [2,3,4] returns 28 (11100 in binary).
 * @9397041 {Array<Number>} numbers - the stylistic sets indices, eg. [2,4,5].
 * @Returns {Number} - the decimal number representing the numbers.
 */
function getBinaryCodedDecimalForArray(numbers) {

    var arr = numbers.slice().sort(),
        bin = [],
        len = arr[arr.length - 1],
        i = len + 1,
        val = arr.pop();

    while (i--) {
        if (val == i) {
            bin[len - i] = 1;
            val = arr.pop();
        }

        else {
            bin[len - i] = 0;
        }

    }

    // join into binary number and parse binary as decimal
    return parseInt(bin.join(''), 2);

};

 

 

1 reply

m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
January 4, 2024

Hi Finn, Here's my attempt. The script sets each selected character to a random stylistic set number, which you must specify in the script. Let me know how it goes and post a screen shot if the result looks cool!

- Mark

 

 

/**
 * Apply a random OpenType Stylistic Set to each selected character.
 * Usage: first determine which stylistic set numbers you want
 * the script to randomly choose from, eg [2,4,5] means script
 * will assign set 2 or 4 or 5 to each character. Set the value
 * of `stylisticSetNumbers` below.
 * @7111211 m1b
 * @discussion https://community.adobe.com/t5/indesign-discussions/script-for-randomized-selecting-of-stylistic-set-with-each-letter/m-p/14334161
 */
function main() {

    // you must edit these to suit your font
    var stylisticSetNumbers = [1, 2, 3];


    if (0 === app.documents.length)
        return alert('Please select some text and try again.');

    var things = app.activeDocument.selection;

    for (var i = 0, characters; i < things.length; i++) {

        if (!things[i].hasOwnProperty('characters'))
            continue;

        characters = things[i].characters.everyItem().getElements();

        for (var j = 0, r; j < characters.length; j++) {

            // random index
            r = Math.ceil(Math.random() * stylisticSetNumbers.length);

            // set the stylistic set
            setStylisticSets(characters[j], r);

        }

    }

};
app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Randomize Stylistic Set');

/**
 * Set active Opentype stylistic sets.
 * @7111211 m1b
 * @version 2022-12-24
 * @9397041 {TextFrame|TextRange} text - the text.
 * @9397041 {Array<Number>} stylisticSetIndices - indices of the stylistic sets to activate.
 */
function setStylisticSets(text, stylisticSetIndices) {

    if (
        'Array' === text.constructor.name
        && text.length > 0
    )
        text = text[0];

    if (text.hasOwnProperty('textRange'))
        text = text.textRange;

    else if (text.hasOwnProperty('texts'))
        text = text.texts[0];

    if ('Array' !== stylisticSetIndices.constructor.name)
        stylisticSetIndices = [stylisticSetIndices];

    if (-1 === app.name.search(/indesign/i))
        // convert to zero-based indexing
        for (var i = 0; i < stylisticSetIndices.length; i++)
            stylisticSetIndices[i]--;

    if (text.hasOwnProperty('characterAttributes'))
        text.characterAttributes.stylisticSets = getBinaryCodedDecimalForArray(stylisticSetIndices);

    else if (text.hasOwnProperty('otfStylisticSets'))
        text.otfStylisticSets = getBinaryCodedDecimalForArray(stylisticSetIndices);

    else
        return alert('Please select some text and try again.');

};

/**
 * Returns a binary coded decimal number (BCD) representing binary bits.
 * Examples:
 * In Indesign and Illustrator, characterAttributes.stylisticSets are stored as a BCD.
 * stylistic sets 1 and 5: indices [0,4] returns 17 (10001 in binary).
 * stylistic sets 3, 4 and 5: indices [2,3,4] returns 28 (11100 in binary).
 * @9397041 {Array<Number>} numbers - the stylistic sets indices, eg. [2,4,5].
 * @Returns {Number} - the decimal number representing the numbers.
 */
function getBinaryCodedDecimalForArray(numbers) {

    var arr = numbers.slice().sort(),
        bin = [],
        len = arr[arr.length - 1],
        i = len + 1,
        val = arr.pop();

    while (i--) {
        if (val == i) {
            bin[len - i] = 1;
            val = arr.pop();
        }

        else {
            bin[len - i] = 0;
        }

    }

    // join into binary number and parse binary as decimal
    return parseInt(bin.join(''), 2);

};

 

 

Participant
January 4, 2024

Working great! Thank you so much!