Python: captionbob.effects
captionbob.effects.punch
Punch effect: bold white words and a heavy slanted keyword.
Each caption shows one or two words in one line of bold white letters, in the case and with the end marks of the speech, with a soft dark shadow that reaches a little further below the letters than above them. A caption ends at each end mark, such as a comma. The longest word of a caption is its keyword when it has enough letters. A keyword is written in heavy slanted capitals that are larger and wider than the other words. Its letters keep a top color over their upper part and go to a bottom color over their lower part. A dark outline in the color of the keyword goes around its letters, with a glow of that color below them. The keywords of a video take the keyword looks in turn. An end mark behind a keyword, such as a full stop, has the look of the other words.
A caption with a keyword sits lower than a plain caption, and it drifts on a diagonal: a short time after its start it moves in a straight line for the drift time, and then it stays. The middle of the drift is the place of the caption. The keyword captions take the drift turns in order, down and to the right or up and to the left. A space in front of a keyword gets the gap before a keyword, and a space behind it gets the gap after a keyword, so that the outline and the glow of the keyword keep a clear room from the other words. The slanted letters lean to the right at their top, so the space behind a keyword needs more room than the space in front.
A caption shows at once when its first word starts, and it goes when its last word ends, so the screen is empty in a pause between two captions.
A caption always stays in one line. The caption measure gives the width of each word in its font, and a caption that is wider than the room between the side margins gets smaller as a whole, with its borders, its blurs and its drops, so that it fits the room. The width of a caption is the width of its words and of the spaces between them: the words and the spaces of the plain font at the plain letter width, and each keyword at the keyword letter width, with its weight on each side and the keyword gaps at the spaces next to it. The measure gives the spaces from the caption in the plain font, so the slant of a keyword can make a caption a few pixels wider or narrower than its count.
A caption is events at one place, one layer above the other: the shadow of the plain words, the outline and the glow of the keyword, the text, and the strips of the gradient of the keyword. ASS has no gradient, so each strip is an event of the whole caption with a clip to the rows of the strip, and only the keyword shows in it. The clip of a strip moves with the drift. Each word and each space is a run of its own, with the same font tags in each event, so the events of a caption put each word at one place.
The keyword font name may be the full name of one face of a font, such as Ubuntu Bold Italic. libass and the caption measure both pick that face by the name, so the measure gives the widths of the slanted letters.
The effect draws nothing itself. It builds the text of an ASS script, and ffmpeg draws it on the video. The common part of the effects is in effect_common.py.
The defaults are the look of the source video of the effect, measured on its frames and scaled to a video of 1080x1920.
Source file: captionbob/effects/punch.py
Settings
The command line and the HTTP API call this effect the style punch. Its settings class is PunchSettings. Each setting has the default below.
| Setting | Type | Default | Description |
|---|---|---|---|
most_words |
integer | 2 |
The most words that one caption shows. |
fewest_words |
integer | 1 |
The fewest words that one caption shows, when its sentence is long enough for that. |
font_name |
string | "Ubuntu" |
Name of the font of the text. |
font_size |
integer | 89 |
Height of the font in pixels. |
bold |
boolean | true |
True for bold text. |
primary_color |
string | "#FFFFFF" |
Color of the text, as "#RRGGBB". |
stroke_color |
string | "#000000" |
Color of the outline of the text, as "#RRGGBB". |
stroke_width |
number | 0.0 |
Width of the outline in pixels. 0 gives no outline. |
bottom_position |
number | 0.6995 |
Where the bottom of the caption sits, as a part of the video height from the top. 0.75 is three quarters of the way down. |
side_margin |
integer | 54 |
Room in pixels that stays free on the left and on the right of the caption. A caption that is too wide for the room between the margins breaks into lines. |
letter_width |
number | 1.02 |
The width of the letters of the plain words as a part of the width that the font gives them, above 0. |
end_at_marks |
boolean | true |
True to end a caption also at each word that ends with an end mark, such as a comma. |
shadow_color |
string | "#000000" |
The color of the shadow of the plain words, as "#RRGGBB". |
shadow_spread |
number | 4.0 |
How far the shadow reaches past the outline, in pixels. |
shadow_blur |
number | 9.0 |
How far the edge of the shadow fades out, in pixels. |
shadow_opacity |
number | 0.85 |
The strength of the shadow, from 0 for no shadow to 1. |
shadow_drop |
number | 3.0 |
How far the shadow is below the letters, in pixels. A value below 0 puts the shadow above them. |
keyword_font_name |
string | "Ubuntu Bold Italic" |
Name of the font of a keyword. A full name, such as Ubuntu Bold Italic, picks one face of a font. |
keyword_bold |
boolean | true |
True for bold keyword letters. |
keyword_font_size |
integer | 105 |
Height of the font of a keyword in pixels, a whole number above 0. The row of a caption with a keyword is this high. |
keyword_letter_width |
number | 1.37 |
The width of the letters of a keyword as a part of the width that the font gives them, above 0. |
keyword_weight |
number | 6.0 |
How far the letters of a keyword grow on each side, in pixels, to make them heavier. 0 keeps the letters of the font. |
keyword_looks |
list | [{"top_color": "#700091", "bottom_color": "#520098", "outline_color": "#42076A"}, {"top_color": "#61DF08", "bottom_color": "#428805", "outline_color": "#3F7906"}, {"top_color": "#BF5606", "bottom_color": "#731B06", "outline_color": "#640B00"}] |
The looks of the keywords, each a top color, a bottom color and an outline color. The keywords of a video take them in turn. |
keyword_outline_width |
number | 7.0 |
How far the outline of a keyword reaches past its grown letters, in pixels. |
keyword_outline_blur |
number | 5.0 |
How far the edge of the outline and of the glow fades out, in pixels. |
keyword_glow_drop |
number | 14.0 |
How far the glow of a keyword is below its letters, in pixels. A value below 0 puts it above them. |
keyword_glow_opacity |
number | 0.5 |
The strength of the glow, from 0 for no glow to 1. |
gradient_top |
number | 0.48 |
Where the gradient of a keyword starts, as a part of its row below the top of the row. The letters above it have the top color. |
gradient_bottom |
number | 0.9 |
Where the gradient ends, as a part of its row below the top of the row, below the gradient top. The letters below it have the bottom color. |
strip_height |
integer | 3 |
The height in pixels of a strip of the gradient, 1 or above. A lower strip gives a smoother gradient and more events. |
keyword_gap_before |
number | 11.0 |
Room in pixels that is added to a space in front of a keyword. A value below 0 puts the words closer. |
keyword_gap_after |
number | 30.0 |
Room in pixels that is added to a space behind a keyword. A value below 0 puts the words closer. A space between two keywords gets both gaps. |
keyword_drop |
number | 32.5 |
How far the place of a caption with a keyword is below the bottom position, in pixels. A value below 0 puts it higher. |
drift |
number | 19.0 |
How far a caption with a keyword moves to the side and up or down, in pixels. 0 keeps it at its place. |
drift_delay_seconds |
number | 0.1 |
The time from the start of a caption with a keyword to the start of its drift. |
drift_seconds |
number | 0.53 |
The time of the drift. 0 shows the caption at the end of its drift from the delay on. |
drift_turns |
list | ["down right", "up left"] |
The directions of the drift, DRIFT_DOWN_RIGHT or DRIFT_UP_LEFT. The captions with a keyword take them in turn. |
hold_seconds |
number | 0.0 |
The longest time that a caption stays after its last word ends. The caption goes earlier when the next caption starts. |
KeywordLook
class KeywordLook(NamedTuple)
The colors of one keyword look.
Args:
top_color: The color of the upper part of the letters, as "#RRGGBB".bottom_color: The color at the bottom of the letters, as "#RRGGBB".outline_color: The color of the outline and of the glow, as "#RRGGBB".
PunchSettings
@dataclass(frozen=True)
class PunchSettings(CaptionSettings)
The settings of the punch effect: the settings of CaptionSettings, with the defaults of the source video, the letter width, the end of a caption at an end mark, the shadow, the keyword, its looks, its outline and glow, its gradient, its gap and its drop, the drift and the hold time.
Args:
letter_width: The width of the letters of the plain words as a part of the width that the font gives them, above 0.end_at_marks: True to end a caption also at each word that ends with an end mark, such as a comma.shadow_color: The color of the shadow of the plain words, as "#RRGGBB".shadow_spread: How far the shadow reaches past the outline, in pixels.shadow_blur: How far the edge of the shadow fades out, in pixels.shadow_opacity: The strength of the shadow, from 0 for no shadow to 1.shadow_drop: How far the shadow is below the letters, in pixels. A value below 0 puts the shadow above them.keyword_font_name: Name of the font of a keyword. A full name, such as Ubuntu Bold Italic, picks one face of a font.keyword_bold: True for bold keyword letters.keyword_font_size: Height of the font of a keyword in pixels, a whole number above 0. The row of a caption with a keyword is this high.keyword_letter_width: The width of the letters of a keyword as a part of the width that the font gives them, above 0.keyword_weight: How far the letters of a keyword grow on each side, in pixels, to make them heavier. 0 keeps the letters of the font.keyword_looks: The looks of the keywords, each a top color, a bottom color and an outline color. The keywords of a video take them in turn.keyword_outline_width: How far the outline of a keyword reaches past its grown letters, in pixels.keyword_outline_blur: How far the edge of the outline and of the glow fades out, in pixels.keyword_glow_drop: How far the glow of a keyword is below its letters, in pixels. A value below 0 puts it above them.keyword_glow_opacity: The strength of the glow, from 0 for no glow to 1.gradient_top: Where the gradient of a keyword starts, as a part of its row below the top of the row. The letters above it have the top color.gradient_bottom: Where the gradient ends, as a part of its row below the top of the row, below the gradient top. The letters below it have the bottom color.strip_height: The height in pixels of a strip of the gradient, 1 or above. A lower strip gives a smoother gradient and more events.keyword_gap_before: Room in pixels that is added to a space in front of a keyword. A value below 0 puts the words closer.keyword_gap_after: Room in pixels that is added to a space behind a keyword. A value below 0 puts the words closer. A space between two keywords gets both gaps.keyword_drop: How far the place of a caption with a keyword is below the bottom position, in pixels. A value below 0 puts it higher.drift: How far a caption with a keyword moves to the side and up or down, in pixels. 0 keeps it at its place.drift_delay_seconds: The time from the start of a caption with a keyword to the start of its drift.drift_seconds: The time of the drift. 0 shows the caption at the end of its drift from the delay on.drift_turns: The directions of the drift, DRIFT_DOWN_RIGHT or DRIFT_UP_LEFT. The captions with a keyword take them in turn.hold_seconds: The longest time that a caption stays after its last word ends. The caption goes earlier when the next caption starts.
Raises:
TypeError: When a word count is not a whole number.ValueError: When a value is outside its range, when a color is not in the form "#RRGGBB", or when a font name is empty or holds a comma.
PunchSettings.plain_font_tags
def plain_font_tags(self, scale: float) -> str
Write the font tags of a plain word, with no curly brackets.
Args:
scale: The size of the caption as a part of its full size.
PunchSettings.keyword_font_tags
def keyword_font_tags(self, scale: float) -> str
Write the font tags of a keyword, with no curly brackets.
Args:
scale: The size of the caption as a part of its full size.
keyword_parts
def keyword_parts(text: str) -> tuple[str, str]
Cut a keyword into its letters and the end marks behind them.
Args:
text: The text of the word, as spoken.
Returns:
The word with no end marks and no closing marks at its end, and those marks. A word that is only such marks keeps its text, and it has no marks behind it.
ShownWord
class ShownWord(NamedTuple)
One word of a caption as the effect shows it.
Args:
letters: The letters of the word. A keyword has them in capitals.marks: The end marks behind the letters of a keyword, which have the look of the plain words. Empty for a plain word.
PunchCaption
class PunchCaption(NamedTuple)
One caption of the effect, before it is fitted to its room.
Args:
caption: The caption with the times of its events.shown: The words as the effect shows them.looks: The look of each keyword, by its place.
MeasureBlock
class MeasureBlock(NamedTuple)
One part of a caption that the caption measure measures.
Args:
word: The place of the word of the part.text: The text of the part: the letters of a word, or the end marks of a keyword.keyword_letters: True for the letters of a keyword.
Drift
class Drift(NamedTuple)
The place of a caption at the start and at the end of its drift.
Args:
start_x: The column of the bottom middle of the caption at the start.start_y: The row of the bottom middle of the caption at the start.end_x: The column at the end of the drift.end_y: The row at the end of the drift.start_milliseconds: The tag time at which the drift starts.end_milliseconds: The tag time at which the drift ends.
Drift.moves
def moves(self) -> bool
Say if the caption moves: it has a way to go and a time to go it. libass reads the times 0 and 0 of a move as the whole length of the event, so a drift that ends at 0 does not move.
Drift.place_tags
def place_tags(self, drop: float) -> str
Write the tags of the place of an event of the caption.
Args:
drop: How far the event is below the place of the caption, in pixels.
Returns:
The tags with no curly brackets: the move of the drift, or the place at its end when the caption does not move.
Drift.clip_tags
def clip_tags(self, top: int, bottom: int, video_width: int) -> str
Write the clip of a strip that moves with the drift.
Args:
top: The first row of the strip at the start of the drift.bottom: The row below the strip at the start of the drift.video_width: Width of a frame of the video in pixels.
Returns:
The tags with no curly brackets. The clip of a caption that moves changes in a straight line in the time of the drift, so it keeps the rows of the strip. A clip tag holds whole rows.
PunchEffect
class PunchEffect
def __init__(
self, settings: PunchSettings, caption_measure: PlaceMeasure,
keyword_picker: KeywordPicker = DEFAULT_KEYWORD_PICKER) -> None
Builds the ASS script of bold white words with a heavy slanted keyword.
Args:
settings: The look and the timing of the effect.caption_measure: The measure that says how wide libass draws each word in its font. It runs ffmpeg once for the plain words and once for the keywords of a video.keyword_picker: Names the keywords of each caption from its words as spoken. The default picks the longest word when it has KEYWORD_FEWEST_LETTERS letters or more.
PunchEffect.build_ass_text
def build_ass_text(self, words: Sequence[Word], video: VideoInfo) -> str
Build the ASS script of the effect for the words of one video.
Each caption is a shadow event and a text event. A caption with a keyword also has an outline event and the strip events of the gradient of its keywords. The events of all captions are written by layer, from the lowest. They start with the first word of their caption. They end when the next caption starts, and at the latest the hold time after its last word and at the end of the video.
Args:
words: The words of the video in time order, each with its times.video: The frame size and the duration of the video.
Returns:
The text of the ASS script. It has no event when there are no words.
Raises:
ValueError: When the side margins leave no room for the caption in the width of the video, when the keyword picker gives a place that is not a word of its caption, or when libass draws no pixel for a word.RuntimeError: When the ffmpeg of the caption measure fails.