From 107bf3253c12b3a9f13dda26e13cf61b805faa55 Mon Sep 17 00:00:00 2001 From: Pepper Date: Thu, 30 Apr 2015 18:32:38 -0400 Subject: master --- breaker.py | 267 ---------------------------------------------------- config.py | 20 ---- gradient.py | 215 ------------------------------------------ imgrid.py | 230 --------------------------------------------- lib/__init__.py | 0 lib/db.py | 31 ------- lib/utils.py | 122 ------------------------ pattern.py | 171 ---------------------------------- pb/__init__.py | 0 pb/breaker.py | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++ pb/config.py | 20 ++++ pb/gradient.py | 216 ++++++++++++++++++++++++++++++++++++++++++ pb/imgrid.py | 231 +++++++++++++++++++++++++++++++++++++++++++++ pb/lib/__init__.py | 0 pb/lib/db.py | 31 +++++++ pb/lib/utils.py | 122 ++++++++++++++++++++++++ pb/pattern.py | 172 ++++++++++++++++++++++++++++++++++ pbserver.py | 28 +++--- test.sh | 2 - 19 files changed, 1074 insertions(+), 1072 deletions(-) delete mode 100755 breaker.py delete mode 100644 config.py delete mode 100755 gradient.py delete mode 100755 imgrid.py delete mode 100644 lib/__init__.py delete mode 100755 lib/db.py delete mode 100644 lib/utils.py delete mode 100755 pattern.py create mode 100644 pb/__init__.py create mode 100755 pb/breaker.py create mode 100644 pb/config.py create mode 100755 pb/gradient.py create mode 100755 pb/imgrid.py create mode 100644 pb/lib/__init__.py create mode 100755 pb/lib/db.py create mode 100644 pb/lib/utils.py create mode 100755 pb/pattern.py diff --git a/breaker.py b/breaker.py deleted file mode 100755 index 06c89cf..0000000 --- a/breaker.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/python2.7 -import os -import sys -import random -import re -import lib.utils as utils -import urllib -from config import * - -DEFAULT_FINALFORMAT = "png"; -SUBTLE_BREAK_MARK = 'pron' -EXTREME_BREAK_MARK = 'sugar' - -HEADER_OFFSET = 2000 - -# 'CLASSIC':'jpg', -# 'REDUX':'pcds', -# 'BLURRY_BREAK':'viff', -# 'BLURRY_BREAK_2':'mat', -# 'SWIPE':'miff', -# 'RGB_WASH':'psd', -# 'RGB_WASH_2':'psb', -# 'NOISY_BREAK':'palm', -# 'NOISY_BREAK_2':'fig', -# 'BROKEN_VIGNETTE':'pbm', -# 'FAX_MACHINE':'cals', -# 'STRIPES':'exr', -# 'PHOTOCOPY':'art', - -class Breaker(): - def __init__(self, **kwargs): - self.params = {} - self.tag = "imBreak" - self.commands = []; - self._required_keys = [ - "url", - "breaktype", - "finalformat", - "breakmode", - "breakangle", - "username", - "expanded" - ] - self.files_created = [] - for k in self._required_keys: - if k in kwargs: - if k == 'breaktype': - self.params['breaktype'] = self._get_breaktype(kwargs[k]) - elif k == 'url': - self.params[k] = kwargs[k] - else: - self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k])) - else: - self.params[k] = False; - - - self.params = utils.dotdict(self.params) - - self.basename, self._first_format = self._get_filename(); - self._downloaded_file = os.path.join(WORKING_DIR, "IMBREAKTMP{}.{}".format(self.basename, self._first_format)) # same here - - try: - utils.download(self.params.url, self._downloaded_file) - self.files_created.append(self._downloaded_file) - except Exception as e: - sys.stderr.write(str(e)) - raise; - self._gif_frames = utils.gif_frames(self._downloaded_file) - self._gif_frames = self._gif_frames if len(self._gif_frames) > 1 else False - self.width, self.height = utils.dimensions(self._downloaded_file) # same here - - if not self.params.finalformat: - self.params.finalformat = DEFAULT_FINALFORMAT - if self._gif_frames: - self.params.finalformat = 'gif' - if self.params.breaktype == 'miff': - self.params.finalformat = 'jpg' - self.params.breakmode = 'subtle' - #final filepath is stored in self.filepath - self.filename = "{}.{}".format(self.basename, self.params.finalformat) - self.filepath = os.path.join(WORKING_DIR, self.filename) - self._conversion_file = os.path.join(WORKING_DIR, "IMBREAKTMP{}.{}".format(self.basename, self.params.breaktype)) # this - - - def _call_cmd(self, cmd, error=""): - try: - utils.call_cmd(cmd) - self.commands.append(" ".join(cmd)); - except Exception: - raise Exception("Unable to call cmd {}".format(str(cmd))) - - def _get_breaktype(self, key): - #{{{ conversion table - breaktypeTranslate = { - 'CLASSIC':'jpg', - 'REDUX':'pcds', - 'BLURRY_BREAK':'viff', - 'BLURRY_BREAK_2':'mat', - 'SWIPE':'miff', - 'RGB_WASH':'psd', - 'RGB_WASH_2':'psb', - 'NOISY_BREAK':'palm', - 'NOISY_BREAK_2':'fig', - 'BROKEN_VIGNETTE':'pbm', - 'FAX_MACHINE':'cals', - 'STRIPES':'exr', - 'PHOTOCOPY':'art', - } - #}}} - return breaktypeTranslate[key] - - def _get_filename (self): - url = self.params.url - name_part = ""; - file_format = ""; - if "?" in url: - url = url.split("?")[0] - if "/" in url: - url = urllib.unquote(url).replace(" ","") - name_part = url.split("/")[-1] - try: - parts = name_part.split(".") - name_part = utils.sanitize(parts[-2]) - file_format = utils.sanitize(parts[-1]) - if not name_part or not file_format: - sys.stderr.write( "Incompatible input file type") - raise; - except Exception as e: - sys.stderr.write( "Incompatible input file type") - raise; - else: - sys.stderr.write( "Incompatible url") - raise; - if (len(name_part) > 20): - name_part = name_part[:-20] - return "{}{}_{}_{}".format(self.tag, name_part, utils.now(), self.params.username or ""), file_format - -#{{{#########rotatefunctions####################################### - def _rotate(self): - cmd = [BIN_CONVERT,self._downloaded_file,"-rotate",self.params.breakangle,"+repage",self._downloaded_file] - self._call_cmd(cmd) - - def _rotate_back(self): - angle = str(360-int(self.params.breakangle)) - cmd = [BIN_CONVERT,self.filepath,"-rotate",angle,"+repage",self.filepath] - self._call_cmd(cmd) - if not self.params.expanded: - cmd = [BIN_CONVERT,self.filepath,"-gravity","Center","-crop","{}x{}+0+0".format( - self.width, self.height),"+repage",self.filepath] - self._call_cmd(cmd) -#}}} - def _subtle_break(self): - #assume the header is no longer than HEADER_OFFSET bytes - breakpoint = random.randint(HEADER_OFFSET, len(self.file_data)) - newfile = "" - newfile = self.file_data[0:breakpoint]; - newfile += SUBTLE_BREAK_MARK; - newfile += self.file_data[breakpoint:] - self.file_data = newfile[0:len(self.file_data)] - - def _extreme_break(self): - increment = len(self.file_data)/10; - i = 0 - newfile = ""; - for b in self.file_data: - if i > HEADER_OFFSET and not (i % increment): - b += EXTREME_BREAK_MARK - newfile += b - i += 1 - self.file_data = newfile[0:len(self.file_data)] - - def _choose_frame(self): - frame = random.choice(self._gif_frames) - cmd = [BIN_CONVERT, frame, self._downloaded_file] - self._call_cmd(cmd) - - def _enforce_jpg(self): - if self.params.breaktype in [ "exr", "bmp", "miff" ] and not re.match(r'jpe?g', self._first_format, re.IGNORECASE): - jpg_file = os.path.join(WORKING_DIR, "{}.{}".format(self.basename, "jpg")) - cmd = [BIN_CONVERT,self._downloaded_file,jpg_file] - self._call_cmd(cmd) - cmd = ["rm",self._downloaded_file] - self._call_cmd(cmd) - - - def _first_conversion(self): - if self._first_format == self.params.breaktype: - self._downloaded_file = self._conversion_file - return - cmd = [BIN_CONVERT, self._downloaded_file, self._conversion_file] - self._call_cmd(cmd) - self.files_created.append(self._conversion_file) - - def _read_data(self, filepath): - f = open(filepath, 'r'); - data = f.read() - f.close() - return data - - def _prepare_filedata(self): - if self._gif_frames: - self._choose_frame() - if self.params.breakangle: - self._rotate() - self._enforce_jpg(); - self._first_conversion(); - self.file_data = self._read_data(self._conversion_file) - if not self.file_data: - sys.stderr.write("Unable to get file_data") - raise; - - def _add_false_data(self, breakmode): - if breakmode == "subtle": - self._subtle_break() - elif breakmode == "extreme": - self._extreme_break() - f = open(self._conversion_file, 'w') - f.write(self.file_data) - f.close(); - -#{{{ SHRINK (UNUSED) - def _shrink(self): - cmd = [ BIN_CONVERT, "-resize", "500x500", self._downloaded_file, self._downloaded_file ]; - self._call_cmd(cmd) -#}}} - - def _final_conversion(self): - cmd = [BIN_CONVERT, self._conversion_file, self.filepath] - self._call_cmd(cmd) - def psd_psbfilepath(num): - return os.path.join(WORKING_DIR, "{}-{}.{}".format(self.basename, num, self.params.finalformat)) - if self.params.breaktype == 'psd': - cmd = ['mv', psd_psbfilepath(1), self.filepath] - self._call_cmd(cmd) - self.files_created.append(psd_psbfilepath(0)) - if self.params.breaktype == 'psb': - cmd = ['mv', psd_psbfilepath(0), self.filepath] - self._call_cmd(cmd) - self.files_created.append(psd_psbfilepath(1)) - - if self.params.breakangle: - self._rotate_back() - - def _cleanup(self): - cmd = ["rm"]+self.files_created - self._call_cmd(cmd) - - def create(self, breakmode=""): - if not breakmode: breakmode = self.params.breakmode - self._prepare_filedata(); - self._add_false_data(breakmode); - self._final_conversion() - self._cleanup() - -if __name__ == "__main__": - TEST_PARAMS = { - "url" : "http://i.asdf.us/im/27/1424816234661dumpfmpfifferkinggr_1424816412_pfifferking.gif" , - "breaktype" : "RGB_WASH", - "finalformat" : "png", - "breakmode" : "extreme", - "breakangle" : "10", - "username" : "donkey", - "expanded" : "false" - } - b = Breaker(**TEST_PARAMS) - b.create(); - print b.filepath diff --git a/config.py b/config.py deleted file mode 100644 index b849b9e..0000000 --- a/config.py +++ /dev/null @@ -1,20 +0,0 @@ -MAX_SIZE = 1024 * 1024 * 1.2 * 1.5 - -#PATHS -BIN_CONVERT = "/usr/bin/convert" -BIN_COMPOSITE = "/usr/bin/composite" -BIN_IDENTIFY = "/usr/bin/identify" -THREEDROTATE = "./bin/3Drotate" -GRID = "./bin/grid" -BEVELBORDER = "./bin/bevelborder" - -DEFAULT_FINALFORMAT = "png"; - - -#mounted on tmpfs -WORKING_DIR = "/var/www/cache" - -#s3 -AWS_ACCESS_KEY_ID = 'AKIAIR53VPBXKJMXZIBA' -AWS_SECRET_ACCESS_KEY = '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' -BUCKET_NAME = 'i.asdf.us' diff --git a/gradient.py b/gradient.py deleted file mode 100755 index 68de55b..0000000 --- a/gradient.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/python2.7 -import re -import time -from subprocess import call -import simplejson as json -import sys -import os -import sha -import lib.utils as utils -from config import * - - -PARAM_LIST = [ - "width", "height", - "color1", "color2", - "stripes", - "stripenumber", "stripeintensity", - "blurriness", - "contrast", - "brightness", "saturation", "hue", - "halftone", - "bevel", "percentbeveled", - "rotate", "flip", "flop", "tilt", - "filetype", - "gradienttype", - "username", -] -DEFAULT_FORMAT = "png" -DEFAULT_COLORS = { - "color1" : "white", - "color2" : "black", -}; - -DEFAULT_WIDTH = "200" -DEFAULT_HEIGHT = "200" -DEFAULT_BEVEL_PERCENT = "12"; - -HALFTONEVALUES = { - "checkeredfade": "h6x6a", - "etchedtransition": "o8x8", - "bendaydots": "h16x16o", - "smallerdots1": "h8x8o", - "smallerdots2": "c7x7w", - "flatstripes": "o2x2", - } - - -class Gradient: - def __init__(self, **kwargs): - self.tag = "imGradient" - self.directory = WORKING_DIR - self.commands = [] - self.filename = "" - self.filepath = "" - - params = {} - for key in PARAM_LIST: - if key in kwargs: - if key in ['color1', 'color2']: - params[key] = utils.is_color(kwargs[key]) - else: - params[key] = utils.sanitize(kwargs[key]) - - if key in ['rotate','tilt','blurriness','stripenumber','stripeintensity']: - params[key] = params[key] if utils.is_number(params[key]) else "" - elif key in ['brightness', 'contrast', 'hue']: - if not utils.is_number(params[key]) or params[key] == "100": params[key] = "" - else: - params[key] = "" - params['width'] = params['width'] if utils.is_number(params['width']) else DEFAULT_WIDTH - params['height'] = params['height'] if utils.is_number(params['height']) else DEFAULT_HEIGHT - params["color1"] = params["color1"] or DEFAULT_COLORS["color1"]; - params["color2"] = params["color2"] or DEFAULT_COLORS["color2"]; - self.params = params - if not self.params['percentbeveled']: self.params['percentbeveled'] = DEFAULT_BEVEL_PERCENT - self._bevelvalues = [ - "flatout", "flatinner", "evenlyframed", "biginner", - "bigouter", "dramaticflatout", "dramaticflatinner", - ] - - def newfilename(self): - return "{}{}-{}_{}_{}.{}".format( - self.tag, - self.params['color1'].replace('#','').replace('(','-').replace(')','-'), - self.params['color2'].replace('#','').replace('(','-').replace(')','-'), - utils.now(), - self.params['username'], - self.params['filetype'] or DEFAULT_FORMAT, - ) - - 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 _build_cmd(self): - cmd = [BIN_CONVERT] - cmd.extend([ - '-size', - "{}x{}".format(self.params["width"],self.params["height"]) - ]) - - if self.params['rotate']: cmd.extend(["-rotate", self.params["rotate"]]) - if self.params['tilt']: cmd.extend(["-distort","SRT",self.params['tilt']]) - if self.params['flip'] == "true": cmd.append("-flip") - if self.params['flop'] == "true": cmd.append("-flop") - if self.params['contrast']: cmd.extend(["-contrast-stretch", self.params['contrast']]) - gradients = { - "canvas" : ["canvas:{}".format(self.params['color1'])], - "radial" : [ - "radial-gradient:{}-{}".format( self.params['color1'], self.params['color2']) - ], - "colorspace" : [ - "-colorspace", - "Gray", - "plasma:{}-{}".format(self.params['color1'], self.params['color2']) - ], - "mirrored" : [ - "plasma:{}-{}".format(self.params['color1'], self.params['color2']), - "\(","+clone","-flop","\)", - "append" - ], - "plasmawash" : [ - "plasma:{}-{}".format(self.params['color1'], self.params['color2']), - "-set","colorspace","HSB" - ], - "gradientwash" : [ - "gradient:{}-{}".format(self.params['color1'], self.params['color2']), - "-set","colorspace","HSB" - ], - "noise" : ["xc:","+noise","Random","-virtual-pixel","tile"] - } - if self.params["gradienttype"] in gradients: - cmd.extend(gradients[self.params['gradienttype']]) - else: - cmd.append("gradient:{}-{}".format(self.params['color1'], self.params['color2'])) - - if self.params['blurriness']: - cmd.extend(["-blur","0x{}".format(self.params["blurriness"]),"-auto-level"]) - - if self.params['stripes'] == "true" and len(self.params['stripenumber']): - cmd.extend(["-function","Sinusoid"]) - if self.params['stripeintensity']: - cmd.append("{},{}".format(self.params['stripenumber'],self.params["stripeintensity"])) - else: - cmd.append(self.params['stripenumber']) - if self.params["halftone"] in HALFTONEVALUES: - cmd.extend([ - "-ordered-dither", - HALFTONEVALUES[self.params["halftone"]] - ]) - cmd += [ - '-modulate', - "{},{},{}".format( - self.params['brightness'] or "100", - self.params['saturation'] or "100", - self.params['hue'] or "100") - ] - cmd.append(os.path.join(self.directory,self.filename)); - self._call_cmd(cmd) - - def _get_bevelvalue(self): - w, h = map(int, (self.params['width'], self.params['height'])) - if h >= w: - bevpercentval = str(int(self.params['percentbeveled'])*0.005*int(h)) - else: - bevpercentval = str(int(self.params['percentbeveled'])*0.005*int(w)) - return { - "flatout": ["-s",bevpercentval,"-m","outer"], - "flatinner": ["-s",bevpercentval,"-m","inner"], - "evenlyframed": ["-s ",bevpercentval,"-m", "split"], - "biginner": ["-s",bevpercentval,"-m","outer","-c","50","-b","red","-a","25"], - "bigouter": ["-s",bevpercentval,"-m","split","-c","50","-b","red","-a","25"], - "dramaticflatout": ["-s",bevpercentval,"-m","outer","-a","25","-b","blue"], - "dramaticflatinner": ["-s",bevpercentval,"-m","outer","-a","25","-b","blue"], - }[self.params['bevel']] - - def _make_bevel(self): - cmd = [BEVELBORDER] - cmd += self._get_bevelvalue() - cmd += [ os.path.join(self.directory,self.filename), os.path.join(self.directory, self.filename) ] - self._call_cmd(cmd) - - def create(self): - self.filename = self.newfilename() - self.filepath = os.path.join(self.directory, self.filename) - self._build_cmd() - if self.params['bevel'] in self._bevelvalues: - self._make_bevel() - -if __name__ == "__main__": - TEST_FORM = { - "width" : "200", - "color1" : "#ffdead", - "color2" : "blue", - "stripes" : "true", - "stripenumber" : "20", - "gradienttype" : "radial", - "stripeintensity" : "20", - "halftone" : "checkeredfade", - "percentbeveled" : "30", - "flip" : "true", - "bevel" : "flatinner", - "rotate" : "20", - "height" : "200", - "filetype" : "jpg", - "username" : "whatever" - } - g = Gradient(**TEST_FORM); - g.create(); - print " ".join(g.commands) - print g.filename diff --git a/imgrid.py b/imgrid.py deleted file mode 100755 index e294066..0000000 --- a/imgrid.py +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/python2.7 -import sys -import re -import os -import simplejson as json -import random -import lib.utils as utils -from config import * -import tempfile - -DEFAULT_HEIGHT = 400 -DEFAULT_WIDTH = 600 -DEFAULT_LINE_COLOR = "silver" - -class Imgrid(): - def __init__(self, **kwargs): - self.tag = "imGrid" - self.files_created = [] - self.commands = []; - self._required_keys = [ -#{{{ required_keys - "width", - "height", - "linethickness", - "opacity", - "linecolor", - "spacing", - "vlines", - "hlines", - "shadow", - "bgimage", - "bgcolor", - "imageinstead", - "planebgcolor", - "planebgimage", - "swing", - "tilt", - "roll", - "zoom", - "skycolor", - "transition", - "trim", - "format", - "username" -#}}} - ] - - #Work out params ... - #note, tmpfile lib is pretty much useless here, given imagemagick's behavior with gifs (it splits them) etc... - #instead we're just making our own in /var/www/cache (tmpfs mounted there) - self.params = {} - for k in self._required_keys: - if k in kwargs: - if k in [ 'bgimage', 'planebgimage', 'imageinstead' ] 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']) - frames = utils.gif_frames(self.params[k]['path']) - if len(frames) > 1: - self.params[k]['path'] = random.choice(frames) - - except Exception: - sys.stderr.write(str(e)) - raise Exception ("BAD PARAMS"); - elif k in [ 'skycolor', 'bgcolor', 'planebgcolor','linecolor' ]: - try: - self.params[k] = is_color(params[k]) - except Exception: - raise Exception("Unable to process color for:\n{}".format(k)) - elif k == 'opacity': - self.params[k] = str(float(params[k])) - elif k == 'zoom': - self.params[k] = int(float(params[k])) - else: - self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k])) - else: - self.params[k] = None; - - self.params = utils.dotdict(self.params) - - self.basename = self._get_filename(); - - if not self.params.finalformat: - self.params.finalformat = DEFAULT_FINALFORMAT - self.filename = "{}.{}".format(self.basename, self.params.finalformat) - #final filepath is stored in self.filepath - self.filepath = os.path.join(WORKING_DIR, self.filename) - - def _get_filename(self): - return "{}_{}_{}".format( - self.tag, - utils.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 _make_tempname(self, s): - return "IMGRIDTMP{}{}".format(utils.now(), s); - - - #makes a canvas file...step 1 (if not bgimage) - def _make_canvas(self): - dimensions = "{}x{}".format( - self.params.width or DEFAULT_WIDTH, - self.params.height or DEFAULT_HEIGHT - ) - if self.params.bgimage: - return - bgcolor = "xc:{}".format(self.params.bgcolor or 'transparent') - cmd = [ BIN_CONVERT, "-size", dimensions, bgcolor, self.filepath ] - self._call_cmd(cmd) - - #2nd step-- run grid - def _grid_command(self): - cmd = [GRID] - if self.params.spacing: - if self.params.vlines: - width = 2 * int(self.params.width or DEFAULT_WIDTH) - cmd += ["-s","{},{}".format(self.params.spacing,width)] - elif self.params.hlines: - height = 2 * int(self.params.height or DEFAULT_HEIGHT) - cmd += ["-s", "{},{}".format(height,self.params.spacing)] - else: - cmd += ["-s",self.params.spacing] - cmd += [ "-c", self.params.linecolor or DEFAULT_LINE_COLOR] - if self.params.linethickness: cmd += ['-t',self.params.linethickness] - if self.params.opacity: cmd += ['-o',self.params.opacity] - cmd += [ self.filepath, self.filepath ] - self._call_cmd(cmd) - - def _shadow_cmd(self): - #convert 1.png \( +clone -background black -shadow 110x1+9+9 \) +swap -background none -layers merge +repage 2.png - cmd = [ - BIN_CONVERT, - self.filepath, - "(","+clone","-background","black","-shadow","100x2+20+10",")", - "+swap","-background","none","-layers","merge","+repage" , - self.filepath - ] - self._call_cmd(cmd) - - - def _threed_rotate_cmd (self): - #3rd step--run 3Drotate - cmd = [THREEDROTATE] - if self.params.swing: cmd += ["pan={}".format(self.params.swing)] - if self.params.tilt: cmd += ["tilt={}".format(self.params.tilt)] - if self.params.roll: cmd += ["roll={}".format(self.params.roll)] - if self.params.zoom: - cmd += ["zoom={}".format(self.params.zoom)] - if cmd == [THREEDROTATE]: #if nothing has been added - return - if self.params.planebgcolor and not self.params.planebgimage: - cmd += ["bgcolor={}".format(self.params.planebgcolor)] - else: - cmd += ["bgcolor=none"] - cmd += ["skycolor={}".format(self.params.skycolor or 'none')] - if self.params.transition: cmd += ["vp={}".format(self.params.transition)] - cmd += [ self.filepath, self.filepath ] - self._call_cmd(cmd) - - - def _trim_cmd (self): - cmd = [BIN_CONVERT, self.filepath, "-trim", "+repage", self.filepath] - self._call_cmd(cmd) - - def _prepare_gridimage(self, image): - if image['mimetype'] != 'png': - cmd = [BIN_CONVERT, image['path'], self.filepath] - else: - cmd = ['cp', image['path'], self.filepath] - self._call_cmd(cmd) - - - def _overlay_planebgimage(self): - cmd = [ - BIN_COMPOSITE, - "-compose", "Dst_Over", "-gravity", "center", - self.params.planebgimage["path"], - self.filepath, - self.filepath - ] - self._call_cmd(cmd) - - def _cleanup(self): - if not len(self.files_created): - pass - cmd = ["rm", "-f"] + self.files_created - self._call_cmd(cmd) - - def create(self): - if self.params.bgimage: - self._prepare_gridimage(self.params.bgimage) - self._grid_command() - elif self.params.imageinstead: - self._prepare_gridimage(self.params.imageinstead) - else: - self._make_canvas() - self._grid_command() - if self.params.shadow: self._shadow_cmd() - self._threed_rotate_cmd() - if self.params.planebgimage: self._overlay_planebgimage() - if self.params.trim: self._trim_cmd() - self._cleanup() - -if __name__ == "__main__": - g = Imgrid(**{ - 'bgimage' : 'http://i.asdf.us/im/1a/imBreak_1424909483_xx_abridged___.gif', - 'planebgimage' : 'http://i.imgur.com/FICZtph.png', - 'tilt' : '30', - 'spacing' : '30', - 'hlines' : 'true', - 'roll' : '30', - 'shadow' : 'true', - 'trim' : 'true' - }) - g.create() - print g.commands diff --git a/lib/__init__.py b/lib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/lib/db.py b/lib/db.py deleted file mode 100755 index 2570b4f..0000000 --- a/lib/db.py +++ /dev/null @@ -1,31 +0,0 @@ -import MySQLdb -USER = "asdfus" -PASSWORD = "gTYgT&M6q" -DATABASE = "asdfus" - -class db: - def __init__ (self): - self.conn = None - self.cursor = None - self.connect() - - def connect (self): - self.conn = MySQLdb.connect (host = "localhost", - user = USER, - passwd = PASSWORD, - db = DATABASE - ) - self.cursor = self.conn.cursor () - - def execute (self,sql,args=()): - try: - self.cursor.execute(sql,args) - except MySQLdb.Error, e: - print "Error %d: %s" % (e.args[0], e.args[1]) - # sys.exit (1) - self.connect() - self.cursor.execute(sql,args) - - def lastinsertid (self): - return DB.conn.insert_id() - diff --git a/lib/utils.py b/lib/utils.py deleted file mode 100644 index a662869..0000000 --- a/lib/utils.py +++ /dev/null @@ -1,122 +0,0 @@ -import re -from config import * -import time -import urllib -import urllib2 -import sys -from subprocess import Popen,PIPE,call -Request = urllib2.Request -urlencode = urllib.urlencode -urlopen = urllib2.urlopen - -def call_cmd(cmd, error=""): - try: - call(cmd) - except Exception as e: - raise (str(e)) - -def is_color(s): - if s == "": - return "transparent" - if re.match('(rgba?\([0-9]+,[0-9]+,[0-9]+\))|([a-zA-Z]+)|(\#[A-Ha-h0-9]+)', s): - return s.replace(' ', ''); - else: - sys.stderr.write("Not a color: {}\n".format(s)) - raise ValueError - -def dimensions (filepath): - #works in lieu of a mimetype check (it reads the header as well) - ident = (Popen([BIN_IDENTIFY, filepath], stdout=PIPE).communicate()[0]).split(" ") - return ident[2].split("x") - -def is_number(s): - try: - return int(s) - except (ValueError, TypeError): - return False - -def bool_correct(s): - if re.match(r'^false$', s, re.IGNORECASE): - return False - elif re.match(r'^true$', s, re.IGNORECASE): - return True - else: - return s - -class dotdict(dict): - """dot.notation access to dictionary attributes""" - def __getattr__(self, attr): - return self.get(attr) - __setattr__= dict.__setitem__ - __delattr__= dict.__delitem__ - -def get_mimetype(f): - try: - mimetype = Popen( - [BIN_IDENTIFY, f], stdout=PIPE - ).communicate()[0].split(" ")[1].lower() - return mimetype - except Exception as e: - sys.stderr.write("couldn't determine mimetype") - sys.stderr.write(str(e)) - raise; - -def sanitize (str): - return re.sub(r'\W+', '', str) - -def now(): - return int(time.time()) - -def browser_request (url, data=None): - headers = { - 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', - 'Accept': '*/*', - } - try: - req = Request(url, data, headers) - response = urlopen(req) - except IOError, e: - if hasattr(e, 'code'): - sys.stderr.write( '%s - ERROR %s' % (url, e.code) ) - raise; - return None - else: - return response - -def download(url, destination, max_size=MAX_SIZE): - response = browser_request(url, None) - rawimg = response.read() - if len(rawimg) == 0: - sys.stderr.write("got zero-length file") - raise; - if len(rawimg) > max_size: - sys.stderr.write("file too big: max size {} KB / {} is {} KB".format( - str(MAX_SIZE/1024), - destination, - str(len(rawimg)/1024) - )) - raise; - f = open(destination, "w") - f.write(rawimg) - f.close() - -def file_size (filepath): - try: - return os.stat(file)[6] - except Exception as e: - sys.stderr.write("IMGRID couldn't determine file size") - sys.stderr.write(str(e)) - raise; - -def gif_frames(filepath): - try: - info = Popen([BIN_IDENTIFY,filepath], stdout=PIPE).communicate()[0] - frames = filter((lambda x: x), map( - (lambda x: x.split(" ")[0]), - (info).split('\n') - )) - return frames - except Exception as e: - sys.stderr.write("IMGRID couldn't get gif frames") - sys.stderr.write(str(e)) - raise; diff --git a/pattern.py b/pattern.py deleted file mode 100755 index 5470004..0000000 --- a/pattern.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/python2.7 -import os -import sys -import random -import re -import urllib -from config import * -import lib.utils as utils - -import simplejson as json -from PIL import Image -import uuid - -FUSE_MODE="Pin_Light" - -class Pattern: - def __init__(self, **kwargs): - self.params = {} - self.tag = "imPattern"; - self._pid = str(os.getpid()) - self.commands = []; - self.height = "" - self.width = "" - self._required_keys = [ - #FIXME change name to username in js - #FIXME change js api - "pattern_url", - "pattern_data", - "username", - "image_url", - ] - self.files_created = [] - for k in self._required_keys: - if k in kwargs: - if k in [ 'pattern_url', 'image_url' ]: - self.params[k] = kwargs[k] - elif k == 'pattern_data': - self.params[k] = kwargs[k] #FIXME add conversion data - else: - self.params[k] = utils.sanitize(kwargs[k]) - else: - self.params[k] = False; - - if not self.params['image_url']: - sys.stderr.write('no image url'); - raise ValueError - self.params = utils.dotdict(self.params) - - self.basename, self._format = self._get_filename(); - #FIXME omit file extension for downloaded files - self._downloaded_file = os.path.join(WORKING_DIR, "IMPATTERNTMP_DL{}_{}.{}".format(self.basename, self._pid, self._format)) # same here - #lets go back to this in a second - self._pattern_file = os.path.join(WORKING_DIR, "IMPATTERNTMP_PTN{}_{}.{}".format(self.basename, self._pid, self._format)) # this - - self._download(self.params.image_url, self._downloaded_file) - - self.width, self.height = utils.dimensions(self._downloaded_file) # same here - - self.filename = "{}.{}".format(self.basename, self._format) - self.filepath = os.path.join(WORKING_DIR, self.filename) - - if self.params['pattern_url']: - self._download(self.params['pattern_url'], self._pattern_file) - elif self.params['pattern_data']: - self._from_pattern_data() - else: - sys.stderr.write("pattern must be supplied as json array or as a png url") - raise ValueError; - - def _download(self, url, dest): - try: - utils.download(url, dest) - self.files_created.append(dest) - except Exception as e: - sys.stderr.write(str(e)) - raise; - - 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 _from_pattern_data(self): - def boolToColor(boolean): - if boolean: - return (0,0,0,255); - else: - return (255,255,255,255) - specs = json.loads(self.params.pattern_data); - if int(specs['width']) > 100 or int(specs['height']) > 100: - raise ValueError - sys.stderr.write("height and width need to be less than 100 px") - img = Image.new('RGBA', (int(specs['width']), int(specs['height']))); - pixels = img.load(); - for i in range(0, len(specs['matrix'])): - for j in range(0, len(specs['matrix'][i])): - pixels[j,i] = boolToColor(int(specs['matrix'][i][j])); - - img.save(self._pattern_file, "PNG") - - - def _get_filename (self): - url = self.params.image_url - name_part = ""; - file_format = ""; - if "?" in url: - url = url.split("?")[0] - if "/" in url: - url = urllib.unquote(url).replace(" ","") - name_part = url.split("/")[-1] - try: - parts = name_part.split(".") - name_part = utils.sanitize(parts[-2]) - file_format = utils.sanitize(parts[-1]) - if not name_part or not file_format: - sys.stderr.write( "Incompatible input file type") - raise; - except Exception as e: - sys.stderr.write( "Incompatible input file type") - raise; - else: - sys.stderr.write( "Incompatible url") - raise; - if (len(name_part) > 20): - name_part = name_part[:-20] - return "{}{}_{}_{}".format(self.tag, name_part, utils.now(), self.params.username or ""), file_format - - def _cleanup(self): - cmd = ["rm"]+self.files_created - self._call_cmd(cmd) - - #first step - def _make_canvas(self): - cmd = [BIN_CONVERT,"-size",self.width+"x"+self.height,"canvas:transparent", self.filepath] - self._call_cmd(cmd) - - #second step use the Canvas as a background - def _make_mask(self): - #tile the pattern pattern on the canvas - cmd = [BIN_COMPOSITE,"-tile", self._pattern_file, self.filepath, self.filepath]; - self._call_cmd(cmd) - #fuse the tiled file to create a mask - #convert thebg.gif -compose Dst_In null: thefile.gif -matte -layers composite new.gif - cmd = [BIN_CONVERT, self.filepath, "-compose", "Dst_In", "null:", - self._downloaded_file, "-matte", "-layers", "composite", self.filepath] - self._call_cmd(cmd) - - #third step - def _fuse_mask(self, fuse_mode=FUSE_MODE): - cmd = [BIN_CONVERT, "-dispose", "2", self.filepath, "null:", - self._downloaded_file, "-matte", "-compose", fuse_mode, "-layers", "composite", - self.filepath] - self._call_cmd(cmd) - - def create(self): - self._make_canvas(); - self._make_mask() - self._fuse_mask(); - -if __name__ == "__main__": - TEST_PARAMS = { - # "pattern_url" : "http://asdf.us/impattern/patterns/1.png", - "pattern_data" : '{"matrix":[["0","0","0","0","0","1","0","0","0","0"],["0","0","0","0","1","1","1","0","0","0"],["0","0","1","1","1","0","1","0","0","0"],["0","1","1","0","0","0","0","0","0","0"],["0","1","0","0","1","0","0","0","0","0"],["0","1","0","0","1","0","0","0","1","0"],["0","1","0","0","1","1","0","0","1","0"],["0","1","0","0","0","1","1","1","1","0"],["0","1","1","1","1","0","0","0","0","0"],["0","0","0","0","1","0","0","0","0","0"]],"width":"10","height":"10"}', - # "username" : "garfield", - "image_url" : "http://i.asdf.us/im/be/PinkHijab_1425078647_reye.gif", - } - p = Pattern(**TEST_PARAMS) - p.create() - diff --git a/pb/__init__.py b/pb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pb/breaker.py b/pb/breaker.py new file mode 100755 index 0000000..c982b14 --- /dev/null +++ b/pb/breaker.py @@ -0,0 +1,268 @@ +#!/usr/bin/python2.7 +import os +import sys +import random +import re +import pb.lib.utils as utils +import urllib +from pb.config import * + +DEFAULT_FINALFORMAT = "png"; +SUBTLE_BREAK_MARK = 'pron' +EXTREME_BREAK_MARK = 'sugar' + +HEADER_OFFSET = 2000 + +# 'CLASSIC':'jpg', +# 'REDUX':'pcds', +# 'BLURRY_BREAK':'viff', +# 'BLURRY_BREAK_2':'mat', +# 'SWIPE':'miff', +# 'RGB_WASH':'psd', +# 'RGB_WASH_2':'psb', +# 'NOISY_BREAK':'palm', +# 'NOISY_BREAK_2':'fig', +# 'BROKEN_VIGNETTE':'pbm', +# 'FAX_MACHINE':'cals', +# 'STRIPES':'exr', +# 'PHOTOCOPY':'art', + +class Breaker(): + def __init__(self, **kwargs): + self.params = {} + self.tag = "imBreak" + self.commands = []; + self._required_keys = [ + "url", + "breaktype", + "finalformat", + "breakmode", + "breakangle", + "username", + "expanded" + ] + self.now = utils.now() + self.files_created = [] + for k in self._required_keys: + if k in kwargs: + if k == 'breaktype': + self.params['breaktype'] = self._get_breaktype(kwargs[k]) + elif k == 'url': + self.params[k] = kwargs[k] + else: + self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k])) + else: + self.params[k] = False; + + + self.params = utils.dotdict(self.params) + + self.basename, self._first_format = self._get_filename(); + self._downloaded_file = os.path.join(WORKING_DIR, "IMBREAKTMP{}.{}".format(self.basename, self._first_format)) # same here + + try: + utils.download(self.params.url, self._downloaded_file) + self.files_created.append(self._downloaded_file) + except Exception as e: + sys.stderr.write(str(e)) + raise; + self._gif_frames = utils.gif_frames(self._downloaded_file) + self._gif_frames = self._gif_frames if len(self._gif_frames) > 1 else False + self.width, self.height = utils.dimensions(self._downloaded_file) # same here + + if not self.params.finalformat: + self.params.finalformat = DEFAULT_FINALFORMAT + if self._gif_frames: + self.params.finalformat = 'gif' + if self.params.breaktype == 'miff': + self.params.finalformat = 'jpg' + self.params.breakmode = 'subtle' + #final filepath is stored in self.filepath + self.filename = "{}.{}".format(self.basename, self.params.finalformat) + self.filepath = os.path.join(WORKING_DIR, self.filename) + self._conversion_file = os.path.join(WORKING_DIR, "IMBREAKTMP{}.{}".format(self.basename, self.params.breaktype)) # this + + + def _call_cmd(self, cmd, error=""): + try: + utils.call_cmd(cmd) + self.commands.append(" ".join(cmd)); + except Exception: + raise Exception("Unable to call cmd {}".format(str(cmd))) + + def _get_breaktype(self, key): + #{{{ conversion table + breaktypeTranslate = { + 'CLASSIC':'jpg', + 'REDUX':'pcds', + 'BLURRY_BREAK':'viff', + 'BLURRY_BREAK_2':'mat', + 'SWIPE':'miff', + 'RGB_WASH':'psd', + 'RGB_WASH_2':'psb', + 'NOISY_BREAK':'palm', + 'NOISY_BREAK_2':'fig', + 'BROKEN_VIGNETTE':'pbm', + 'FAX_MACHINE':'cals', + 'STRIPES':'exr', + 'PHOTOCOPY':'art', + } + #}}} + return breaktypeTranslate[key] + + def _get_filename (self): + url = self.params.url + name_part = ""; + file_format = ""; + if "?" in url: + url = url.split("?")[0] + if "/" in url: + url = urllib.unquote(url).replace(" ","") + name_part = url.split("/")[-1] + try: + parts = name_part.split(".") + name_part = utils.sanitize(parts[-2]) + file_format = utils.sanitize(parts[-1]) + if not name_part or not file_format: + sys.stderr.write( "Incompatible input file type") + raise; + except Exception as e: + sys.stderr.write( "Incompatible input file type") + raise; + else: + sys.stderr.write( "Incompatible url") + raise; + if (len(name_part) > 20): + name_part = name_part[:-20] + return "{}{}_{}_{}".format(self.tag, name_part, self.now, self.params.username or ""), file_format + +#{{{#########rotatefunctions####################################### + def _rotate(self): + cmd = [BIN_CONVERT,self._downloaded_file,"-rotate",self.params.breakangle,"+repage",self._downloaded_file] + self._call_cmd(cmd) + + def _rotate_back(self): + angle = str(360-int(self.params.breakangle)) + cmd = [BIN_CONVERT,self.filepath,"-rotate",angle,"+repage",self.filepath] + self._call_cmd(cmd) + if not self.params.expanded: + cmd = [BIN_CONVERT,self.filepath,"-gravity","Center","-crop","{}x{}+0+0".format( + self.width, self.height),"+repage",self.filepath] + self._call_cmd(cmd) +#}}} + def _subtle_break(self): + #assume the header is no longer than HEADER_OFFSET bytes + breakpoint = random.randint(HEADER_OFFSET, len(self.file_data)) + newfile = "" + newfile = self.file_data[0:breakpoint]; + newfile += SUBTLE_BREAK_MARK; + newfile += self.file_data[breakpoint:] + self.file_data = newfile[0:len(self.file_data)] + + def _extreme_break(self): + increment = len(self.file_data)/10; + i = 0 + newfile = ""; + for b in self.file_data: + if i > HEADER_OFFSET and not (i % increment): + b += EXTREME_BREAK_MARK + newfile += b + i += 1 + self.file_data = newfile[0:len(self.file_data)] + + def _choose_frame(self): + frame = random.choice(self._gif_frames) + cmd = [BIN_CONVERT, frame, self._downloaded_file] + self._call_cmd(cmd) + + def _enforce_jpg(self): + if self.params.breaktype in [ "exr", "bmp", "miff" ] and not re.match(r'jpe?g', self._first_format, re.IGNORECASE): + jpg_file = os.path.join(WORKING_DIR, "{}.{}".format(self.basename, "jpg")) + cmd = [BIN_CONVERT,self._downloaded_file,jpg_file] + self._call_cmd(cmd) + cmd = ["rm",self._downloaded_file] + self._call_cmd(cmd) + + + def _first_conversion(self): + if self._first_format == self.params.breaktype: + self._downloaded_file = self._conversion_file + return + cmd = [BIN_CONVERT, self._downloaded_file, self._conversion_file] + self._call_cmd(cmd) + self.files_created.append(self._conversion_file) + + def _read_data(self, filepath): + f = open(filepath, 'r'); + data = f.read() + f.close() + return data + + def _prepare_filedata(self): + if self._gif_frames: + self._choose_frame() + if self.params.breakangle: + self._rotate() + self._enforce_jpg(); + self._first_conversion(); + self.file_data = self._read_data(self._conversion_file) + if not self.file_data: + sys.stderr.write("Unable to get file_data") + raise; + + def _add_false_data(self, breakmode): + if breakmode == "subtle": + self._subtle_break() + elif breakmode == "extreme": + self._extreme_break() + f = open(self._conversion_file, 'w') + f.write(self.file_data) + f.close(); + +#{{{ SHRINK (UNUSED) + def _shrink(self): + cmd = [ BIN_CONVERT, "-resize", "500x500", self._downloaded_file, self._downloaded_file ]; + self._call_cmd(cmd) +#}}} + + def _final_conversion(self): + cmd = [BIN_CONVERT, self._conversion_file, self.filepath] + self._call_cmd(cmd) + def psd_psbfilepath(num): + return os.path.join(WORKING_DIR, "{}-{}.{}".format(self.basename, num, self.params.finalformat)) + if self.params.breaktype == 'psd': + cmd = ['mv', psd_psbfilepath(1), self.filepath] + self._call_cmd(cmd) + self.files_created.append(psd_psbfilepath(0)) + if self.params.breaktype == 'psb': + cmd = ['mv', psd_psbfilepath(0), self.filepath] + self._call_cmd(cmd) + self.files_created.append(psd_psbfilepath(1)) + + if self.params.breakangle: + self._rotate_back() + + def _cleanup(self): + cmd = ["rm"]+self.files_created + self._call_cmd(cmd) + + def create(self, breakmode=""): + if not breakmode: breakmode = self.params.breakmode + self._prepare_filedata(); + self._add_false_data(breakmode); + self._final_conversion() + self._cleanup() + +if __name__ == "__main__": + TEST_PARAMS = { + "url" : "http://i.asdf.us/im/27/1424816234661dumpfmpfifferkinggr_1424816412_pfifferking.gif" , + "breaktype" : "RGB_WASH", + "finalformat" : "png", + "breakmode" : "extreme", + "breakangle" : "10", + "username" : "donkey", + "expanded" : "false" + } + b = Breaker(**TEST_PARAMS) + b.create(); + print b.filepath diff --git a/pb/config.py b/pb/config.py new file mode 100644 index 0000000..b849b9e --- /dev/null +++ b/pb/config.py @@ -0,0 +1,20 @@ +MAX_SIZE = 1024 * 1024 * 1.2 * 1.5 + +#PATHS +BIN_CONVERT = "/usr/bin/convert" +BIN_COMPOSITE = "/usr/bin/composite" +BIN_IDENTIFY = "/usr/bin/identify" +THREEDROTATE = "./bin/3Drotate" +GRID = "./bin/grid" +BEVELBORDER = "./bin/bevelborder" + +DEFAULT_FINALFORMAT = "png"; + + +#mounted on tmpfs +WORKING_DIR = "/var/www/cache" + +#s3 +AWS_ACCESS_KEY_ID = 'AKIAIR53VPBXKJMXZIBA' +AWS_SECRET_ACCESS_KEY = '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' +BUCKET_NAME = 'i.asdf.us' diff --git a/pb/gradient.py b/pb/gradient.py new file mode 100755 index 0000000..724b37c --- /dev/null +++ b/pb/gradient.py @@ -0,0 +1,216 @@ +#!/usr/bin/python2.7 +import re +import time +from subprocess import call +import simplejson as json +import sys +import os +import sha +import pb.lib.utils as utils +from pb.config import * + + +PARAM_LIST = [ + "width", "height", + "color1", "color2", + "stripes", + "stripenumber", "stripeintensity", + "blurriness", + "contrast", + "brightness", "saturation", "hue", + "halftone", + "bevel", "percentbeveled", + "rotate", "flip", "flop", "tilt", + "filetype", + "gradienttype", + "username", +] +DEFAULT_FORMAT = "png" +DEFAULT_COLORS = { + "color1" : "white", + "color2" : "black", +}; + +DEFAULT_WIDTH = "200" +DEFAULT_HEIGHT = "200" +DEFAULT_BEVEL_PERCENT = "12"; + +HALFTONEVALUES = { + "checkeredfade": "h6x6a", + "etchedtransition": "o8x8", + "bendaydots": "h16x16o", + "smallerdots1": "h8x8o", + "smallerdots2": "c7x7w", + "flatstripes": "o2x2", + } + + +class Gradient: + def __init__(self, **kwargs): + self.tag = "imGradient" + self.directory = WORKING_DIR + self.commands = [] + self.filename = "" + self.filepath = "" + self.now = utils.now() + + params = {} + for key in PARAM_LIST: + if key in kwargs: + if key in ['color1', 'color2']: + params[key] = utils.is_color(kwargs[key]) + else: + params[key] = utils.sanitize(kwargs[key]) + + if key in ['rotate','tilt','blurriness','stripenumber','stripeintensity']: + params[key] = params[key] if utils.is_number(params[key]) else "" + elif key in ['brightness', 'contrast', 'hue']: + if not utils.is_number(params[key]) or params[key] == "100": params[key] = "" + else: + params[key] = "" + params['width'] = params['width'] if utils.is_number(params['width']) else DEFAULT_WIDTH + params['height'] = params['height'] if utils.is_number(params['height']) else DEFAULT_HEIGHT + params["color1"] = params["color1"] or DEFAULT_COLORS["color1"]; + params["color2"] = params["color2"] or DEFAULT_COLORS["color2"]; + self.params = params + if not self.params['percentbeveled']: self.params['percentbeveled'] = DEFAULT_BEVEL_PERCENT + self._bevelvalues = [ + "flatout", "flatinner", "evenlyframed", "biginner", + "bigouter", "dramaticflatout", "dramaticflatinner", + ] + + def newfilename(self): + return "{}{}-{}_{}_{}.{}".format( + self.tag, + self.params['color1'].replace('#','').replace('(','-').replace(')','-'), + self.params['color2'].replace('#','').replace('(','-').replace(')','-'), + self.now, + self.params['username'], + self.params['filetype'] or DEFAULT_FORMAT, + ) + + 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 _build_cmd(self): + cmd = [BIN_CONVERT] + cmd.extend([ + '-size', + "{}x{}".format(self.params["width"],self.params["height"]) + ]) + + if self.params['rotate']: cmd.extend(["-rotate", self.params["rotate"]]) + if self.params['tilt']: cmd.extend(["-distort","SRT",self.params['tilt']]) + if self.params['flip'] == "true": cmd.append("-flip") + if self.params['flop'] == "true": cmd.append("-flop") + if self.params['contrast']: cmd.extend(["-contrast-stretch", self.params['contrast']]) + gradients = { + "canvas" : ["canvas:{}".format(self.params['color1'])], + "radial" : [ + "radial-gradient:{}-{}".format( self.params['color1'], self.params['color2']) + ], + "colorspace" : [ + "-colorspace", + "Gray", + "plasma:{}-{}".format(self.params['color1'], self.params['color2']) + ], + "mirrored" : [ + "plasma:{}-{}".format(self.params['color1'], self.params['color2']), + "\(","+clone","-flop","\)", + "append" + ], + "plasmawash" : [ + "plasma:{}-{}".format(self.params['color1'], self.params['color2']), + "-set","colorspace","HSB" + ], + "gradientwash" : [ + "gradient:{}-{}".format(self.params['color1'], self.params['color2']), + "-set","colorspace","HSB" + ], + "noise" : ["xc:","+noise","Random","-virtual-pixel","tile"] + } + if self.params["gradienttype"] in gradients: + cmd.extend(gradients[self.params['gradienttype']]) + else: + cmd.append("gradient:{}-{}".format(self.params['color1'], self.params['color2'])) + + if self.params['blurriness']: + cmd.extend(["-blur","0x{}".format(self.params["blurriness"]),"-auto-level"]) + + if self.params['stripes'] == "true" and len(self.params['stripenumber']): + cmd.extend(["-function","Sinusoid"]) + if self.params['stripeintensity']: + cmd.append("{},{}".format(self.params['stripenumber'],self.params["stripeintensity"])) + else: + cmd.append(self.params['stripenumber']) + if self.params["halftone"] in HALFTONEVALUES: + cmd.extend([ + "-ordered-dither", + HALFTONEVALUES[self.params["halftone"]] + ]) + cmd += [ + '-modulate', + "{},{},{}".format( + self.params['brightness'] or "100", + self.params['saturation'] or "100", + self.params['hue'] or "100") + ] + cmd.append(os.path.join(self.directory,self.filename)); + self._call_cmd(cmd) + + def _get_bevelvalue(self): + w, h = map(int, (self.params['width'], self.params['height'])) + if h >= w: + bevpercentval = str(int(self.params['percentbeveled'])*0.005*int(h)) + else: + bevpercentval = str(int(self.params['percentbeveled'])*0.005*int(w)) + return { + "flatout": ["-s",bevpercentval,"-m","outer"], + "flatinner": ["-s",bevpercentval,"-m","inner"], + "evenlyframed": ["-s ",bevpercentval,"-m", "split"], + "biginner": ["-s",bevpercentval,"-m","outer","-c","50","-b","red","-a","25"], + "bigouter": ["-s",bevpercentval,"-m","split","-c","50","-b","red","-a","25"], + "dramaticflatout": ["-s",bevpercentval,"-m","outer","-a","25","-b","blue"], + "dramaticflatinner": ["-s",bevpercentval,"-m","outer","-a","25","-b","blue"], + }[self.params['bevel']] + + def _make_bevel(self): + cmd = [BEVELBORDER] + cmd += self._get_bevelvalue() + cmd += [ os.path.join(self.directory,self.filename), os.path.join(self.directory, self.filename) ] + self._call_cmd(cmd) + + def create(self): + self.filename = self.newfilename() + self.filepath = os.path.join(self.directory, self.filename) + self._build_cmd() + if self.params['bevel'] in self._bevelvalues: + self._make_bevel() + +if __name__ == "__main__": + TEST_FORM = { + "width" : "200", + "color1" : "#ffdead", + "color2" : "blue", + "stripes" : "true", + "stripenumber" : "20", + "gradienttype" : "radial", + "stripeintensity" : "20", + "halftone" : "checkeredfade", + "percentbeveled" : "30", + "flip" : "true", + "bevel" : "flatinner", + "rotate" : "20", + "height" : "200", + "filetype" : "jpg", + "username" : "whatever" + } + g = Gradient(**TEST_FORM); + g.create(); + print " ".join(g.commands) + print g.filename diff --git a/pb/imgrid.py b/pb/imgrid.py new file mode 100755 index 0000000..f75ec4a --- /dev/null +++ b/pb/imgrid.py @@ -0,0 +1,231 @@ +#!/usr/bin/python2.7 +import sys +import re +import os +import simplejson as json +import random +import pb.lib.utils as utils +from pb.config import * +import tempfile + +DEFAULT_HEIGHT = 400 +DEFAULT_WIDTH = 600 +DEFAULT_LINE_COLOR = "silver" + +class Imgrid(): + def __init__(self, **kwargs): + self.tag = "imGrid" + self.files_created = [] + self.commands = []; + self._required_keys = [ +#{{{ required_keys + "width", + "height", + "linethickness", + "opacity", + "linecolor", + "spacing", + "vlines", + "hlines", + "shadow", + "bgimage", + "bgcolor", + "imageinstead", + "planebgcolor", + "planebgimage", + "swing", + "tilt", + "roll", + "zoom", + "skycolor", + "transition", + "trim", + "format", + "username" +#}}} + ] + self.now = utils.now() + + #Work out params ... + #note, tmpfile lib is pretty much useless here, given imagemagick's behavior with gifs (it splits them) etc... + #instead we're just making our own in /var/www/cache (tmpfs mounted there) + self.params = {} + for k in self._required_keys: + if k in kwargs: + if k in [ 'bgimage', 'planebgimage', 'imageinstead' ] 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']) + frames = utils.gif_frames(self.params[k]['path']) + if len(frames) > 1: + self.params[k]['path'] = random.choice(frames) + + except Exception: + sys.stderr.write(str(e)) + raise Exception ("BAD PARAMS"); + elif k in [ 'skycolor', 'bgcolor', 'planebgcolor','linecolor' ]: + try: + self.params[k] = is_color(params[k]) + except Exception: + raise Exception("Unable to process color for:\n{}".format(k)) + elif k == 'opacity': + self.params[k] = str(float(params[k])) + elif k == 'zoom': + self.params[k] = int(float(params[k])) + else: + self.params[k] = utils.bool_correct(utils.sanitize(kwargs[k])) + else: + self.params[k] = None; + + self.params = utils.dotdict(self.params) + + self.basename = self._get_filename(); + + if not self.params.finalformat: + self.params.finalformat = DEFAULT_FINALFORMAT + self.filename = "{}.{}".format(self.basename, self.params.finalformat) + #final filepath is stored in self.filepath + self.filepath = os.path.join(WORKING_DIR, self.filename) + + 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 _make_tempname(self, s): + return "IMGRIDTMP{}{}".format(self.now, s); + + + #makes a canvas file...step 1 (if not bgimage) + def _make_canvas(self): + dimensions = "{}x{}".format( + self.params.width or DEFAULT_WIDTH, + self.params.height or DEFAULT_HEIGHT + ) + if self.params.bgimage: + return + bgcolor = "xc:{}".format(self.params.bgcolor or 'transparent') + cmd = [ BIN_CONVERT, "-size", dimensions, bgcolor, self.filepath ] + self._call_cmd(cmd) + + #2nd step-- run grid + def _grid_command(self): + cmd = [GRID] + if self.params.spacing: + if self.params.vlines: + width = 2 * int(self.params.width or DEFAULT_WIDTH) + cmd += ["-s","{},{}".format(self.params.spacing,width)] + elif self.params.hlines: + height = 2 * int(self.params.height or DEFAULT_HEIGHT) + cmd += ["-s", "{},{}".format(height,self.params.spacing)] + else: + cmd += ["-s",self.params.spacing] + cmd += [ "-c", self.params.linecolor or DEFAULT_LINE_COLOR] + if self.params.linethickness: cmd += ['-t',self.params.linethickness] + if self.params.opacity: cmd += ['-o',self.params.opacity] + cmd += [ self.filepath, self.filepath ] + self._call_cmd(cmd) + + def _shadow_cmd(self): + #convert 1.png \( +clone -background black -shadow 110x1+9+9 \) +swap -background none -layers merge +repage 2.png + cmd = [ + BIN_CONVERT, + self.filepath, + "(","+clone","-background","black","-shadow","100x2+20+10",")", + "+swap","-background","none","-layers","merge","+repage" , + self.filepath + ] + self._call_cmd(cmd) + + + def _threed_rotate_cmd (self): + #3rd step--run 3Drotate + cmd = [THREEDROTATE] + if self.params.swing: cmd += ["pan={}".format(self.params.swing)] + if self.params.tilt: cmd += ["tilt={}".format(self.params.tilt)] + if self.params.roll: cmd += ["roll={}".format(self.params.roll)] + if self.params.zoom: + cmd += ["zoom={}".format(self.params.zoom)] + if cmd == [THREEDROTATE]: #if nothing has been added + return + if self.params.planebgcolor and not self.params.planebgimage: + cmd += ["bgcolor={}".format(self.params.planebgcolor)] + else: + cmd += ["bgcolor=none"] + cmd += ["skycolor={}".format(self.params.skycolor or 'none')] + if self.params.transition: cmd += ["vp={}".format(self.params.transition)] + cmd += [ self.filepath, self.filepath ] + self._call_cmd(cmd) + + + def _trim_cmd (self): + cmd = [BIN_CONVERT, self.filepath, "-trim", "+repage", self.filepath] + self._call_cmd(cmd) + + def _prepare_gridimage(self, image): + if image['mimetype'] != 'png': + cmd = [BIN_CONVERT, image['path'], self.filepath] + else: + cmd = ['cp', image['path'], self.filepath] + self._call_cmd(cmd) + + + def _overlay_planebgimage(self): + cmd = [ + BIN_COMPOSITE, + "-compose", "Dst_Over", "-gravity", "center", + self.params.planebgimage["path"], + self.filepath, + self.filepath + ] + self._call_cmd(cmd) + + def _cleanup(self): + if not len(self.files_created): + pass + cmd = ["rm", "-f"] + self.files_created + self._call_cmd(cmd) + + def create(self): + if self.params.bgimage: + self._prepare_gridimage(self.params.bgimage) + self._grid_command() + elif self.params.imageinstead: + self._prepare_gridimage(self.params.imageinstead) + else: + self._make_canvas() + self._grid_command() + if self.params.shadow: self._shadow_cmd() + self._threed_rotate_cmd() + if self.params.planebgimage: self._overlay_planebgimage() + if self.params.trim: self._trim_cmd() + self._cleanup() + +if __name__ == "__main__": + g = Imgrid(**{ + 'bgimage' : 'http://i.asdf.us/im/1a/imBreak_1424909483_xx_abridged___.gif', + 'planebgimage' : 'http://i.imgur.com/FICZtph.png', + 'tilt' : '30', + 'spacing' : '30', + 'hlines' : 'true', + 'roll' : '30', + 'shadow' : 'true', + 'trim' : 'true' + }) + g.create() + print g.commands diff --git a/pb/lib/__init__.py b/pb/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pb/lib/db.py b/pb/lib/db.py new file mode 100755 index 0000000..2570b4f --- /dev/null +++ b/pb/lib/db.py @@ -0,0 +1,31 @@ +import MySQLdb +USER = "asdfus" +PASSWORD = "gTYgT&M6q" +DATABASE = "asdfus" + +class db: + def __init__ (self): + self.conn = None + self.cursor = None + self.connect() + + def connect (self): + self.conn = MySQLdb.connect (host = "localhost", + user = USER, + passwd = PASSWORD, + db = DATABASE + ) + self.cursor = self.conn.cursor () + + def execute (self,sql,args=()): + try: + self.cursor.execute(sql,args) + except MySQLdb.Error, e: + print "Error %d: %s" % (e.args[0], e.args[1]) + # sys.exit (1) + self.connect() + self.cursor.execute(sql,args) + + def lastinsertid (self): + return DB.conn.insert_id() + diff --git a/pb/lib/utils.py b/pb/lib/utils.py new file mode 100644 index 0000000..3630ba0 --- /dev/null +++ b/pb/lib/utils.py @@ -0,0 +1,122 @@ +import re +from pb.config import * +import time +import urllib +import urllib2 +import sys +from subprocess import Popen,PIPE,call +Request = urllib2.Request +urlencode = urllib.urlencode +urlopen = urllib2.urlopen + +def call_cmd(cmd, error=""): + try: + call(cmd) + except Exception as e: + raise (str(e)) + +def is_color(s): + if s == "": + return "transparent" + if re.match('(rgba?\([0-9]+,[0-9]+,[0-9]+\))|([a-zA-Z]+)|(\#[A-Ha-h0-9]+)', s): + return s.replace(' ', ''); + else: + sys.stderr.write("Not a color: {}\n".format(s)) + raise ValueError + +def dimensions (filepath): + #works in lieu of a mimetype check (it reads the header as well) + ident = (Popen([BIN_IDENTIFY, filepath], stdout=PIPE).communicate()[0]).split(" ") + return ident[2].split("x") + +def is_number(s): + try: + return int(s) + except (ValueError, TypeError): + return False + +def bool_correct(s): + if re.match(r'^false$', s, re.IGNORECASE): + return False + elif re.match(r'^true$', s, re.IGNORECASE): + return True + else: + return s + +class dotdict(dict): + """dot.notation access to dictionary attributes""" + def __getattr__(self, attr): + return self.get(attr) + __setattr__= dict.__setitem__ + __delattr__= dict.__delitem__ + +def get_mimetype(f): + try: + mimetype = Popen( + [BIN_IDENTIFY, f], stdout=PIPE + ).communicate()[0].split(" ")[1].lower() + return mimetype + except Exception as e: + sys.stderr.write("couldn't determine mimetype") + sys.stderr.write(str(e)) + raise; + +def sanitize (str): + return re.sub(r'\W+', '', str) + +def now(): + return int(time.time()) + +def browser_request (url, data=None): + headers = { + 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', + 'Accept': '*/*', + } + try: + req = Request(url, data, headers) + response = urlopen(req) + except IOError, e: + if hasattr(e, 'code'): + sys.stderr.write( '%s - ERROR %s' % (url, e.code) ) + raise; + return None + else: + return response + +def download(url, destination, max_size=MAX_SIZE): + response = browser_request(url, None) + rawimg = response.read() + if len(rawimg) == 0: + sys.stderr.write("got zero-length file") + raise; + if len(rawimg) > max_size: + sys.stderr.write("file too big: max size {} KB / {} is {} KB".format( + str(MAX_SIZE/1024), + destination, + str(len(rawimg)/1024) + )) + raise; + f = open(destination, "w") + f.write(rawimg) + f.close() + +def file_size (filepath): + try: + return os.stat(file)[6] + except Exception as e: + sys.stderr.write("IMGRID couldn't determine file size") + sys.stderr.write(str(e)) + raise; + +def gif_frames(filepath): + try: + info = Popen([BIN_IDENTIFY,filepath], stdout=PIPE).communicate()[0] + frames = filter((lambda x: x), map( + (lambda x: x.split(" ")[0]), + (info).split('\n') + )) + return frames + except Exception as e: + sys.stderr.write("IMGRID couldn't get gif frames") + sys.stderr.write(str(e)) + raise; diff --git a/pb/pattern.py b/pb/pattern.py new file mode 100755 index 0000000..359af20 --- /dev/null +++ b/pb/pattern.py @@ -0,0 +1,172 @@ +#!/usr/bin/python2.7 +import os +import sys +import random +import re +import urllib +from pb.config import * +import lib.utils as utils + +import simplejson as json +from PIL import Image +import uuid + +FUSE_MODE="Pin_Light" + +class Pattern: + def __init__(self, **kwargs): + self.params = {} + self.tag = "imPattern"; + self._pid = str(os.getpid()) + self.commands = []; + self.now = utils.now() + self.height = "" + self.width = "" + self._required_keys = [ + #FIXME change name to username in js + #FIXME change js api + "pattern_url", + "pattern_data", + "username", + "image_url", + ] + self.files_created = [] + for k in self._required_keys: + if k in kwargs: + if k in [ 'pattern_url', 'image_url' ]: + self.params[k] = kwargs[k] + elif k == 'pattern_data': + self.params[k] = kwargs[k] #FIXME add conversion data + else: + self.params[k] = utils.sanitize(kwargs[k]) + else: + self.params[k] = False; + + if not self.params['image_url']: + sys.stderr.write('no image url'); + raise ValueError + self.params = utils.dotdict(self.params) + + self.basename, self._format = self._get_filename(); + #FIXME omit file extension for downloaded files + self._downloaded_file = os.path.join(WORKING_DIR, "IMPATTERNTMP_DL{}_{}.{}".format(self.basename, self._pid, self._format)) # same here + #lets go back to this in a second + self._pattern_file = os.path.join(WORKING_DIR, "IMPATTERNTMP_PTN{}_{}.{}".format(self.basename, self._pid, self._format)) # this + + self._download(self.params.image_url, self._downloaded_file) + + self.width, self.height = utils.dimensions(self._downloaded_file) # same here + + self.filename = "{}.{}".format(self.basename, self._format) + self.filepath = os.path.join(WORKING_DIR, self.filename) + + if self.params['pattern_url']: + self._download(self.params['pattern_url'], self._pattern_file) + elif self.params['pattern_data']: + self._from_pattern_data() + else: + sys.stderr.write("pattern must be supplied as json array or as a png url") + raise ValueError; + + def _download(self, url, dest): + try: + utils.download(url, dest) + self.files_created.append(dest) + except Exception as e: + sys.stderr.write(str(e)) + raise; + + 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 _from_pattern_data(self): + def boolToColor(boolean): + if boolean: + return (0,0,0,255); + else: + return (255,255,255,255) + specs = json.loads(self.params.pattern_data); + if int(specs['width']) > 100 or int(specs['height']) > 100: + raise ValueError + sys.stderr.write("height and width need to be less than 100 px") + img = Image.new('RGBA', (int(specs['width']), int(specs['height']))); + pixels = img.load(); + for i in range(0, len(specs['matrix'])): + for j in range(0, len(specs['matrix'][i])): + pixels[j,i] = boolToColor(int(specs['matrix'][i][j])); + + img.save(self._pattern_file, "PNG") + + + def _get_filename (self): + url = self.params.image_url + name_part = ""; + file_format = ""; + if "?" in url: + url = url.split("?")[0] + if "/" in url: + url = urllib.unquote(url).replace(" ","") + name_part = url.split("/")[-1] + try: + parts = name_part.split(".") + name_part = utils.sanitize(parts[-2]) + file_format = utils.sanitize(parts[-1]) + if not name_part or not file_format: + sys.stderr.write( "Incompatible input file type") + raise; + except Exception as e: + sys.stderr.write( "Incompatible input file type") + raise; + else: + sys.stderr.write( "Incompatible url") + raise; + if (len(name_part) > 20): + name_part = name_part[:-20] + return "{}{}_{}_{}".format(self.tag, name_part, self.now, self.params.username or ""), file_format + + def _cleanup(self): + cmd = ["rm"]+self.files_created + self._call_cmd(cmd) + + #first step + def _make_canvas(self): + cmd = [BIN_CONVERT,"-size",self.width+"x"+self.height,"canvas:transparent", self.filepath] + self._call_cmd(cmd) + + #second step use the Canvas as a background + def _make_mask(self): + #tile the pattern pattern on the canvas + cmd = [BIN_COMPOSITE,"-tile", self._pattern_file, self.filepath, self.filepath]; + self._call_cmd(cmd) + #fuse the tiled file to create a mask + #convert thebg.gif -compose Dst_In null: thefile.gif -matte -layers composite new.gif + cmd = [BIN_CONVERT, self.filepath, "-compose", "Dst_In", "null:", + self._downloaded_file, "-matte", "-layers", "composite", self.filepath] + self._call_cmd(cmd) + + #third step + def _fuse_mask(self, fuse_mode=FUSE_MODE): + cmd = [BIN_CONVERT, "-dispose", "2", self.filepath, "null:", + self._downloaded_file, "-matte", "-compose", fuse_mode, "-layers", "composite", + self.filepath] + self._call_cmd(cmd) + + def create(self): + self._make_canvas(); + self._make_mask() + self._fuse_mask(); + +if __name__ == "__main__": + TEST_PARAMS = { + # "pattern_url" : "http://asdf.us/impattern/patterns/1.png", + "pattern_data" : '{"matrix":[["0","0","0","0","0","1","0","0","0","0"],["0","0","0","0","1","1","1","0","0","0"],["0","0","1","1","1","0","1","0","0","0"],["0","1","1","0","0","0","0","0","0","0"],["0","1","0","0","1","0","0","0","0","0"],["0","1","0","0","1","0","0","0","1","0"],["0","1","0","0","1","1","0","0","1","0"],["0","1","0","0","0","1","1","1","1","0"],["0","1","1","1","1","0","0","0","0","0"],["0","0","0","0","1","0","0","0","0","0"]],"width":"10","height":"10"}', + # "username" : "garfield", + "image_url" : "http://i.asdf.us/im/be/PinkHijab_1425078647_reye.gif", + } + p = Pattern(**TEST_PARAMS) + p.create() + diff --git a/pbserver.py b/pbserver.py index 02a17ed..fb7fb65 100755 --- a/pbserver.py +++ b/pbserver.py @@ -1,16 +1,16 @@ #!/usr/bin/python2.7 from bottle import route, run, post, request -from gradient import Gradient -from imgrid import Imgrid -from breaker import Breaker -from pattern import Pattern +from pb.gradient import Gradient +from pb.imgrid import Imgrid +from pb.breaker import Breaker +from pb.pattern import Pattern -from config import AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, BUCKET_NAME +from pb.config import AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, BUCKET_NAME import os import sys -import lib.db as db +import pb.lib.db as db import mimetypes import sha from subprocess import call, Popen, PIPE @@ -20,11 +20,11 @@ BIN_IDENTIFY = "/usr/bin/identify" from boto.s3.connection import S3Connection from boto.s3.key import Key # -#try: -# DB = db.db () -#except Exception as e: -# sys.stderr.write("Could not connect to db:\n{}".format(e)) -# sys.exit(1); +try: + DB = db.db () +except Exception as e: + sys.stderr.write("Could not connect to db:\n{}".format(e)) + sys.exit(1); BASE_URL = "http://i.asdf.us" def hashdir(filename): @@ -126,7 +126,7 @@ def gradient(): @post('/im/api/imgrid') def imgrid(): try: - im = Imgrid(request.forms) + im = Imgrid(**(dict(request.forms))) im.create(); url= "NULL" for elem in [ im.params.imageinstead , im.params.bgimage, im.params.planebgimage ]: @@ -141,7 +141,7 @@ def imgrid(): @post('/im/api/imbreak') def breaker(): try: - im = Breaker(request.forms) + im = Breaker(**(dict(request.forms))) im.create(); return return_image(im, im.params['url']) except Exception as e: @@ -151,7 +151,7 @@ def breaker(): @post('/im/api/impattern') def pattern(): try: - im = Pattern(request.forms) + im = Pattern(**(dict(request.forms))) im.create(); return return_image(im, im.params['image_url']) except Exception as e: diff --git a/test.sh b/test.sh index 8892abd..855c655 100644 --- a/test.sh +++ b/test.sh @@ -1,6 +1,4 @@ #!/bin/bash -curl --data 'width=200&height=500&stripes=true&stripenumber=50&stripeintensity=50&color1=green&color2=silver' localhost:8999/gradient -echo "" curl --data 'width=200&height=500' localhost:8999/imgrid echo "" curl --data 'url=http://i.asdf.us/im/56/6005101large_1424913577_bike.gif&breaktype=RGB_WASH&breakmode=extreme' localhost:8999/breaker -- cgit v1.2.3-70-g09d2