Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions Dynamic Text Positioning/Scaling

  • Dan Ebberts

    September 20, 2012 at 2:54 pm

    It’s a good, fast method that will work in a lot of cases. It works especially well with mono-spaced fonts, but it may be close enough even for proportionally spaced fonts. You can examine all the lines in a single expression. Here’s how you would scale down the text layer to stay within the width of max characters:


    txt = text.sourceText.split("r");
    max = 15;
    n = 0;
    for (i = 0; i < txt.length; i++) n = Math.max(n, txt[i].length);
    if (n > max)
    value*max/n
    else
    value

    Alternatively, you could scale up the width of a background layer to accomodate a text forground with a maximum line length greate than max:


    txt = thisComp.layer("text01").text.sourceText.split("r");
    max = 15;
    n = 0;
    for (i = 0; i < txt.length; i++) n = Math.max(n, txt[i].length);
    if (n > max)
    [value[0]*n/max,value[1]]
    else
    value

    Note that the forum will not print the necessary backslash character in split(“[backslash-goes-here]r”) but it needs to be there.

    Dan

  • Andy Kreutzberg

    September 27, 2012 at 11:57 am

    I have now managed to build a scaler based on this text which is pretty cool. It features an adjustable threshold because our font is not mono spaced, so you can still go in and adjust that threshold if something does not fit despite the auto scale.

    I have thought about a way to fix this. Would it not be possible to assign each letter a specific value representing it’s pixel size and then just adding up the values for each characters in a single line?

    I have played around and managed to achieve something like that. At first i scan the text for the number of occurences for each individual character of the alphabet plus free spaces and general length (the ladder of which will add the space between characters)


    l1 = (thisComp.layer(index+2).text.sourceText.split("A").length - 1);
    l2 = (thisComp.layer(index+2).text.sourceText.split("B").length - 1);
    l3 = (thisComp.layer(index+2).text.sourceText.split("C").length - 1);
    l4...
    l5...
    l27 = (thisComp.layer(index+2).text.sourceText.split("b").length - 1);
    l28 = thisComp.layer(index+2).text.sourceText.length

    After that, each letter gets a value assigned representing it’s pixel length


    s1=l1*95
    s2=l2*80
    s3=l3*75
    s4=l4*80
    s5=l5*74
    ...

    Then the values are being added:

    s1+s2+s3+s4+s5 ...+s28

    If i use the result for the pixel length of a box layer, it fits really closely. Now the only problem is, i can’t make this work for individual lines. It’s only possible to do for the entire text. I have tried to do it with the piece of code from the scaling expression posted by dan above but the apporach seems to be too different to fit into this.

    Is there a way to have this character counting plus translation into values done for each line individually (which would result in two individual length values if the text has two lines)?

  • Dan Ebberts

    September 27, 2012 at 5:32 pm

    This method is definitely more accurate than just multiplying the character count by an average character width. It’s tedious measuring all the characters to set up your tables though. I think you can tighten your code up a little. I’d set up an array with widths for the 128 ASCII codes, and loop through the text, character by character adding up the widths.

    Something like this:


    widths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    13.5,16.6,26.2,27.3,27.2,44.2,33.7,14.8,
    .
    . (the rest of the ASCII widths go here)
    .
    25.8,25.2,24.2,17.9,12.6,17.9,34.1, 0.0];

    txt = thisComp.layer(index+2).text.sourceText;
    w = 0;
    for (i = 0; i < txt.length; i++){ w += widths[txt.charCodeAt(i)]; } w now has the total width

    This can work very well, but you'll pick up some inaccuracies due to kerning (where for example, a capital V and a capital A next to each other will overlap "AV").

    I would use a large font size to build the array, then you can just scale everything by the actual font size. For example, if you measured the characters at font size 100, you'd have something like this:

    nomFontSize = 100;
    actualFontSize = 36;

    then at the end you would use:

    w*actualFontSize/nomFontSize

    If you need to check for multiple lines, you can just split the text on backslash+r and check the length:

    splitLines = txt.split("backslash+r")
    numLines = splitLines.length;
    if (numLines > 1){

    (do something)

    }

    I hope this helps.

    Dan

    Note: I made a few edits--DE

Page 2 of 2

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy