#!/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