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.