--- a/index.cgi Tue May 05 18:25:16 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,379 +0,0 @@
-#!/usr/bin/python2.5
-import werkzeug
-from werkzeug.exceptions import HTTPException
-import wsgiref.handlers
-
-from PIL import Image, ImageDraw, ImageFont, ImageEnhance
-from cStringIO import StringIO
-import random, itertools, time
-
-if not hasattr(itertools, 'izip_longest') :
-
- def izip_longest(*args, **kwds):
- # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
- fillvalue = kwds.get('fillvalue')
- def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
- yield counter() # yields the fillvalue, or raises IndexError
- fillers = itertools.repeat(fillvalue)
- iters = [itertools.chain(it, sentinel(), fillers) for it in args]
- try:
- for tup in itertools.izip(*iters):
- yield tup
- except IndexError:
- pass
-
- itertools.izip_longest = izip_longest
-
-class Defaults :
- # settings
-
- text_lang = 'en'
-
- chars = [ u'"', u'!', u'?' ]
-
- colors = [
- "#0469af",
- "#fbc614",
- "#e1313b",
- ]
-
- font_name = 'helvetica'
- font_size = 30
-
- bg_color = "#ffffff"
- line_spacing = -10
- sharpness = 0.6
-
- img_format = 'png'
-
-TEXT_BY_LANG = dict(
- en = [
- u"aalto",
- u"unive",
- u"rsity"
- ],
- fi = [
- u"aalto",
- u"yliop",
- u"isto"
- ],
- se = [
- u"aalto",
- u"univer",
- u"sitetet",
- ],
-)
-
-FONTS = {
- 'dejavu-sans-bold': "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf",
- 'helvetica': "HELR65W.TTF",
- }
-
-IMAGE_FORMATS = {
- 'jpeg': 'jpeg',
- 'jpg': 'jpeg',
- 'png': 'png',
- 'bmp': 'bmp'
-}
-
-FONT_SIZE_MAX = 1024
-
-# enable debugging
-DEBUG = True
-
-
-def randomize (seq) :
- """
- Returns the given sequence in random order as a list
- """
-
- # copy
- l = list(seq)
-
- # rearrange
- random.shuffle(l)
-
- return l
-
-def randomize_str_char (str) :
- """
- Randomize the given string by moving one char around
- """
-
- l = list(str)
-
- c = l.pop(random.randint(0, len(l) - 1))
- l.insert(random.randint(0, len(l)), c)
-
- return ''.join(l)
-
-def build_data (text, chars, line_colors, random_chars=True, random_text=False, random_text_char=False) :
- """
- 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
- random_chars - randomize the lines the chars go in
- random_text - randomize the chars in each line
- random_text_char - randomize each line by moving one char around
- """
-
- data = []
-
- if random_chars :
- chars = randomize(chars)
-
- for line, char, color in itertools.izip_longest(text, chars, line_colors, fillvalue=None) :
- # pick position to place char
- pos = random.randint(1, len(line) - 1)
-
- if not color :
- color = "#000000"
-
- if random_text :
- line = ''.join(randomize(line))
-
- if random_text_char :
- line = randomize_str_char(line)
-
- # split into three parts
- if char :
- data.append([
- (line[:pos], "#000000"),
- (char, color),
- (line[pos:], "#000000"),
- ])
- else :
- data.append([
- (line, "#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_sharpness (img, factor) :
- """
- Sharpen the image by the given factor
- """
-
- return ImageEnhance.Sharpness(img).enhance(factor)
-
-def build_img (img, format='png') :
- """
- Write the given PIL.Image as a string, returning the raw binary data
-
- Format should be one of the PIL-supported image foarts
- """
-
- # render PNG output
- buf = StringIO()
- img.save(buf, format)
- data = buf.getvalue()
-
- return data
-
-def arg_bool (val) :
- if val.lower() in ('true', 't', '1', 'yes', 'y') :
- return True
- elif val.lower() in ('false', 'f', '0', 'no', 'n') :
- return False
- else :
- raise ValueError(val)
-
-def arg_color (val) :
- if val.beginswith('#') :
- int(val[1:], 16)
-
- return val
- else :
- raise ValueError(val)
-
-class Option (object) :
- def __init__ (self, name, is_list, type, default, range) :
- self.name = name
- self.is_list = is_list
- self.type = type
- self.default = default
- self.range = range
-
- def parse (self, args) :
- if self.is_list :
- if self.name in args :
- return args.getlist(self.name, self.type)
- else :
- return self.default
- else :
- if self.type == arg_bool and not self.default and self.name in args :
- return True
-
- else :
- return args.get(self.name, self.default, self.type)
-
-class Options (object) :
- def __init__ (self, *options) :
- self.options = options
-
- def parse (self, args) :
- return dict((opt.name, opt.parse(args)) for opt in self.options)
-
-OPTIONS = Options(
- Option('lang', False, str, Defaults.text_lang, TEXT_BY_LANG.keys()),
- Option('text', True, unicode, None, None),
- Option('random-text', False, arg_bool, False, None),
- Option('random-text-char', False, arg_bool, False, None),
- Option('chars', True, unicode, Defaults.chars, None),
- Option('random-chars', False, arg_bool, True, None),
- Option('colors', True, arg_color, Defaults.colors, None),
- Option('font', False, str, Defaults.font_name, FONTS.keys()),
- Option('font-size', False, int, Defaults.font_size, None),
- Option('bg-color', False, arg_color, Defaults.bg_color, None),
- Option('line-spacing', False, int, Defaults.line_spacing, None),
- Option('sharpness', False, float, Defaults.sharpness, None),
- Option('image-format', False, str, Defaults.img_format, IMAGE_FORMATS.keys()),
- Option('seed', False, int, None, None),
-)
-
-def handle_help (req) :
- return werkzeug.Response('\n'.join(
- "%-15s %4s %-10s %-20s %s" % data for data in [
- ("name", "", "type", "default", "range"),
- ("", "", "", "", ""),
- ] + [(
- opt.name,
- 'list' if opt.is_list else 'item',
- opt.type.__name__,
- repr(opt.default),
- opt.range if opt.range else ""
- ) for opt in OPTIONS.options]
- ), mimetype='text/plain')
-
-def handle_request (req) :
- if 'help' in req.args :
- return handle_help(req)
-
- # parse options
- opts = OPTIONS.parse(req.args)
-
- # postprocess
- if opts['text'] is None :
- opts['text'] = TEXT_BY_LANG[opts['lang']]
-
- if opts['font-size'] > FONT_SIZE_MAX :
- raise ValueError(opts['font-size'])
-
- if opts['seed'] is None :
- opts['seed'] = time.time()
-
- # load/prep resources
- random.seed(opts['seed'])
- data = build_data(opts['text'], opts['chars'], opts['colors'], opts['random-chars'], opts['random-text'], opts['random-text-char'])
- font = load_font(opts['font'], opts['font-size'])
-
- # render the image
- img = render_img(data, font, opts['bg-color'], opts['line-spacing'])
-
- img = effect_sharpness(img, opts['sharpness'])
-
- png_data = build_img(img, opts['image-format'])
-
- # build the response
- response = werkzeug.Response(png_data, mimetype='image/%s' % opts['image-format'])
-
- return response
-
-@werkzeug.Request.application
-def wsgi_application (request) :
- """
- Our werkzeug WSGI handler
- """
-
- try :
- # request -> response
- response = handle_request(request)
-
- return response
-
- except HTTPException, e :
- # return as HTTP response
- return e
-
-def main () :
- handler = wsgiref.handlers.CGIHandler()
- app = wsgi_application
-
- if DEBUG :
- # enable debugging
- app = werkzeug.DebuggedApplication(app, evalex=False)
-
- handler.run(app)
-
-if __name__ == '__main__' :
- main()
-