Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
4

Performance problem with variable font script

Community Beginner ,
Jan 27, 2024 Jan 27, 2024

Hey there, I've been playing around with variable fonts and extend script and wrote a script that makes each character in a text block slowly go from sans to serif, I have attached the result as a screenshot. This works fine in theory but I have found that the processing time scales up exponentially. So 20 characters take 1,4 seconds to process while 120 characters already take 1 minute to process. My inital goal was to do this on whole pages or even on books and I understand that this is gonna take some time but it seems weird that its gonna increase drastically with more characters

 

This is my code so far: 

app.scriptPreferences.enableRedraw = false;
app.doScript(variable_transition, ScriptLanguage.javascript, undefined, UndoModes.FAST_ENTIRE_SCRIPT, "Script Action");
app.scriptPreferences.enableRedraw = true;

function variable_transition() {
    var doc = app.activeDocument;

    var text = doc.textFrames.item(0).characters;

    for (var x = 0; x < text.length; x++) {
        text.item(x).setNthDesignAxis(2, map_range(x, 0, text.length, 0, 1));
    }

    function map_range(value, low1, high1, low2, high2) {
        return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
    }
}

 

Any help on this would be greatly appreciated

TOPICS
Experiment , Scripting , Type
1.7K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 3 Correct answers

Community Expert , Jan 28, 2024 Jan 28, 2024

Converting collections to arrays almost always speeds up a script, especially if that arrey is used in a loop. Instead of

var text = doc.textFrames.item(0).characters;

use

var text = doc.textFrames.item(0).characters.everyItem().getElements();

 

Translate
Community Expert , Jan 28, 2024 Jan 28, 2024

Hi @Christoph5C7F , Not sure if this helps, but I think setting the axis values to an integer rather than a real number helps with speed. This takes around 6 secs for 900 characters:

 

app.scriptPreferences.enableRedraw = false;
app.doScript(characterBlend, ScriptLanguage.javascript, undefined, UndoModes.FAST_ENTIRE_SCRIPT, "Script Action");
app.scriptPreferences.enableRedraw = true;


