It’s pronounced ‘cutie’, bee tee doubleyou
Context
Since my last post on doing video work in Blender, which posited a system for generating text objects (some time ago) I’ve made a few more highlight videos. For example:
They’re a bit different from the Barotrauma video linked in the post above, and use text mostly as subtitles. But they definitely have another thing in common: the amount of time that they take to make!
Setting the colour, position, size and duration of text clips — as well as typing the text itself! — is tedious work. It’s slow too as different properties are in different places in the Blender text sequence properties in the UI:
Looking at the keybindings page of the Blender preferences doesn’t seem to show any hotkeys for quickly setting any of the common text properties we are interested in.
What Do We Want to Achieve?
Quicker text editing! The common things I do are: editing text, setting position (for multi-line captions), colour (to indicate speaker), text size, and adjusting duration. The last is usually done to a near frame-exact point but sometimes having something to the nearest 5/15 frames is good enough.
Of these, the last three are easiest to do ‘quickly’ (there’s no real shortcut to transcribing audio as I found out) in an automatic way. Helpfully, the properties are accessible via the API:
- position:
location
(array of 2 floats, (x,y)) - colour:
color
(an array of 4 floats, RGBA) - size:
font_size
(0-2000) - duration:
frame_final_duration
Code
At this early stage this is a demonstration of concept- that we can use the Blender API to achieve the manipulations we want. The following defines and registers four Operators (reference) for the manipulations listed above. Note that this does a random effect- we’ll get to doing specifics later!
"""quicker-text-editing.py -- text addon for Blender VSE""" bl_info = { "name": "Quicker Text Editing for VSE", "author": "bertieb", "version": (0, 1), "blender": (3, 3, 0), "location": "Video Sequence Editor > Text Strip", "description": "Quicker editing of text strips: position, colour, size, duration", "warning": "", "doc_url": "", "category": "Sequencer", } from enum import Enum import bpy import random class Colours(Enum): """some predefined colours - array of 4 floats (RGBA)""" GREEN = [0.03529411926865578, 0.6117647290229797, 0.03921568766236305, 1.0] PURPLE = [0.43800756335258484, 0.0, 0.6117647290229797, 1.0] BLUE = [0.12156863510608673, 0.41568630933761597, 0.6117647290229797, 1.0] class Locations(Enum): """predefined locations - array of 2 floats (x,y)""" ONE = [0.5, 0.1] TWO = [0.5, 0.22] THREE = [0.5, 0.34] FOUR = [0.5, 0.45] class TextSequenceAction(bpy.types.Operator): """Implements operations for quickly manipulating text sequences in VSE""" bl_idname = "sequencer.textsequenceaction" bl_label = "Text Sequence Action" def execute(self, context): return {"FINISHED"} @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) class SetTextColour(TextSequenceAction): """Set colour of text sequence[s]""" bl_idname = "sequencer.settextcolor" bl_label = "Set Text Colour" def execute(self, context): for strip in bpy.context.selected_editable_sequences: if strip.type == "TEXT": strip.color = random.choice(list(Colours)).value return {'FINISHED'} class SetTextLocation(TextSequenceAction): """Set location of text sequence[s]""" bl_idname = "sequencer.settextlocation" bl_label = "Set Text Location" def execute(self, context): for strip in bpy.context.selected_editable_sequences: if strip.type == "TEXT": strip.location = random.choice(list(Locations)).value return {'FINISHED'} class SetTextDuration(TextSequenceAction): """Set location of text sequence[s]""" bl_idname = "sequencer.settextduration" bl_label = "Set Text Duration" def execute(self, context): for strip in bpy.context.selected_editable_sequences: if strip.type == "TEXT": strip.frame_final_duration += random.randint(-10, 10) return {'FINISHED'} class SetTextSize(TextSequenceAction): """Set size of text sequence[s]""" bl_idname = "sequencer.settextsize" bl_label = "Set Text Size" def execute(self, context): for strip in bpy.context.selected_editable_sequences: if strip.type == "TEXT": strip.font_size += random.choice([-15, -10, -5, 5, 10, 15]) return {'FINISHED'} REGISTER_CLASSES = [SetTextColour, SetTextLocation, SetTextDuration, SetTextSize] def register(): for classname in REGISTER_CLASSES: bpy.utils.register_class(classname) def unregister(): for classname in REGISTER_CLASSES: bpy.utils.unregister_class(classname) if __name__ == "__main__": register()
Even though it’s just a simple test of the concept we still put in a couple of safeguards- the poll()
method checks we’re in the right context (we have a scene, we’re in the video sequence editor, we have a sequence selected); and we check the strip type is ‘TEXT’ before trying any operation.
Demo
Does it work? (You might ask, “Will it blend..?”)
Next Steps
The immediate next step is to figure out how best to call the operators with specifics- eg change the colour to red, set the position to #2 (0.5, 0.22), set the size to 125, change the duration by +15 frames. We also need to find out if there’s a way to quickly, easily call that (ie, can we set a hotkey / key combo / key sequence?).
Update: I’ve asked a question on blenderartists on how best to do that
After that, we can then add the ability to let the user define their presets!
Pingback: Quicker Text Editing in Blender (Part 2) – Rob's Blog
Pingback: Quicker Text Editing in Blender (Part 7): QTE Beta Release – Rob's Blog