index.py
changeset 16 9234f5ae765b
parent 15 707ddd7a7912
child 17 301725d72e29
equal deleted inserted replaced
15:707ddd7a7912 16:9234f5ae765b
   124             random_text         - randomize the chars in each line
   124             random_text         - randomize the chars in each line
   125             random_text_char    - randomize each line by moving one char around
   125             random_text_char    - randomize each line by moving one char around
   126     """
   126     """
   127 
   127 
   128     data = []
   128     data = []
   129 
   129     
       
   130     # if no chars given, don't insert any
       
   131     if not chars :
       
   132         chars = []
       
   133     
       
   134     # randomize char order across lines?
   130     if random_chars :
   135     if random_chars :
   131         chars = randomize(chars)
   136         chars = randomize(chars)
   132     
   137     
   133     for line, char, color in itertools.izip_longest(text, chars, line_colors, fillvalue=None) :
   138     for line, char, color in itertools.izip_longest(text, chars, line_colors, fillvalue=None) :
   134         if not line :
   139         if not line :
   135             continue
   140             continue
   136 
   141 
   137         # pick position to place char
   142         # pick position to place char
   138         pos = random.randint(1, len(line) - 1)
   143         if len(line) >= 2 :
   139 
   144             pos = random.randint(1, len(line) - 1)
       
   145         else :
       
   146             pos = random.randint(0, 1)
       
   147         
       
   148         # default color
   140         if not color :
   149         if not color :
   141             color = "#000000"
   150             color = "#000000"
   142 
   151         
       
   152         # randomize text in some way?
   143         if random_text :
   153         if random_text :
   144             line = ''.join(randomize(line))
   154             line = ''.join(randomize(line))
   145 
   155 
   146         if random_text_char :
   156         if random_text_char :
   147             line = randomize_str_char(line)
   157             line = randomize_str_char(line)
   249     img.save(buf, format)
   259     img.save(buf, format)
   250     data = buf.getvalue()
   260     data = buf.getvalue()
   251 
   261 
   252     return data
   262     return data
   253 
   263 
   254 def arg_bool (val) :
   264 class OptionType (object) :
   255     if val.lower() in ('true', 't', '1', 'yes', 'y') :
   265     def parse (self, val) :
   256         return True
   266         """
   257     elif val.lower() in ('false', 'f', '0', 'no', 'n') :
   267             Unicode value -> object
   258         return False
   268         """
   259     else :
   269 
   260         raise ValueError(val)
   270         abstract
   261 
   271 
   262 def arg_color (val) :
   272     def build (self, val) :
   263     if val.beginswith('#') :
   273         """
   264         int(val[1:], 16)
   274             object -> unicode value
   265 
   275         """
   266         return val
   276 
   267     else :
   277         return unicode(val)
   268         raise ValueError(val)
   278     
       
   279     def input (self, val) :
       
   280         """
       
   281             HTML input item
       
   282         """
       
   283 
       
   284         abstract
       
   285 
       
   286 class StringOption (OptionType) :
       
   287     def parse (self, val) :
       
   288         return unicode(val)
       
   289     
       
   290     def build (self, val) :
       
   291         if val is None :
       
   292             return ""
       
   293 
       
   294         else :
       
   295             return val
       
   296 
       
   297     def input (self, opt, val) :
       
   298         return """<input type="text" name="%(name)s" id="%(name)s" value="%(value)s" />""" % dict(
       
   299             name        = opt.name,
       
   300             value       = self.build(val),
       
   301         )
       
   302     
       
   303     def select (self, opt, val) :
       
   304         return """<select name="%(name)s">
       
   305 %(options)s
       
   306 </select>""" % dict(
       
   307             name        = opt.name,
       
   308             options     = '\n'.join(
       
   309                 "\t<option %(selected)s>%(value)s</option>" % dict(
       
   310                     value       = self.build(optval),
       
   311                     selected    = 'selected="selected"' if val == optval else "",
       
   312                 ) for optval in opt.range
       
   313             ),
       
   314         )
       
   315 
       
   316 class BoolOption (OptionType) :
       
   317     def parse (self, val) :
       
   318         if val.lower() in ('true', 't', '1', 'yes', 'y') :
       
   319             return True
       
   320 
       
   321         elif val.lower() in ('false', 'f', '0', 'no', 'n') :
       
   322             return False
       
   323 
       
   324         else :
       
   325             raise ValueError(val)
       
   326     
       
   327     def input (self, opt, val) :
       
   328         return """<input type="checkbox" name="%(name)s" id="%(name)s" %(checked)s/>""" % dict(
       
   329             name        = opt.name,
       
   330             checked     = 'checked="checked"' if val else '',
       
   331         )
       
   332 
       
   333 class IntOption (StringOption) :
       
   334     def parse (self, val) :
       
   335         return int(val)
       
   336 
       
   337 class FloatOption (StringOption) :
       
   338     def parse (self, val) :
       
   339         return float(val)
       
   340 
       
   341 class ColorOption (StringOption) :
       
   342     def _parse (self, val) :
       
   343         if val.startswith('#') :
       
   344             int(val[1:], 16)
       
   345 
       
   346             return val
       
   347         else :
       
   348             raise ValueError(val)
       
   349 
   269 
   350 
   270 class Option (object) :
   351 class Option (object) :
   271     def __init__ (self, name, is_list, type, default, range) :
   352     def __init__ (self, name, is_list, type, default, range) :
   272         self.name = name
   353         self.name = name
   273         self.is_list = is_list
   354         self.is_list = is_list
   274         self.type = type
   355         self.type = type
   275         self.default = default
   356         self.default = default
   276         self.range = range
   357         self.range = range
   277 
   358 
   278     def parse (self, args) :
   359     def parse (self, args, force_bool=False) :
   279         if self.is_list :
   360         if self.is_list :
   280             if self.name in args :
   361             if self.name in args :
   281                 return args.getlist(self.name, self.type)
   362                 l = args.getlist(self.name, self.type.parse)
       
   363                 
       
   364                 # special-case to handle a single param with a newline-separtated list
       
   365                 if len(l) == 1 :
       
   366                     if not l[0] :
       
   367                         return None
       
   368 
       
   369                     else :
       
   370                         return l[0].split('\r\n')
       
   371 
       
   372                 else :
       
   373                     return l
       
   374 
   282             else :
   375             else :
   283                 return self.default
   376                 return self.default
   284         else :
   377 
   285             if self.type == arg_bool and not self.default and self.name in args :
   378         else :
       
   379             if isinstance(self.type, BoolOption) and force_bool :
       
   380                 return self.name in args
       
   381 
       
   382             elif isinstance(self.type, BoolOption) and not self.default and self.name in args :
   286                 return True
   383                 return True
   287 
   384 
   288             else :
   385             else :
   289                 return args.get(self.name, self.default, self.type)
   386                 return args.get(self.name, self.default, self.type.parse)
       
   387     
       
   388     def build_list (self, value) :
       
   389         if self.is_list and value :
       
   390             return [self.type.build(val) for val in value]
       
   391 
       
   392         else :
       
   393             return [self.type.build(value)]
       
   394 
       
   395     def _build_input (self, value) :
       
   396         if self.is_list :
       
   397             return """\
       
   398 <textarea name="%(name)s" cols="30">\
       
   399 %(data)s\
       
   400 </textarea>""" % dict(
       
   401                 name        = self.name,
       
   402                 data        = '\n'.join(self.type.build(val) for val in value) if value else '',
       
   403             )
       
   404 
       
   405         elif self.range :
       
   406             return self.type.select(self, value)
       
   407 
       
   408         else :
       
   409             return self.type.input(self, value)
       
   410 
       
   411     def build_form (self, opts) :
       
   412         value = opts[self.name]
       
   413 
       
   414         return """\
       
   415 <div class="param"><label for="%(name)s">%(title)s</label>%(input)s</div>\
       
   416         """ % dict(
       
   417             name        = self.name,
       
   418             title       = self.name.title().replace('-', ' '),
       
   419             input       = self._build_input(value)
       
   420         )
   290 
   421 
   291 class Options (object) :
   422 class Options (object) :
   292     def __init__ (self, *options) :
   423     def __init__ (self, *options) :
   293         self.options = options
   424         self.options = list(options)
   294 
   425         self.options_by_name = dict((opt.name, opt) for opt in options)
   295     def parse (self, args) :
   426 
   296         return dict((opt.name, opt.parse(args)) for opt in self.options)
   427     def parse (self, args, **kwargs) :
       
   428         return dict((opt.name, opt.parse(args, **kwargs)) for opt in self.options)
   297 
   429 
   298 OPTIONS = Options(
   430 OPTIONS = Options(
   299     Option('lang',          False,  str,        Defaults.text_lang,     TEXT_BY_LANG.keys()),
   431     Option('lang',          False,  StringOption(), Defaults.text_lang,     TEXT_BY_LANG.keys()),
   300     Option('text',          True,   unicode,    None,                   None),
   432     Option('text',          True,   StringOption(), None,                   None),
   301     Option('random-text',   False,  arg_bool,   False,                  None),
   433     Option('random-text',   False,  BoolOption(),   False,                  None),
   302     Option('random-text-char', False, arg_bool, False,                  None),
   434     Option('random-text-char',False,BoolOption(),   False,                  None),
   303     Option('chars',         True,   unicode,    Defaults.chars,         None),
   435     Option('chars',         True,   StringOption(), Defaults.chars,         None),
   304     Option('random-chars',  False,  arg_bool,   True,                   None),
   436     Option('random-chars',  False,  BoolOption(),   True,                   None),
   305     Option('colors',        True,   arg_color,  Defaults.colors,        None),
   437     Option('colors',        True,   ColorOption(),  Defaults.colors,        None),
   306     Option('font',          False,  str,        Defaults.font_name,     FONTS.keys()),
   438     Option('font',          False,  StringOption(), Defaults.font_name,     FONTS.keys()),
   307     Option('font-size',     False,  int,        Defaults.font_size,     None),
   439     Option('font-size',     False,  IntOption(),    Defaults.font_size,     None),
   308     Option('bg-color',      False,  arg_color,  Defaults.bg_color,      None),
   440     Option('bg-color',      False,  ColorOption(),  Defaults.bg_color,      None),
   309     Option('line-spacing',  False,  int,        Defaults.line_spacing,  None),
   441     Option('line-spacing',  False,  IntOption(),    Defaults.line_spacing,  None),
   310     Option('sharpness',     False,  float,      Defaults.sharpness,     None),
   442     Option('sharpness',     False,  FloatOption(),  Defaults.sharpness,     None),
   311     Option('image-format',  False,  str,        Defaults.img_format,    IMAGE_FORMATS.keys()),
   443     Option('image-format',  False,  StringOption(), Defaults.img_format,    IMAGE_FORMATS.keys()),
   312     Option('seed',          False,  int,        None,                   None),
   444     Option('seed',          False,  IntOption(),    None,                   None),
   313     Option('img_width',     False,  int,        None,                   None),
   445     Option('img_width',     False,  IntOption(),    None,                   None),
   314     Option('img_height',    False,  int,        None,                   None),
   446     Option('img_height',    False,  IntOption(),    None,                   None),
   315 )
   447 )
   316 
   448 
   317 def handle_generic (req, img_size=None) :
   449 def handle_generic (req, img_size=None) :
   318     # parse options
   450     # parse options
   319     opts = OPTIONS.parse(req.args)
   451     opts = OPTIONS.parse(req.args)
   372     return handle_generic(req)
   504     return handle_generic(req)
   373 
   505 
   374 def handle_tile (req) :
   506 def handle_tile (req) :
   375     return handle_generic(req, img_size=TILE_SIZE)
   507     return handle_generic(req, img_size=TILE_SIZE)
   376 
   508 
       
   509 def handle_index (options, req) :
       
   510     # parse options, force booleans if any form data was submitted, as checkboxes work that way
       
   511     opts = options.parse(req.values, force_bool=bool(req.form))
       
   512 
       
   513     # build query string of req things
       
   514     qargs = [
       
   515         (opt.name, opt.build_list(val)) for opt, val in (
       
   516             (options.options_by_name[opt_name], val) for opt_name, val in opts.iteritems()
       
   517         ) if val != opt.default
       
   518     ]
       
   519 
       
   520     img_url = req.url_root + "logo" + ("?%s" % werkzeug.url_encode(qargs) if qargs else '')
       
   521 
       
   522     return werkzeug.Response("""\
       
   523 <html>
       
   524     <head>
       
   525         <title>Aaltologotin</title>
       
   526         <style type="text/css">
       
   527 div#logo {
       
   528     text-align: center;
       
   529     padding: 100px;
       
   530 }
       
   531 
       
   532 img {
       
   533     border: none;
       
   534 }
       
   535 
       
   536 div#info {
       
   537     font-size: small;
       
   538     padding-left: 25px;
       
   539     margin-top: 50px;
       
   540     color: grey;
       
   541 }
       
   542 
       
   543 label {
       
   544     display: block;
       
   545     float: left;
       
   546 
       
   547     width: 150px;
       
   548 }
       
   549 
       
   550 div.param {
       
   551     padding: 3px;
       
   552 }
       
   553         </style>
       
   554     </head>
       
   555     <body>
       
   556         <div id='logo'>
       
   557             <a href="%(img_url)s"><img src="%(img_url)s" alt="Aaltologo" /></a>
       
   558         </div>
       
   559         <div id='info'>
       
   560             <h1>Aaltologotin</h1>
       
   561             <p>Aaltologotin pulauttaa sulle uuden, sattumanvaraisesti valitun aalto-logon!</p>
       
   562             
       
   563             <form action="." method="POST">
       
   564                 <fieldset>
       
   565                     <legend>Aalto-parameterit</legend>
       
   566 %(form_fields)s
       
   567                     <input type="submit" value="Logota!" />
       
   568                 </fieldset>
       
   569             </form>
       
   570         </div>
       
   571     </body>
       
   572 </html>""" % dict(
       
   573         img_url     = img_url,
       
   574         form_fields = "\n".join(
       
   575             "\t%s" % opt.build_form(opts) for opt in options.options
       
   576         ),
       
   577     ), mimetype='text/html')
       
   578 
   377 def handle_request (req) :
   579 def handle_request (req) :
   378     if req.path == '/' or req.path.startswith('/logo.') :
   580     if req.path == '/' :
       
   581         return handle_index(OPTIONS, req)
       
   582     
       
   583     elif req.path.startswith('/logo') :
   379         return handle_logo(req)
   584         return handle_logo(req)
   380     
   585     
   381     elif req.path == '/tile' :
   586     elif req.path == '/tile' :
   382         return handle_tile(req)
   587         return handle_tile(req)
   383 
   588