Text moviepy and gizeh

Viewed 1145

I wrote a little python program with moviepy and gizeh (thank Zulko). It shows on screen and moves a text string "my_text" and it works fine.

<!-- language: python -->
# Import everything needed to edit video clips
from moviepy.editor import *
import random
import gizeh

# RESOLUTION
W = 1280
H = 720
duration = 5

def make_frame(t):
    surface = gizeh.Surface(W,H)
    text = gizeh.text("my_text", fontsize = 80, fontfamily="Impact", 
           fill=(1,1,1), xy=(W/2, (min(340,-340+1000*t) )))
    text.draw(surface)

    return surface.get_npimage()

clip2 = VideoClip(make_frame, duration=duration)

clip2.write_videofile("my_video.avi",fps=12, codec='libx264')

I have a poor programming skill. I would like to use a list of text strings ["my_text1", "my_text2", "my_text3"...] instead than just one string "my_text". Furthermore these list elements should appear on the screen in succession and not at the same time. Can someone put me towards the right direction to solve this?

1 Answers

I haven't worked with moviepy, but I believe that the t argument provided to make_frame indicates how many seconds have passed. If we have a list of text_strings that we'd like to spread evenly through the movie (which is 5 seconds long), we'd want to divide the list up into those seconds:

def make_frame(t):
    surface = gizeh.Surface(W,H)
    current_text = text_strings[int((t*len(text_string))//5)]
    text = gizeh.text(current_text, fontsize = 80, fontfamily="Impact", 
           fill=(1,1,1), xy=(W/2, (min(340,-340+1000*t) )))
    text.draw(surface)

If you want each of them to start from the top, I'd recommend having duration be an (integer) variable outside of the function scope. To go through the movement len(text_string) times, we'd want to have it move some max_distance each of those times. This should do that:

def make_frame(t):
    surface = gizeh.Surface(W,H)
    current_text = text_strings[int((t*len(text_string))//duration)]
    text = gizeh.text(current_text, fontsize = 80, fontfamily="Impact", 
           fill=(1,1,1), 
           xy=(W/2, min(340,-340+max_distance*((t*len(text_string)/duration)%1)))
    text.draw(surface)

The way the rather ugly max_distance*((t*len(text_string)/duration)%1) works is this: max_distance is obviously the maximum value, so let's move inside the parentheses. (t*len(text_string)/duration) will move linearly from 0 to len(text_string) over the course of the video. The reason for this is clear when you look at t/duration by itself: the value of that is the fraction of how far through the video we have gone (e.g. Halfway through, t/duration = 0.5). The one interesting part is the use of %1. A primer on the modulus operator can be found elsewhere, but essentially what this will do is "restart" the proportion from 0 to 1 each time we get to a new value. This is best seen in an example:

t = 0
duration = 10
num_strings = 5
while t < 10:
    print(round((t*num_strings/duration)%1, 3))
    t += .1

Note the round is there simply so you won't see any floating point errors. Hopefully now it's clearer.

Related