Is there a way to determine the size of a text sequence?

Hello all. I am in the process of implementing ‘text appears a word at a time’ functionality for VSE. A crude example:

To achieve this my plan is to take a regular text sequence that contains a sentence of words to split, and then split that into separate sequences for individual words. Those sequences can then be offset in time with relative ease using frame_start.

However, for relative positioning it would be helpful to know the actual dimensions of a word. Judging from how it appears in the VSE, a text effect sequence by default is the size of the output. I have had a look at the API and there doesn’t appear to be anything obvious- is there an internal method for doing so? I did try searching, but most results relating to text width are for the 3d context (example).

Q: is there any way to determine the actual size (width/height) of text in VSE?

This is technically possible, but the process is a bit convoluted- you can use the blf module (which is normally used for rendering text) to calculate the dimensions of a string. Here’s a minimal example that should give you some ideas- you will obviously need to take the sequence’s transform into consideration, render resolution, things like that.

# the first three font indices are built-in blender fonts, so if you have a single custom font 
# loaded the font_id to use here is 3. you basically just want to loop through bpy.data.fonts until
# you find seq.font, then add 3 to whatever index you found it at.
font_id = 3
blf.size(font_id, seq.font_size, 72)
width, height = blf.dimensions(font_id, text)
print(f"Text strip dimensions: {width} x {height}")

I’m not sure how accurate it is, so you might need to do a bit of experimenting, but I did a quick test where I loaded a super condensed font, and then a bold/book font and saw a notable difference in the width output. I didn’t actually take any screenshots and measure the pixels to compare- so ymmv. Anyway VSE is not my area of expertise, but I wanted to give you an idea of some things to try, since there weren’t any replies to your question yet.

1 Like

Marvellous! Thank you for that and the example :slight_smile: I will test it out and see how it works for my purposes.

In a word: confusingly !


I was getting odd results using ‘bpy.data.fonts + offset of 3’, so I wrote an operator to walk sequences and fontids, since there doesn’t seem to be a way of enumerating the latter:

class SEQUENCER_OT_debug_font_sizing(bpy.types.Operator):
    """Print font sizing info"""
    bl_label = "Show font sizing info"
    bl_idname = "sequencer.debug_font_sizing"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        """Ensure we're in the VSE with at least one sequence selected"""
        return (context.scene and context.scene.sequence_editor
                and context.selected_editable_sequences is not None)

    def execute(self, context):
        """Loop through sequences, printing info about font and text"""

        import blf
        OUTFILE = "/tmp/blender_font_infos.txt"

        render_rez_x = bpy.data.scenes["Scene"].render.resolution_x

        with open(OUTFILE, "w", encoding="UTF-8") as fh:
            # bpy.data.fonts
            fh.write(f"There are {len(bpy.data.fonts)} fonts in bpy.data.fonts:\n")
            for bpyfont in bpy.data.fonts:
                fh.write(f"\t{bpyfont}\n")
            fh.write("*"*72 + "\n\n\n")

            # sequences
            fh.write(f"There are {len(context.selected_editable_sequences)} sequences\n\n")

            for seq in context.selected_editable_sequences:
                closest_diff = render_rez_x
                closest_width = 0
                closest_id = 0
                fh.write(f"With sequence '{seq.name}':\n")
                fh.write(f"\tSequence text: '{seq.text}\'\n")
                fh.write(f"\tSequence font: '{seq.font}'\n")
                fh.write(f"\tSequence size: '{seq.font_size}'\n")

                for fid in range(0, 50):
                    blf.size(fid, seq.font_size)
                    w, h = blf.dimensions(fid, seq.text)
                    if w == 0 and h == 0:
                        continue
                    fh.write(f"\t\tfid: {fid}\tw: {w}\th: {h}\n")
                    difference = abs(render_rez_x - w)
                    if difference < closest_diff:
                        closest_diff = difference
                        closest_width = w
                        closest_id = fid

                fh.write(f"\nClosest candidate:fid={closest_id} at {closest_width} px.\n")
                fh.write(f"Font id - 25 ({closest_id - 25}) to bpy.data.fonts: {bpy.data.fonts[closest_id-25].name}\n")
                fh.write("-"*72 + "\n\n")

        return {'FINISHED'}

I set up three sequences with different fonts & texts, and then sized them all to be as close to the full width of output as I could:

The output from walking the sequences and fontids is attached:

blender_font_infos.txt (3.9 KB)

There seem to be 28 fonts loaded, and the ones for the test strips start in the mid 20s. Edit: a new VSE file with one text strip added and a custom font selected has 26 fontids (0…25) that give a size, with fontid = 25 seemingly being the custom font.

Q: is there a way to get the font (name) from a fontid ? I looked at the documentation for blf, but there doesn’t seem to be much that gives. Alternatively: is there a way to get a fontid from a VectorFont ?

With some further testing I have found that the offset between fontid (as used by blf) is not necessarily consistent even within the same blend file. My educated guess is that it depends on what order fonts are used, if other fonts have been loaded in the interim.

Since this is getting further into the API, I have asked about matching up the fontids with fonts over at devtalk, for anyone wanting to follow the discussion there:

Just to round this off for anyone else who like me is looking for a way to get the size of a text sequence, the workaround I posted on devtalk:

This feels like an ugly workaround, as it relies on Blender caching / reusing fontids for the same font file; but it works.

The basic approach is:

  1. get filepath property from TextSequence.font (ref)
  2. resolve that to the absolute path via Python’s path.normpath() - just using Blender’s path.abspath() gives an ‘absolute path relative (??!) to the blend’; if you don’t and use the ‘absolute relative’ path you get a new fontid, which should still work for getting the size, but it feels better to have obvious side effects
  3. use that path with blf.load() to get the fontid
  4. set size with blf.size() and theTextSequence.font_size property
  5. finally, get size via blf.dimensions() and the TextSequence.text property

For actual code, you can look at the get_strip_text_size() function in my addon.