#!/usr/bin/python2.5
import cgi, cgitb
cgitb.enable()
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
from cStringIO import StringIO
import random
# settings
text = [
"aalto",
"unive",
"rsity"
]
random_chars = [ '"', '!', '?' ]
line_colors = [
"#0469af",
"#fbc614",
"#e1313b",
]
fonts = {
'dejavu-sans-bold': "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf",
'helvetica': "HELR65W.TTF",
}
font_name = 'helvetica'
font_size = 30
def randomize (seq) :
"""
Returns the given sequence in random order as a list
"""
# copy
l = list(seq)
# rearrange
random.shuffle(l)
return l
def build_data (text, chars, line_colors) :
"""
Returns a matrix of (text, color) tuples representing the data to render
[ [ (str, str) ] ]
text - list of lines
chars - list of random chars to interpse
line_colors - list of colors to draw the chars in
"""
data = []
for line, char, color in zip(text, chars, line_colors) :
# pick position to place char
pos = random.randint(1, len(line) - 1)
# split into three parts
data.append([
(line[:pos], "#000000"),
(char, color),
(line[pos:], "#000000"),
])
return data
def load_font (font_name, font_size) :
"""
Load a font by name
"""
# load font
font_path = fonts[font_name]
font = ImageFont.truetype(font_path, font_size)
return font
def render_img (data, font, background_color="#ffffff", line_spacing=0) :
"""
Render the data (as from build_data) as an image, using the given PIL.ImageFont, and return the PIL Image object
"""
img_width = img_height = 0
img_data = []
# compute image width/height
for segments in data :
line_width = line_height = 0
# build a new list of segments with additional info
line_segments = []
for seg_text, seg_color in segments :
# compute rendered text size
seg_width, seg_height = font.getsize(seg_text)
# update line_*
line_width += seg_width
line_height = max(line_height, seg_height)
# build the new segments list
line_segments.append((seg_text, seg_color, seg_width))
# update img_*
img_width = max(img_width, line_width)
img_height += line_height
img_data.append((line_segments, line_height))
# calculate height needed for line spacing
img_height += (len(img_data) - 1) * line_spacing
# create image
img = Image.new("RGB", (img_width, img_height), background_color)
draw = ImageDraw.Draw(img)
# draw text
img_y = 0
for segments, line_height in img_data :
img_x = 0
# draw each segment build above, incremeing along img_x
for seg_text, seg_color, seg_width in segments :
draw.text((img_x, img_y), seg_text, font=font, fill=seg_color)
img_x += seg_width
img_y += line_height + line_spacing
return img
def effect_smooth (img, factor) :
"""
De-sharpen the image by the given factor
"""
return ImageEnhance.Sharpness(img).enhance(factor)
def build_png (img) :
"""
Write the given PIL.Image as a string, returning the raw binary data
"""
# render PNG output
buf = StringIO()
img.save(buf, "png")
data = buf.getvalue()
return data
def response (type, data) :
"""
Write out the HTTP Response
"""
from sys import stdout
stdout.write("Content-Type: %s\r\n" % type)
stdout.write("Content-Length: %d\r\n" % len(data))
stdout.write("\r\n")
stdout.write(data)
def main () :
data = build_data(text, randomize(random_chars), line_colors)
font = load_font(font_name, font_size)
img = render_img(data, font, line_spacing=-10)
img = effect_smooth(img, 0.6)
png_data = build_png(img)
response("image/png", png_data)
if __name__ == '__main__' :
main()