From 46681c0088ac43d4d626e793d09583173f3c0ba7 Mon Sep 17 00:00:00 2001 From: pepperpepperpepper Date: Tue, 1 Mar 2016 13:30:58 -0800 Subject: good first version works --- photoblaster/_file.py | 157 ++++++++++++++++++++++++ photoblaster/config.py | 2 +- photoblaster/modules/.ropeproject/globalnames | Bin 476 -> 494 bytes photoblaster/modules/base.py | 165 +++----------------------- photoblaster/modules/pbgenerate.py | 1 + photoblaster/modules/pbgradient.py | 158 +++++++++++++----------- run_module_examples.py | 4 +- 7 files changed, 264 insertions(+), 223 deletions(-) create mode 100644 photoblaster/_file.py diff --git a/photoblaster/_file.py b/photoblaster/_file.py new file mode 100644 index 0000000..3ab1afc --- /dev/null +++ b/photoblaster/_file.py @@ -0,0 +1,157 @@ +import os +import re +import random +import sha +import sys +import time +from photoblaster.s3.cli import S3Cli +from subprocess import Popen, PIPE +from photoblaster.config import WORKING_DIR, BIN_IDENTIFY, DEFAULT_WIDTH, \ + DEFAULT_HEIGHT, BIN_CONVERT, LOCAL, BASE_URL, DEFAULT_FINALFORMAT + +_MAX_FILENAME_LENGTH = 20 + + +class File(object): + def __init__( + self, + namepart="", + username="", + is_temp=False, + extension=DEFAULT_FINALFORMAT, + directory=WORKING_DIR + ): + self._is_temp = is_temp + self.extension = extension + self._directory = directory + self._filename = None + self._creation_time = str(int(time.time())) + self.set_filename( + namepart=namepart, + username=username + ) + self._hashdir = sha.new( + self.get_filepath() + ).hexdigest()[:2] + self._storage = "local" + + @classmethod + def from_url(cls, url, **kwargs): + """creates the filename from a url""" + _basename = os.path.basename(url) + namepart = re.split(r'\.', _basename)[0] + namepart = cls.url_sanitize(namepart)[0:_MAX_FILENAME_LENGTH] + kwargs[namepart] = namepart + return cls(**kwargs) + + def set_filename( + self, + namepart="", + username="" + ): + name = "" + if self._is_temp: + namepart = "temp" + if namepart: + name += "%s-" % namepart + name += "%s_%s" % (self.__class__.__name__, self.get_creation_time()) + if username: + name += "_%s" % username + if self.extension: + name += ".%s" % self.extension + self._filename = name + + def set_filepath( + self, + directory=WORKING_DIR + ): + """creates a local working path""" + if self._is_temp: + self.directory = WORKING_DIR + self.filepath = os.path.join(directory, self.get_filename()) + + def get_filepath(self): + return os.path.join(self._directory, self.get_filename()) + + def get_filename(self): + return self._filename + + @staticmethod + def url_sanitize(self, s): + return re.sub(r'\W+', '', s) + + def get_dimensions(self): + try: + ident = (Popen( + [BIN_IDENTIFY, self.get_filepath()], + stdout=PIPE).communicate()[0]).split(" ") + return ident[2].split("x") + except Exception as e: + sys.stderr.write("Unable to get file dimensions:\n") + sys.stderr.write("%s \n" % e) + + def get_raw_data(self): + f = open(self.get_filepath(), 'r') + data = f.read() + f.close() + return data + + @staticmethod + 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("couldn't get gif frames\n") + raise e + + def _choose_gif_frame(self): + _gif_frames = self.gif_frames(self.filepath) + frame = random.choice(_gif_frames) + self._call_cmd([BIN_CONVERT, frame, self.filepath]) + + def as_dict(self): + url = "%s/im/%s/%s" % (BASE_URL, self._hashdir, self.get_filename()) + if self.get_storage() == "local": + url = "/im/cache/%s" % self.get_filename() + dimensions = self.get_dimensions() + return { + 'url': url, + 'size': self.get_size_in_bytes(), + 'width': "%spx" % dimensions[0], + 'height': "%spx" % dimensions[1], + } + + def s3move(self): + s3cli = S3Cli() + s3cli.s3move( + self.get_filepath(), "im/{}/{}".format( + self._hashdir, self.get_filename()) + ) + self._storage = "s3" + + def delete(self): + os.remove(self.get_filepath()) + self._storage = None + + def get_storage(self): + return self._storage + + def get_hashdir(self): + return self._hashdir + + def get_creation_time(self): + return self._creation_time + + def get_size_in_bytes(self): + try: + return os.stat(self.get_filepath())[6] + except Exception as e: + sys.stderr.write( + "Couldn't determine filesize of %s\n" % self.get_filepath()) + sys.stderr.write("%s\n" % e) diff --git a/photoblaster/config.py b/photoblaster/config.py index adaae8e..9e0bc4f 100644 --- a/photoblaster/config.py +++ b/photoblaster/config.py @@ -60,5 +60,5 @@ DB_PASSWORD = "gTYgT&M6q" DB_NAME = "asdfus" if LOCAL: DB_HOST = "localhost" - +BASE_URL = "http://i.asdf.us" diff --git a/photoblaster/modules/.ropeproject/globalnames b/photoblaster/modules/.ropeproject/globalnames index 6a68327..bf1ed49 100644 Binary files a/photoblaster/modules/.ropeproject/globalnames and b/photoblaster/modules/.ropeproject/globalnames differ diff --git a/photoblaster/modules/base.py b/photoblaster/modules/base.py index ada2504..14163f5 100644 --- a/photoblaster/modules/base.py +++ b/photoblaster/modules/base.py @@ -2,22 +2,11 @@ contains only the Pb class which is used by the Pb.* modules for inheritance """ -import re -from photoblaster.config import WORKING_DIR, BIN_CONVERT, BIN_IDENTIFY,\ - DEFAULT_HEIGHT, DEFAULT_WIDTH, LOCAL -import time import sys -import os -import random -from subprocess import Popen, PIPE, call +from subprocess import call from photoblaster.params import Params -import sha import simplejson as json -from photoblaster.s3.cli import S3Cli from photoblaster.db.models.imcmd import ImCmd -BASE_URL = "http://i.asdf.us" - -_MAX_FILENAME_LENGTH = 20 class PbProcessError(Exception): @@ -28,65 +17,16 @@ class Pb(object): """Base Pb class. USED ONLY FOR INHERITANCE""" def __init__(self, **kwargs): self._input_kwargs = kwargs - self._now = str(int(time.time())) - self.params = Params(classname=self.__class__.__name__, now=self._now) + self.params = Params( + classname=self.__class__.__name__ + ) self._files_created = [] self.commands = [] - self._working_dir = WORKING_DIR self.tag = self.__class__.__name__ - self._hashdir = None self._db_url_param = None - # FIXME move to separate class - self.file_size = None self.width = None self.height = None - self.filename = None - self.filepath = None - self.file_height = None - self.file_width = None - - def _filename_create(self, url=None, namepart="", extension=""): - if url: - _basename = os.path.basename(url) - namepart = re.split(r'\.', _basename)[0] - namepart = self._url_sanitize(namepart)[0:_MAX_FILENAME_LENGTH] - name = "" - if namepart: - name += "%s-" % namepart - name += "%s_%s" % (self.__class__.__name__, self._now) - if self.params.username: - name += "_%s" % self.params.username - if extension: - name += ".%s" % extension - return name - - def _filepath_create(self, filename, directory=WORKING_DIR): - return os.path.join(directory, filename) - - def _filename_filepath_create( - self, - url=None, - namepart="", - directory=WORKING_DIR, - extension="" - ): - filename = self._filename_create( - url=url, namepart=namepart, extension=extension) - filepath = self._filepath_create(filename, directory=directory) - return filename, filepath - - def _tempfilepath_create( - self, namepart="temp", directory=WORKING_DIR, extension=""): - filename = self._filename_create( - namepart=namepart, extension=extension) - return self._filepath_create(filename, directory=directory) - - def _hashdir_create(self): - self._hashdir = sha.new(self.filename).hexdigest()[:2] - - def _url_sanitize(self, s): - return re.sub(r'\W+', '', s) def _call_cmd(self, cmd): try: @@ -96,44 +36,6 @@ class Pb(object): except Exception: raise Exception("Unable to call cmd {}".format(str(cmd))) - def _dimensions(self, filepath): - try: - ident = (Popen( - [BIN_IDENTIFY, filepath], - stdout=PIPE).communicate()[0]).split(" ") - return ident[2].split("x") - except Exception as e: - self.err_warn("Unable to get file dimensions:\n") - self.err_ward(str(e)) - - def _file_dimensions(self): - self.file_width, self.file_height = self._dimensions(self.filepath) - - def _width_and_height_set( - self, - filepath=None, - width=DEFAULT_WIDTH, - height=DEFAULT_HEIGHT - ): - if filepath: - self.width, self.height = self._dimensions(filepath) - return - self.width = width - self.height = height - - def _file_size_get(self): - try: - self.file_size = os.stat(self.filepath)[6] - except Exception as e: - self.err_warn("Couldn't determine filesize of %s\n" % self.filepath) - self.err_warn(str(e)) - - def _file_read(self, filepath): - f = open(filepath, 'r') - data = f.read() - f.close() - return data - def err_warn(self, s): sys.stderr.write("ERROR:{} - {}\n".format(self.__class__.__name__, s)) raise PbProcessError @@ -141,10 +43,7 @@ class Pb(object): def _cleanup(self): if not self._files_created: return - map(lambda n: os.remove(n), self._files_created) - - def _file_clean_local(self): - os.remove(self.filepath) + map(lambda n: n.delete(), self._files_created) def err_fatal(self, s): sys.stderr.write("ERROR[FATAL]:%s - %s\n" % ( @@ -161,39 +60,25 @@ class Pb(object): b = cls(**example_params) b.create() if verbose: - sys.stderr.write("generated %s\n" % b.filepath) + sys.stderr.write("generated %s\n" % b.newfile.get_filepath()) sys.stderr.write("files created %s\n" % b._files_created) sys.stderr.write("commands:\n %s\n" % ";\n ".join(b.commands)) return b - @staticmethod - 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: - Pb.err_warn("couldn't get gif frames") - raise e - - def _choose_gif_frame(self, filepath): - _gif_frames = Pb.gif_frames(filepath) - frame = random.choice(_gif_frames) - self._call_cmd([BIN_CONVERT, frame, filepath]) - - def db_send(self, remote_addr=None, db_connection=None): + def db_send( + self, + remote_addr=None, + db_connection=None + ): try: _insert_data = { - 'date': self._now, + 'date': self.newfile.get_creation_time(), 'remote_addr': remote_addr, 'name': str(self.params.username), 'url': self._db_url_param, - 'dir': self._hashdir, + 'dir': self.newfile.get_hashdir(), 'oldfile': None, - 'newfile': self.filename, + 'newfile': self.newfile.get_filename(), 'dataobj': json.dumps(dict(self._input_kwargs)), 'cmd': "; ".join(self.commands), 'tag': self.tag, @@ -202,27 +87,5 @@ class Pb(object): except Exception as e: self.err_warn("Problem sending to database:\n %s" % str(e)) - def file_s3move(self): - self._hashdir_create() - s3cli = S3Cli() - s3cli.s3move( - self.filepath, "im/{}/{}".format(self._hashdir, self.filename) - ) - self._file_clean_local() - - def file_dict(self): - url = "%s/im/%s/%s" % (BASE_URL, self._hashdir, self.filename) - if LOCAL: - url = "/im/cache/%s" % self.filename - return { - 'url': url, - 'size': self.file_size, - 'width': "%spx" % self.file_width, - 'height': "%spx" % self.file_height, - } - def create(self): - # base methods FIXME move into File class - self._file_dimensions() - self._file_size_get() self._cleanup() diff --git a/photoblaster/modules/pbgenerate.py b/photoblaster/modules/pbgenerate.py index d857562..c034a6f 100755 --- a/photoblaster/modules/pbgenerate.py +++ b/photoblaster/modules/pbgenerate.py @@ -123,6 +123,7 @@ class PbGenerate(Pb): elif self.params.transparent: self.tag = "%s:%s" % (self.tag, "transparent") + self.newfile = File() self.filename, self.filepath = self._filename_filepath_create( url=self.params.url['url'], extension=self.params.format ) diff --git a/photoblaster/modules/pbgradient.py b/photoblaster/modules/pbgradient.py index 9b8ecaf..bf6bdd2 100755 --- a/photoblaster/modules/pbgradient.py +++ b/photoblaster/modules/pbgradient.py @@ -4,6 +4,7 @@ from photoblaster.config import DEFAULT_WIDTH, DEFAULT_HEIGHT,\ DEFAULT_FINALFORMAT, \ BIN_CONVERT, BEVELBORDER, OUTPUT_IMAGE_TYPES from photoblaster.modules import Pb +from photoblaster._file import File _DEFAULT_COLOR_1 = "white" _DEFAULT_COLOR_2 = "black" @@ -19,77 +20,79 @@ _halftone_values = { "flatstripes": "o2x2", } + class PbGradient(Pb): example_params = { - "width" : "200", - "color1" : "#ffdead", - "color2" : "blue", - "stripes" : "true", - "stripenumber" : "20", - "gradienttype" : "plasma", - "stripeintensity" : "20", - "halftone" : "checkeredfade", - "percentbeveled" : "30", - "flip" : "true", - "bevel" : "flatinner", - "rotate" : "20", - "height" : "200", - "filetype" : "jpg", - "username" : "whatever" + "width": "200", + "color1": "#ffdead", + "color2": "blue", + "stripes": "true", + "stripenumber": "20", + "gradienttype": "plasma", + "stripeintensity": "20", + "halftone": "checkeredfade", + "percentbeveled": "30", + "flip": "true", + "bevel": "flatinner", + "rotate": "20", + "height": "200", + "filetype": "jpg", + "username": "whatever" } + def __init__(self, **kwargs): super(PbGradient, self).__init__(**kwargs) _definitions = { - 'width': {'type':'int', 'default': DEFAULT_WIDTH}, - 'height': {'type':'int', 'default' : DEFAULT_HEIGHT}, - 'color1': {'type':'color', 'default': _DEFAULT_COLOR_1}, - 'color2': {'type':'color', 'default': _DEFAULT_COLOR_2}, - 'stripes': {'type':'bool'}, - 'stripenumber': {'type':'int', 'default': 0}, - 'stripeintensity': {'type':'int', 'default': 0}, - 'blurriness': {'type':'int', 'default': 0}, - 'contrast': {'type':'int', 'default': 100}, - 'brightness': {'type':'int', 'default': 100}, - 'saturation': {'type':'int', 'default': 100}, - 'hue': {'type':'int', 'default': 100}, - 'halftone': {'type':'enum', 'enum_values' : [ + 'width': {'type': 'int', 'default': DEFAULT_WIDTH}, + 'height': {'type': 'int', 'default': DEFAULT_HEIGHT}, + 'color1': {'type': 'color', 'default': _DEFAULT_COLOR_1}, + 'color2': {'type': 'color', 'default': _DEFAULT_COLOR_2}, + 'stripes': {'type': 'bool'}, + 'stripenumber': {'type': 'int', 'default': 0}, + 'stripeintensity': {'type': 'int', 'default': 0}, + 'blurriness': {'type': 'int', 'default': 0}, + 'contrast': {'type': 'int', 'default': 100}, + 'brightness': {'type': 'int', 'default': 100}, + 'saturation': {'type': 'int', 'default': 100}, + 'hue': {'type': 'int', 'default': 100}, + 'halftone': {'type': 'enum', 'enum_values': [ 'checkeredfade', 'etchedtransition', 'bendaydots', 'smallerdots1', 'smallerdots2', 'flatstripes', ]}, - 'bevel': {'type':'enum', 'enum_values' : [ + 'bevel': {'type': 'enum', 'enum_values': [ 'flatout', 'flatinner', 'evenlyframed', 'biginner', 'bigouter', 'dramaticflatout', 'dramaticflatinner', ]}, - 'percentbeveled': {'type':'int', 'default': _DEFAULT_BEVEL_PERCENT}, - 'tilt': {'type':'int'}, - 'rotate': {'type':'int'}, - 'flip': {'type':'bool'}, - 'flop': {'type':'bool'}, + 'percentbeveled': { + 'type': 'int', 'default': _DEFAULT_BEVEL_PERCENT}, + 'tilt': {'type': 'int'}, + 'rotate': {'type': 'int'}, + 'flip': {'type': 'bool'}, + 'flop': {'type': 'bool'}, 'filetype': { 'type': 'enum', 'enum_values': OUTPUT_IMAGE_TYPES, 'default': DEFAULT_FINALFORMAT }, - 'gradienttype': {'type':'enum', 'enum_values':[ + 'gradienttype': {'type': 'enum', 'enum_values': [ 'gradient', 'canvas', 'plasma', 'radial', 'colorspace', 'mirrored', 'plasmawash', 'gradientwash', 'noise' ], 'default': 'gradient'}, - 'username': {'type':'string'} + 'username': {'type': 'string'} } - self.params.definitions_import(_definitions, kwargs, classname=self.__class__.__name__) - - self.filename, self.filepath = self._filename_filepath_create() + self.params.definitions_import( + _definitions, kwargs, classname=self.__class__.__name__) - def _filename_create(self, **kwargs): - _base = "{}{}-{}_{}".format( + namepart = "%s%s-%s" % ( self.__class__.__name__, - str(self.params.color1).replace('#', '').replace('(', '-').replace(')', '-'), - str(self.params.color2).replace('#', '').replace('(', '-').replace(')', '-'), - self._now, + str(self.params.color1).replace( + '#', '').replace('(', '-').replace(')', '-'), + str(self.params.color2).replace( + '#', '').replace('(', '-').replace(')', '-') ) - if self.params.username: _base += "_%s" % self.params.username - return _base + ".%s" % self.params.filetype - + if self.params.username: + namepart += "_%s" % self.params.username + self.newfile = File(namepart=namepart, extension=self.params.filetype) def _build_cmd(self): cmd = [BIN_CONVERT] @@ -109,15 +112,18 @@ class PbGradient(Pb): if self.params.contrast: cmd.extend(["-contrast-stretch", str(self.params.contrast)]) _gradients = { - "gradient" : ["gradient:{}-{}".format(self.params.color1, self.params.color2)], - "canvas" : ["canvas:{}".format(self.params.color1)], - "radial" : [ - "radial-gradient:{}-{}".format(self.params.color1, self.params.color2) + "gradient": [ + "gradient:{}-{}".format( + self.params.color1, self.params.color2)], + "canvas": ["canvas:{}".format(self.params.color1)], + "radial": [ + "radial-gradient:{}-{}".format( + self.params.color1, self.params.color2) ], - "plasma" : [ + "plasma": [ "plasma:{}-{}".format(self.params.color1, self.params.color2) ], - "colorspace" : [ + "colorspace": [ "-colorspace", "Gray", "plasma:{}-{}".format( @@ -125,7 +131,7 @@ class PbGradient(Pb): self.params.color2 ) ], - "mirrored" : [ + "mirrored": [ "plasma:{}-{}".format( self.params.color1, self.params.color2 @@ -133,26 +139,27 @@ class PbGradient(Pb): "(", "+clone", "-flop", ")", "+append" ], - "plasmawash" : [ + "plasmawash": [ "plasma:{}-{}".format( self.params.color1, self.params.color2 ), "-set", "colorspace", "HSB" ], - "gradientwash" : [ + "gradientwash": [ "gradient:{}-{}".format( self.params.color1, self.params.color2 ), "-set", "colorspace", "HSB" ], - "noise" : ["xc:", "+noise", "Random", "-virtual-pixel", "tile"] + "noise": ["xc:", "+noise", "Random", "-virtual-pixel", "tile"] } cmd += _gradients[str(self.params.gradienttype)] if self.params.blurriness: - cmd.extend(["-blur", "0x{}".format(self.params.blurriness), "-auto-level"]) + cmd.extend( + ["-blur", "0x{}".format(self.params.blurriness), "-auto-level"]) if self.params.stripes and self.params.stripenumber: cmd.extend(["-function", "Sinusoid"]) @@ -177,32 +184,45 @@ class PbGradient(Pb): self.params.hue or "100" ) ] - cmd.append(self.filepath) - import sys - sys.stderr.write("\n%s\n" % cmd) + cmd.append(self.newfile.get_filepath()) self._call_cmd(cmd) - if self.params.bevel: self._make_bevel() + if self.params.bevel: + self._make_bevel() def _get_bevelvalue(self): w, h = map(int, (self.params.width, self.params.height)) if h >= w: - bevpercentval = str(int(int(self.params.percentbeveled)*int(h))/500) + bevpercentval = str( + int(int(self.params.percentbeveled)*int(h))/500) else: - bevpercentval = str(int(int(self.params.percentbeveled)*int(w))/500) + bevpercentval = str( + int(int(self.params.percentbeveled)*int(w))/500) 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"], + "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"], }[str(self.params.bevel)] def _make_bevel(self): cmd = [BEVELBORDER] cmd += self._get_bevelvalue() - cmd += [self.filepath, self.filepath] + cmd += [self.newfile.get_filepath(), self.newfile.get_filepath()] self._call_cmd(cmd) def create(self): diff --git a/run_module_examples.py b/run_module_examples.py index 82d35ea..779a6e8 100644 --- a/run_module_examples.py +++ b/run_module_examples.py @@ -5,6 +5,6 @@ for cls in Pb.__subclasses__(): print cls.__name__ if cls.__name__ == "PbGradient": instance = cls.example_run() - instance.file_s3move() - print instance.file_dict() + print instance.newfile.as_dict() + instance.newfile.s3move() instance.db_send() -- cgit v1.2.3-70-g09d2