Copy link to clipboard
Copied
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
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();
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 =
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.
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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?!?
Copy link to clipboard
Copied
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()
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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..
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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();
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
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;
}
}
Copy link to clipboard
Copied
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.
Copy link to clipboard
Copied
uuuh, very helpful! funny that we almost have the same code structure haha