#!/usr/bin/python2.7 import sys import os import re import sha from pb.config import * import pb.lib.utils as utils #FIXME these guys can do stuff wider than 1000 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(" ") GRAVITY_DEFAULT = "center" 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", "Linear_Dodge", "Linear_Burn", "Color_Dodge", "Color_Burn" ] DISPOSE = "None Previous Background".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 as e: 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.bool_correct(utils.sanitize(kwargs[k])) elif k == 'gravity' and self._test_enum(kwargs[k], GRAVITY): self.params[k] = kwargs[k] elif k == 'format' and self._test_enum(kwargs[k], FORMAT): self.params[k] = kwargs[k] elif k == 'compose' and self._test_enum(kwargs[k], COMPOSE): self.params[k] = kwargs[k] elif k == 'dispose' and self._test_enum(kwargs[k], DISPOSE): self.params[k] = kwargs[k] elif k in [ "fuzz", "width", "height", "brightness", "contrast", "saturation", "rotate", "hue" ]: self.params[k] = int(kwargs[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 if not self.params.dispose: self.params.dispose = 'None'; self.filename = "{}.{}".format(self.basename, self.params.format) #final filepath is stored in self.filepath self.filepath = os.path.join(WORKING_DIR, self.filename) print str(self.params); 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, self.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) #FIXME need to be more specific two functions below def bin_composite (self, params, bottomfile, topfile, newfile): cmd = [BIN_CONVERT] cmd += [ bottomfile ] cmd += [ "null:" ] cmd += [ topfile ] cmd += [ "-matte" ] cmd += params cmd += [ "-layers", "composite" ] cmd += [ newfile ] self._call_cmd(cmd); def bin_convert (self, params, oldfile, newfile): cmd = [BIN_CONVERT, oldfile] cmd.extend(params) cmd.append(newfile) self._call_cmd(cmd); def _build_cmd(self): cmd = [] if self.params.rotate: cmd += ["-rotate", self.params.rotate ] if self.params.flip: cmd += ["-flip"] if self.params.flop: cmd += ["-flop"] #FIXME add like a boss and make width == height when there's only one #same thing in the other scripts #also dotdict is bad, it's like javascript if self.params['transparent']: self.tag = "transparent" if self.params.fuzz: cmd += ["-fuzz", "{}%".format(self.params.fuzz) ] cmd += [ "-transparent", self.params.get('subtract', "white") ] if self.params.width or self.params.height: if self.params['nearest']: if self.params.format == "gif": cmd += [ "-coalesce","+map","-interpolate","Nearest","-interpolative-resize" ] else: cmd.append("-resize") cmd.append("{}x{}".format(self.params.get('width',''), self.params.get('height',''))) if self.params['black'] != "black" or self.params['white'] != 'white': cmd += [ "+level-colors" , "{},{}".format(self.params.black, self.params.black) ] if self.params.contrast: cmd += [ '-contrast-stretch', self.params.contrast ] if any( e in self.params.keys for e in ['brightness', 'saturation', 'hue' ]): cmd += [ "{},{},{}".format( self.params.get('brightness', 100), self.params.get('contrast', 100), self.params.get('hue', 100) ), "-modulate" ] if self.params.bgfile: self.tag = self.params['compose'] cmd.append("-coalesce"); compositeparams = ["-dispose", "None", "-gravity", self.params.get("gravity",GRAVITY_DEFAULT) ] compositeparams.extend([ "-compose", self.params['compose'] ]) # # bin_convert (WORKING_DIR, cmd, oldfile, compositefile) #then... # bin_composite (compositeparams, bgfile, 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) # ##remove(newfile) # #g.close() if __name__ == "__main__": TEST_PARAMS = { 'nearest': 'true', # 'height': None, 'compose': 'Soft_Light', 'coalesce': 'true', 'dispose': 'true', 'gravity': 'Center', 'width': '200', 'black': 'black', 'tile': 'true', 'white': 'white', 'contrast': '100', 'hue': '90', 'saturation': '100', 'merge_early': 'true', 'format': 'gif', 'background': 'http://i.asdf.us/im/bc/new_1430440747.gif', 'subtract': '#EE7AE9', 'transparent': 'true', # 'rotate': None, 'name': 'yo', # 'brightness': None, 'url': 'http://asdf.us/im/new.gif', 'flop': 'true', 'flip': 'false', 'callback': 'jsonp1430442384162', 'fuzz': '5' } g = Generate(**TEST_PARAMS);