#!/usr/bin/python2.7 import sys import os import re import sha from pb.config import * import pb.lib.utils as utils LIKE_A_BOSS = "ryz pepper seamonkey JAMES".split(" ") DEFAULT_FINALFORMAT = "gif" DB_TAG = "pb"; GRAVITY = "NorthWest North NorthEast West Center East SouthWest South SouthEast".split(" ") FORMAT = "jpg gif png".split(" ") COMPOSE = "Over ATop Dst_Over Dst_In Dst_Out Multiply Screen Divide Plus Difference Exclusion "+ "Lighten Darken Overlay Hard_Light Soft_Light Pegtop_Light Linear_Light Vivid_Light Pin_Light "+ "Linear_Dodge Linear_Burn Color_Dodge Color_Burn".split(" "); class Generate(): def __init__(self, **kwargs): self.params = {} self.tag = "im" self.now = utils.now() self.files_created = [] self.commands = []; self._required_keys = [ #{{{ required_keys #IMAGES "url", "background", #BOOLS "coalesce", "dispose", "nearest", "merge_early", "flip", "flop", "tile", "transparent", #COLORS "black", "white", "subtract", #INTS "fuzz", "width", "height", "brightness", "contrast", "saturation", "rotate", "hue", #ENUMS "compose", "gravity", "format", #STRINGS "name", "callback", #}}} ] for k in self._required_keys: if k in kwargs: if k in [ 'url', 'background' ] and utils.bool_correct(kwargs[k]): self.params[k] = { 'url' : kwargs[k], 'filename' : self._make_tempname(k), 'path' : os.path.join(WORKING_DIR, self._make_tempname(k)) , } try: utils.download(self.params[k]['url'], self.params[k]['path']) self.files_created.append(self.params[k]['path']) self.params[k]['mimetype'] = utils.get_mimetype(self.params[k]['path']) except Exception: sys.stderr.write(str(e)) raise Exception ("BAD PARAMS"); elif k in [ 'black', 'white', 'subtract' ]: try: self.params[k] = utils.is_color(kwargs[k]) except Exception: raise Exception("Unable to process color for:\n{}".format(k)) elif k in [ "coalesce", "dispose", "nearest", "merge_early", "flip", "flop", "tile", "transparent", ]: self.params[k] = utils.bootl_correct(utils.sanitize(kwargs[k])) elif k == 'gravity' and self._test_enum(k, GRAVITY): self.params[k] = kwargs[k] elif k == 'format' and self._test_enum(k, FORMAT): self.params[k] = kwargs[k] elif k == 'compose' and self._test_enum(k, COMPOSE): self.params[k] = kwargs[k] elif k in [ "fuzz", "width", "height", "brightness", "contrast", "saturation", "rotate", "hue" ]: self.params[k] = int(params[k]) else: self.params[k] = utils.sanitize(kwargs[k]) else: self.params[k] = None; self.params = utils.dotdict(self.params) self.basename = self._get_filename(); if not self.params.format: self.params.format = DEFAULT_FINALFORMAT self.filename = "{}.{}".format(self.basename, self.params.format) #final filepath is stored in self.filepath self.filepath = os.path.join(WORKING_DIR, self.filename) def _make_tempname(self, s): return "PBTMP{}{}".format(self.now, s); def _test_enum(self, k, arr): if k in arr: return True else: raise Exception("Bad Param: {}".format(k)) def _get_filename(self): return "{}_{}_{}".format( self.tag, now(), self.params.username or "" ); def _call_cmd(self, cmd): try: utils.call_cmd(cmd) self.commands.append(" ".join(cmd)); except Exception: raise Exception("Unable to call cmd {}".format(str(cmd))) def _cleanup(self): if not len(self.files_created): pass cmd = ["rm", "-f"] + self.files_created self._call_cmd(cmd) def bin_composite (params, bottomdir, bottomfile, topdir, topfile, newfile): cmd = [BIN_CONVERT] cmd.append(os.path.join(bottomdir,bottomfile)) cmd.append('null:') cmd.append(os.path.join(topdir,topfile)) cmd.append("-matte") cmd.extend(params) cmd.append("-layers composite") cmd.append(os.path.join(topdir, newfile)) # g.write("bin_composite command: %s" % (" ".join(cmd))); os.system(" ".join(cmd)) os.system("rm "+os.path.join(bottomdir,bottomfile)+" "+os.path.join(topdir,topfile)) def bin_convert (directory, params, oldfile, newfile): cmd = [BIN_CONVERT, os.path.join(directory, oldfile)] for x in params: cmd.append(x) cmd.append(os.path.join(directory,newfile)) os.system(" ".join(cmd)) # g.write("bin_convert command: %s" % (" ".join(cmd))); os.system("rm "+os.path.join(directory,oldfile)) def _build_cmd(self): cmd = [] #FIXME test if number if self.params.rotate: cmd += ["-rotate", self.params.rotate ] if self.params.flip: cmd += ["-flip"] if self.params.flop: cmd += ["-flop"] if param['transparent'] == "true": tag = "transparent" if is_number(param['fuzz']) and param['fuzz'] != 0: cmd.append("-fuzz") cmd.append(param['fuzz']+"%") subtract_color = as_color(param['subtract'], "white") cmd.append("-transparent") cmd.append(subtract_color) VALID_DISPOSE_METHODS=["none","previous","background"] dispose = "None" if param['width'] is not None and is_number(param['width']): if int(param['width']) > 1000 and NOT_A_BOSS: error ("width cannot be greater than 1000") width = param['width'] if param['height'] is not None and is_number(param['height']): if int(param['height']) > 1000 and NOT_A_BOSS: error ("height cannot be greater than 1000") height = param['height'] if (width or height): if param['nearest'] == "true": if format == "gif": cmd.append("-coalesce") cmd.append("+map") cmd.append("-interpolate") cmd.append("Nearest") cmd.append("-interpolative-resize") else: cmd.append("-resize") if width and height: cmd.append(width + "x" + height) elif width: cmd.append(width) elif height: cmd.append("x" + height) if param['black'] != "black" or param['white'] != 'white': try: black = as_color(param['black'], "black") white = as_color(param['white'], "white") cmd.append("+level-colors") cmd.append(black+","+white) except (): pass if param['contrast'] is not None and is_number(param['contrast']): cmd.append("-contrast-stretch") cmd.append(param['contrast']) pass if param['brightness'] is not None or param['saturation'] is not None or param['hue'] is not None: bstring = '' if is_number(param['brightness']): bstring += param['brightness'] else: bstring += "100" bstring += ',' if is_number(param['contrast']): bstring += param['contrast'] else: bstring += "100" bstring += ',' if is_number(param['hue']): bstring += param['hue'] if bstring != "100,100,": cmd.append("-modulate") cmd.append(bstring) if bgfile is not None: tag = param['compose'] gravity = param['gravity'] if gravity not in GRAVITY: gravity = 'center' compositefile = "composite_" + newfile compositeparams = ["-dispose", "None", "-gravity", gravity] compositeparams.extend([ "-compose", param['compose'] ]) cmd.append( "-coalesce") bin_convert (WORKING_DIR, cmd, oldfile, compositefile) bin_composite (compositeparams, WORKING_DIR, bgfile, WORKING_DIR, compositefile, newfile) insert_cmd(dir, oldfile, newfile, cmd, url, name, tag) else: bin_convert(WORKING_DIR, cmd, oldfile, newfile) insert_cmd(dir, oldfile, newfile, cmd, url, name, tag) # jsonp callback if param['callback'] is not None: url = (BASE_URL+dir+"/"+newfile).replace("'", "\\'") width, height = bin_identify (WORKING_DIR, newfile) print param['callback'] + "({" print "'url':'" + url + "'," print "'size':" + str(file_size (WORKING_DIR, newfile)) + "," print "'width':" + width + "," print "'height':" + height print "});" moveToS3(os.path.join(WORKING_DIR, newfile), "im/"+dir+"/"+newfile) else: print "#@im" print ", ".join([k+"="+str(v) for k,v in param.iteritems()]) print " ".join(cmd) print BASE_URL+dir+"/"+newfile print file_size (WORKING_DIR, newfile) print bin_identify (WORKING_DIR, newfile) moveToS3(os.path.join(WORKING_DIR, newfile), "im/"+dir+"/"+newfile) #remove(newfile) g.close()