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

Advanced text expression needed for motion design

New Here ,
Aug 29, 2024 Aug 29, 2024

Copy link to clipboard

Copied

The following task in Adobe After Effects:

A text of unknown length is read into a text layer with an integrated text frame and should not exceed the maximum width of e.g. 1000 px (this value is read from a shape layer).

As the text in the text layer with text frame is already wrapped, the question is how to technically implement the text to be reduced in size in order to stay within the intended maximum dimension of the shape layer.

The text should be reduced as required using the font size in increments of 50px and should not exceed the length of 3 lines of text. If the text is cut off at the end, that would be bearable.

In addition, the text should be a maximum of 300 px and not smaller than 100 px.

I know how to script to scale text and make it the size of the shape layer, using the font size or scaling the text layer, but that does not completely solve the task presented here.

Behind the text there is a shape layer as a support surface, which has already been solved using an expression.

Is it even possible to use an expression to create text of unknown length at the end with breaks, taking the desired maximum width into account?

 

I've already tried using a second text layer to trigger the size and started trying without an integrated text frame, or just thinking about reading the number of letters in the text, but I still can't find a solution. Does anyone have any ideas about how to solve this?

This could be very useful for a lot of cases i think.


I have attached images that may make this easier to understand. The intended safe zone, which should not be exceeded in width, is included in the screenshots.

 

1.png2.png3.png

TOPICS
Scripting

Views

89

Translate

Translate

Report

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
LEGEND ,
Aug 29, 2024 Aug 29, 2024

Copy link to clipboard

Copied

You would probably involve some string.replace() somewhere with a suitable regex inside the parenthesis to filter the characters, determine the word count and word boundaries or whatever. Similar could be done with an expression text animator set to per word mode. Apparently this could go as far as running everything in a complex loop and determining the sourceRectAtTime() on some dummy layers to figure out the actual dimensions of the rendered text. There is per se no elegant way of doing it, though, since you're basically trying to re-create the auto-scale paragraph text found in classic page layout programs, but don't have access to all the necessary parameters for the calculations due to AE's fixed evaluation and rendering order. That's why you have to construct nested loops and do it recursively, i.e. figure out the displayed text lengths first with a generous margin on the dummy layers, then in a second loop scale them down to fit within your criteria on the output layer where you re-assemble the individual lines.

 

Mylenium

Votes

Translate

Translate

Report

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
New Here ,
Aug 29, 2024 Aug 29, 2024

Copy link to clipboard

Copied

yep, it is from design perspective an easy task to make text fit as shown in the layouts., but getting it down via expressions to automate the layout is a hard task. and yes i think dummy layers and letter an/or word count is needed to find a solution just a you mentioned. 

ChatGPT get's to it's limits to if i try to find a way to code a solution ... : )

Votes

Translate

Translate

Report

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
New Here ,
Sep 06, 2024 Sep 06, 2024

Copy link to clipboard

Copied

LATEST

I came up with a solution which seems to work, but still need some optimization.

I have a "Source" textlayer which gives the textinput.
I have a dummy textlayer with the same text in 100px
and dummy textlayer with the same text in 300px.
The textlayer "Final" ist giving the final text output.

This is the code so far:

var sourceText = thisComp.layer("Source").text.sourceText; var maxLines = 3; var maxWidth = 1000; // Max. Breite in Pixel var minFontSize = 100; var maxFontSize = 300; var leadingFactor = 0.9; // Zeilenabstandsfaktor // Funktion zur Berechnung der durchschnittlichen Buchstabenbreite function calculateAverageCharWidth(fontSize) { var tempLayer = fontSize > 200 ? thisComp.layer("Source 300") : thisComp.layer("Source 100"); var text = tempLayer.text.sourceText; var textWidth = tempLayer.sourceRectAtTime(time, false).width; return textWidth / text.length; // Durchschnittliche Breite eines Buchstabens } // Berechne die durchschnittliche Buchstabenbreite bei 100px und 300px var avgCharWidth100 = calculateAverageCharWidth(100); var avgCharWidth300 = calculateAverageCharWidth(300); // Schätzung der durchschnittlichen Buchstabenbreite in Abhängigkeit der Schriftgröße function estimateTextWidth(text, fontSize) { var avgCharWidth = avgCharWidth100 + ((avgCharWidth300 - avgCharWidth100) * ((fontSize - 100) / (300 - 100))); return text.length * avgCharWidth; // Geschätzte Textbreite } // Schriftgrößenanpassung basierend auf der Breite var fontSize = maxFontSize; var fits = false; var lines = []; while (fontSize >= minFontSize && !fits) { // Text in Zeilen aufteilen var words = sourceText.split(" "); var currentLine = ""; var firstLine = ""; // Ästhetik-Logik: Schätzen, wo der beste Umbruch für die erste Zeile ist for (var i = 0; i < words.length; i++) { var testLine = firstLine + words[i] + " "; if (estimateTextWidth(testLine, fontSize) > maxWidth * 0.8) { break; // Abbruch, wenn die Zeile länger als 80% der Maximalbreite ist } firstLine = testLine; // Der mögliche erste Umbruchpunkt } lines.push(firstLine.trim()); // Der restliche Text wird in maximal 2 weitere Zeilen umgebrochen var remainingText = sourceText.replace(firstLine, "").trim(); var remainingWords = remainingText.split(" "); currentLine = ""; for (var i = 0; i < remainingWords.length; i++) { var testLine = currentLine + remainingWords[i] + " "; if (estimateTextWidth(testLine, fontSize) <= maxWidth || lines.length >= maxLines - 1) { currentLine = testLine; } else { lines.push(currentLine.trim()); currentLine = remainingWords[i] + " "; } } if (currentLine !== "") { lines.push(currentLine.trim()); } // Falls die Anzahl der Zeilen die Maximalanzahl überschreitet, schneide den Text ab if (lines.length > maxLines) { lines = lines.slice(0, maxLines); } // Prüfen, ob der Text innerhalb der maximalen Breite passt if (lines.every(line => estimateTextWidth(line, fontSize) <= maxWidth)) { fits = true; // Wenn alle Zeilen passen, ist die Schriftgröße optimal } else { fontSize--; // Schriftgröße verringern und erneut testen lines = []; // Zurücksetzen der Zeilen für den nächsten Versuch } } // Textstil erstellen und die berechnete Schriftgröße und den Zeilenabstand setzen var style = text.sourceText.createStyle() .setFontSize(fontSize) .setLeading(fontSize * leadingFactor) .setText(lines.join("\n")); // Finalen Textstil zurückgeben style;


Sorry for the lost line break because of copy / paste.

And this is the result:
Bildschirmfoto 2024-09-06 um 11.24.14.png


Votes

Translate

Translate

Report

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