View Full Version : Subtext plugin and new line spacing
hello_hello
28th February 2025, 12:55
Is it expected behavior for the Subtext plugin to use less line spacing when a line doesn't contain text. The VapourSynth Text function and Avisynth's Subtitle function would both keep the first and last characters aligned in each example below.
Cheers.
styleA = "Arial,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,20,20,20,1"
styleB = "Arial,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,50,20,20,1"
styleC = "Arial,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,80,20,20,1"
V = core.std.BlankClip()
V = V.sub.Subtitle("A\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nA", style=styleA)
V = V.sub.Subtitle("B\n \n \n \n \n \n \n \n \n \n \n \nB", style=styleB)
V = V.sub.Subtitle("C\nx\n\n\n\n\n\n\n\n\n\nx\nC", style=styleC)
V.set_output()
https://i.ibb.co/vx4nX07X/Screenshot-2025-02-28-22-53-02.png
Myrsloik
28th February 2025, 18:31
Is it expected behavior for the Subtext plugin to use less line spacing when a line doesn't contain text. The VapourSynth Text function and Avisynth's Subtitle function would both keep the first and last characters aligned in each example below.
Cheers.
styleA = "Arial,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,20,20,20,1"
styleB = "Arial,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,50,20,20,1"
styleC = "Arial,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,80,20,20,1"
V = core.std.BlankClip()
V = V.sub.Subtitle("A\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nx\nA", style=styleA)
V = V.sub.Subtitle("B\n \n \n \n \n \n \n \n \n \n \n \nB", style=styleB)
V = V.sub.Subtitle("C\nx\n\n\n\n\n\n\n\n\n\nx\nC", style=styleC)
V.set_output()
https://i.ibb.co/vx4nX07X/Screenshot-2025-02-28-22-53-02.png
The answer is probably yes. Subtext is based on libass and as such matches the ancient quirks of vsfilter/directvobsub.
hello_hello
28th February 2025, 19:17
Thanks.
I've only just starting using Subtext, but at least now I know to add a space between successive new lines to keep the text vertically aligned.
The hex values for color being backwards compared to Avisynth and Vapoursynth had me scratching my head for a while too. :)
BGR instead of RGB
or
&H8CE6F0 instead of $F0E68C
for example.
_Al_
28th February 2025, 21:10
That might be avisynth way of doing things, but using python, there are tools that format text in many ways. I would not construct outputs using new lines etc. To print your example:
text = """
A B C
x x
x
x
x x
x C x
x
x
A B
"""
# must use font that has the same width for upper and lower case like "Consolas" or "Courier New"
style = "Courier New,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,80,20,20,1"
V = V.sub.Subtitle(text, style=style)
V.set_output()
to print variables into a grid where first characters are always the same distance apart (example 10 characters) using f strings.
Note that extra "f" before triple quotes. That means there could be variables inside of string enclosed in complex brackets:
a = "Hi"
b = "Bye"
c = "Hello"
text = f"""
{a:10}{b:10}{c:10}
"""
or just use a function that does everything for you, where you just provide a data (in a list form in our example)
ai google example:
def print_grid(data, column_widths=None):
"""Prints data in a grid format using f-strings.
Args:
data: A list of lists, where each inner list represents a row.
column_widths: An optional list of integers specifying the width of each column.
If None, it automatically determines the maximum width for each column.
"""
if not data:
return
if column_widths is None:
column_widths = [max(len(str(item)) for item in col) for col in zip(*data)]
for row in data:
formatted_row = " ".join(f"{str(item):<{column_widths[i]}}" for i, item in enumerate(row))
print(formatted_row)
# Example Usage
data = [
["Name", "Age", "City"],
["Alice", 30, "New York"],
["Bob", 25, "Los Angeles"],
["Charlie", 35, "Chicago"]
]
print("Default Grid:")
print_grid(data)
print("\nCustom Width Grid:")
print_grid(data, [10, 5, 15])
_Al_
28th February 2025, 21:43
To adjust that last general example to our use it could look like this:
def format_grid(data, column_widths=None):
if not data:
return
if column_widths is None:
column_widths = [max(len(str(item)) for item in col) for col in zip(*data)]
text = []
for row in data:
formatted_row = " ".join(f"{str(item):<{column_widths[i]}}" for i, item in enumerate(row))
text.append(formatted_row)
return "\n".join(text)
data = [
["Name", "Age", "City"],
["Alice", 30, "New York"],
["Bob", 25, "Los Angeles"],
["Charlie", 35, "Chicago"]
]
text = format_grid(data, [10, 10, 10])
style = "Courier New,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,80,20,20,1"
V = V.sub.Subtitle(text, style=style)
V.set_output()
Name Age City
Alice 30 New York
Bob 25 Los Angeles
Charlie 35 Chicago
hello_hello
1st March 2025, 01:07
Thanks _Al_.
I'll definitely try to get my head around that for future reference, but I have it working the way it worked previously using the Text or Subtitle functions now.
The main issue I was having is when some of the lines don't always contain text, for the text below to remain in the same position a blank line containing only "\n" could be added instead. With the Subtext function though, adding an extra "\n" results in all the lines of text below moving up a bit, but now I know to use " \n" instead.
Some lines of text are also added with a different instance of Subtext, either to specify a different color or to ensure they stay in the same position. For instance for text to always appear on line 4, whether lines 1 to 3 exist or not, it's easy add it as a separate subtitle and precede the text with "\n\n\n", or for Subtext, with " \n \n \n".
No doubt it's do-able using your method, and possibly easier if you know how. At the moment it's for my CropResize function though, as I decided to switch to using Subtext, so the text was already formatted and it's displaying correctly again.
Thanks for the info though.
_Al_
1st March 2025, 03:00
If your code is print line by line oriented (not column by column, not sure now, but that does not make sense anyway because you feed it data, which is either way):
If you need to include style for a line, you just introduce some styles dictionary and also call vapoursynth to construct lines separately, as you do now, but just giving it a structure:
def format_grid(data, column_widths=None):
if not data:
return
if column_widths is None:
column_widths = [max(len(str(item)) for item in col) for col in zip(*data)]
lines = []
for row in data:
formatted_row = " ".join(f"{str(item):<{column_widths[i]}}" for i, item in enumerate(row))
lines.append(formatted_row)
return lines
style_1 = "Courier New,20,&H0000FFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,80,20,20,1"
style_2 = "Courier New,20,&H00FFFFFF,&H00000000,&H00000000,&H00000000,1,0,0,0,100,100,0,0,0,2,0,7,80,20,20,1"
styles = { # defining a style for a line
0: style_1,
1: style_2,
2: style_2,
3: style_2
}
data = [
["Name", "Age", "City"],
["Alice", 16, "New York"],
[], # happens to be no data in this line
["Charlie", 35, "Chicago"]
]
lines = format_grid(data, [10, 6, 10])
V = core.std.BlankClip()
line_numbers = iter(range(0, len(data)))
PRINT_EMPTY_LINES = True
for i, style in styles.items():
if not lines[i] and not PRINT_EMPTY_LINES:
continue
line_number = next(line_numbers)
y_position = line_number*" \n"
V = V.sub.Subtitle(f" {y_position}{lines[i]}", style=style)
Preview(V)
V.set_output()
if wanting to print empty line when a provided line is empty then PRINT_EMPTY_LINES=True
I edited it, to include your "hack", printing \n with empty space so it does not overlap instead of multiplying those line ends,
but to multiply line ends a line spacing could be selected choosing different multiple integer:
INTEGER=2
.
.
.
y_position = line_number*"\n"*INTEGER
hello_hello
4th March 2025, 18:20
Thanks for the additional info. I had no idea you could multiply a string in Python, so I've replaced multiple new lines with (' \n' * Integer).
Other than that though, I think reformatting it all would be a lot of work to end up back where I started. Plus some lines are stationary while others aren't, so I think I'll leave it alone for the moment. This is what I was wanting to display with Subtext as it did for the VapourSynth Text function, only with the ability to adjust the text size according to the resolution as it's fixed for the Text function. Using ' \n' instead of 'n' solved the problem.
https://i.ibb.co/84TP6Rv7/A.jpg
https://i.ibb.co/svYDGcBv/B.jpg
https://i.ibb.co/S4nxzwMB/C.jpg
vBulletin® v3.8.11, Copyright ©2000-2025, vBulletin Solutions Inc.