Moving Pictures

We recently did a survey for comments on a particular program. The survey was done through an anonymous Google form, which allowed us to download the list of responses as a CSV file. The question was: How do we display these responses to their intended audience?

Sending out a CSV file, or in fact just a list of comments, didn’t seem like a very effective approach. What we really wanted was a little video that could be played on screen at a meeting.

So, how do you convert a list of text responses into a video? This is my solution.

Libraries

I used the PIL Python library:

from PIL import Image, ImageDraw, ImageFont

and I actually converted my CSV file into a text file. Reading a CSV file in Python is not difficult (I did it here in fact), but I just couldn’t be bothered this time.

To start let’s open the text file of comments:

comments = open('comments-171023.txt','r')

…and then we’re going to loop through making an image from each comment.

Images of Text

First off, we need to read each line in the text file. If there isn’t a line then we’re done and we should break the loop.

n_com = 0  # initialise number of comments looped over
while True:

    line = comments.readline()
    if not line: break

For each text line (comment) I want to make an image. I’m using the PIL Image library here and making a colour image with specified dimensions and a white background (255, 255, 255):

# still inside While loop:
#
    # increment the comment number:
    n_com+=1

    # specify the width and height of the image:
    W, H = (1024,1024)

    # create a new colour image:
    image = Image.new("RGBA", (W,H), (255,255,255))

    # attach the image to the PIL drawing tool:
    draw = ImageDraw.Draw(image)

I’m going to write the text for each comment into the image. I wanted a font that looked like handwriting but was still easy to read as it flashed up. I chose my font from here.

I also specified the font size (80). The fontsize is font-dependent and I had to play around before picking this number.

# still inside While loop:
#
    # specify the font you want to use and the fontsize:
    font = ImageFont.truetype("./FONTS/James_Fajardo.ttf", 80)

Next I had to clean up the contents of my comments a little. I removed the line breaks and then I split every comment up into its constituent words.

# still inside While loop:
#
    line = line.replace('\n','')
    words = line.split(' ')

Splitting the comments up into lists of words is necessary because I didn’t have any prior info on how long each comment was – some of them were just one word, some were short essays.

In order to position the text correctly in the image that meant I had to do a rough partitioning. I chose to put 5 words on each line of text in each image of a comment.

I called each 5 word segment a snippet and worked out how many snippets (n_snip) were in each comment:

# still inside While loop:
#
    n_snip = int(len(words)/5)
    extra = len(words)%5 

    if (extra>0): n_snip+=1

To make each image, I looped over the number of snippets in each comment and I worked out how large each one was using font.getsize.

Note: it’s much better to use font.getsize rather than draw.textsize.

I then positioned each snippet centrally, offset from the image centre by a vertical step of 65 pixels per snippet relative to the central snippet. (It’s more difficult to explain verbally than to write the code…)

# still inside While loop:
#
    for i in range(0,n_snip):
        start = i*5
        stop = (i+1)*5
        snippet = ' '.join(words[start:stop])

        w, h = font.getsize(snippet)

        j = i - (n_snip/2)
        xpt = (W-w)/2
        ypt = ((H-h)/2) + (65*j)

        draw.text((xpt,ypt), snippet, fill="black", font=font)

I then reduced the size of my image down from (1024,1024) to (512,512):

# still inside While loop:
#
    img_resized = image.resize((512,512), Image.ANTIALIAS)

…and saved it as a PNG image:

# still inside While loop:
#
    image.save("./IMAGES/comment_"+str(n_com)+".png")

Apparently it is possible to make an mp4 from a stack of image files inside Python, but there’s really no point. All you need is this one command line using ffmpeg:

ffmpeg -f image2 -r 1/5 -i comment_%d.png -vcodec mpeg4 -y movie.mp4

Then for the blog this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s