function characterBlend(){
    app.selection[0].appliedFont = "Acumin Variable Concept	Regular"
    var txt = 
...
Translate
Community Expert , Jan 28, 2024 Jan 28, 2024

@rob day

 

Just found your older take on this problem:

 

https://community.adobe.com/t5/indesign-discussions/variable-font-progression/m-p/10960543#M177624

 

@Christoph5C7F, you should take a look at it - there are few extra bits.

 

Translate
Community Beginner ,
Jan 27, 2024 Jan 27, 2024

The more I look into it, the more it seems as if its mostly a problem on indesigns site (I'd love for someone to proof me wrong) as not only the creation of such texts takes more time but they also impact the performance of indesign, moving them around causes lag.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 27, 2024 Jan 27, 2024

I'm not JS guy but I'm pretty sure it should work much faster - if you calculate percentage once - and then use it - instead of constantly doing the whole math?

 

Also, I don't understand why JS coders ALWAYS declare new variable(s) instead of just working directly on the collection(s) available directly from the InDesign?!? 

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 27, 2024 Jan 27, 2024

yeah I also thought about something like what you said, calculating all the percentages first. this is my approach at it, is that what you meant?

    var text = doc.textFrames.item(0).characters;
    var percentages = [];

    for (var i = 0; i < text.length; i++) {
        percentages.push(map_range(i, 0, text.length, 0, 1));
        text.item(i).setNthDesignAxis(2, map_range(i, 0, text.length, 0, 1));
    }

    for (var j = 0; j < text.length; j++) {
        text.item(j).setNthDesignAxis(2, percentages[j]);
    }

for your question about me declaring new variables: is it bad to do that with extendscript or is it just a bad habit? maybe I'm understanding you wrong but wouldn't the alternative writing for setting the nth axis be something like this:

doc.textFrames.item(0).characters.item(i).setNthDesignAxis()

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 27, 2024 Jan 27, 2024

Offcourse theres a mistake in my answer, I obviously wouldn't set the design axes twice. however, this approach didn't improve the performance still

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 27, 2024 Jan 27, 2024

I think you should remove 2nd line in the 1st for - with map_range()? Because right now, you are populating "percentages" and then calling setNthDesignAxis - and then again caling setNthDesignAxis in the 2nd for?

You can edit your post even few hours later.

 

I wasn't talking about filling an array with percentage values - as you wouldn't save anything and even made your code slower - but calculating it once.

 

You are "mapping" number of characters to (0,1) - so if you have 10 chars - for each char % will be 0.1 - for 100 chars - % will be 0.01, right?

 

 

And my comment about declaring new variable - was for the "text" variable - I'm not sure how much slower it is in JavaScript - referring through variable to original object?

 

Visually it looks much nicer - you are skipping the whole "doc.textFrames.item(0).characters".

 

Of course, as I'm not JS guy - I might be wrong - and there is nothing wrong and it doesnt have any negative effect on the speed..

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 27, 2024 Jan 27, 2024

Hi @Christoph5C7F, this is my understanding:

 

1. You aren't really doing anything wrong in your code that I can see.

 

2. Every time you "set" a design axis value, you actually cause a new font to be generated, and in Indesign this can often be *very* slow. My guess is that this is what is causing your performance issue.

 

A partial solution, depending on your exact requirements, could be to limit the number of variable instances created—rather than creating one for each character, you could create N instances and spread those amongst the characters. My guess is that this would at least manage the performance issue, because you could specify as high a number of variable font instances created as your machine could handle in a reasonable time and it would have nothing to do with the selected text.

 

Another possible advantage to this approach is that Indesign *might* cache the instances, so that if the same axis values were used again, on another script execution on different text, it might be much faster the second time.

 

Of course this approach would mean that you wouldn't have a perfect gradient of values—if you made 10 font instances and had 20 characters, the axis would only increment every 2 characters, which may well be a deal breaker.

 

If it was me I would at least try that approach, and find an acceptable number of instances to create.

 

Another approach—and I'm not sure if this is feasible but it I think it should work—is to use a good font editor to generate N numbers of non-variable fonts from the variable font axis you are interested in, load them all (myInstanceFont001, myInstanceFont002, myInstanceFont003 ... myInstanceFont100) and use the script to apply that particular font. What this would do (maybe!) is to move the heavy performance required to a pre-process, and the final script would be as fast as setting each character in a different font. I realise that this experiment would be a significant undertaking (you would want to automate it via your font editor) but I'm just brainstorming.

- Mark

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 27, 2024 Jan 27, 2024

Oh wow, that was a very insightful answer. Luckily I'm only trying to solve an idea that came up in a talk I watched so I can just drop this for now. I didn't know that using .setNthDesignAxis() generated a new font each time. I have been looking for a good reason to pick up Glyphs as you can script in it so now I have a reason to do so.

 

Thanks again for your long and friendly answer, I learned a lot here.

-Christoph

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 27, 2024 Jan 27, 2024

One thing that might marginally improve performance is defining your for loop variables outside the for loop. Calling .length each time can slow things down.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 28, 2024 Jan 28, 2024

Converting collections to arrays almost always speeds up a script, especially if that arrey is used in a loop. Instead of

var text = doc.textFrames.item(0).characters;

use

var text = doc.textFrames.item(0).characters.everyItem().getElements();

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 28, 2024 Jan 28, 2024

Thank you SO MUCH! After all these answers I really thought that the problem was just in the nature of inDesign but that is the right solution. My script went from 20 minutes for around 300 characters to 30 seconds for 3000 characters. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 28, 2024 Jan 28, 2024

Hi @Christoph5C7F , Not sure if this helps, but I think setting the axis values to an integer rather than a real number helps with speed. This takes around 6 secs for 900 characters:

 

app.scriptPreferences.enableRedraw = false;
app.doScript(characterBlend, ScriptLanguage.javascript, undefined, UndoModes.FAST_ENTIRE_SCRIPT, "Script Action");
app.scriptPreferences.enableRedraw = true;


function characterBlend(){
    app.selection[0].appliedFont = "Acumin Variable Concept	Regular"
    var txt = app.selection[0].characters.everyItem().getElements();
    var t = txt[0];
    var myDesignAxesValues = t.appliedFont.designAxesValues;
    
    //the beginning and end of the 1st axis
    var a1s = 300;
    var a1e = 600;
    
    //the beginning and end of the 2nd axis
    var a2s = 50;
    var a2e = 100;

    var wstep = (a1e-a1s)/txt.length;
    var cstep = (a2e-a2s)/txt.length;

    for (s=0; s<txt.length; s++){
        myDesignAxesValues[0]=(Math.round(a1s+wstep*s));
        myDesignAxesValues[1]=(Math.round(a2s+cstep*s));
        txt[s].designAxes=myDesignAxesValues;
    } 
}

 

 

Screen Shot 5.png

 

Screen Shot 4.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jan 28, 2024 Jan 28, 2024

@rob day

 

Just found your older take on this problem:

 

https://community.adobe.com/t5/indesign-discussions/variable-font-progression/m-p/10960543#M177624

 

@Christoph5C7F, you should take a look at it - there are few extra bits.

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 28, 2024 Jan 28, 2024
LATEST

uuuh, very helpful! funny that we almost have the same code structure haha

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines