Move additional logic into RH obj

This commit is contained in:
Robohash 2013-08-28 18:08:26 -04:00
parent 78759d8aa5
commit a1ca07ddf8
3 changed files with 80 additions and 35 deletions

1
__init__.py Normal file
View File

@ -0,0 +1 @@
from .robohash import Robohash

View File

@ -3,19 +3,24 @@ import os
import hashlib import hashlib
import Image import Image
class Robohash(object): class Robohash(object):
""" """
Robohash is a quick way of generating unique avatars for a site. Robohash is a quick way of generating unique avatars for a site.
The original use-case was to create somewhat memorable images to represent a RSA key. The original use-case was to create somewhat memorable images to represent a RSA key.
""" """
def __init__(self,string,hashcount=11): def __init__(self,string,hashcount=11,ignoreext = True):
""" """
Creates our Robohasher Creates our Robohasher
Takes in the string to make a Robohash out of. Takes in the string to make a Robohash out of.
""" """
# Optionally remove an images extension before hashing.
if ignoreext is True:
string = self._remove_exts(string)
string = string.encode('utf-8') string = string.encode('utf-8')
hash = hashlib.sha512() hash = hashlib.sha512()
hash.update(string) hash.update(string)
self.hexdigest = hash.hexdigest() self.hexdigest = hash.hexdigest()
@ -28,12 +33,32 @@ class Robohash(object):
self.iter = 4 self.iter = 4
self._create_hashes(hashcount) self._create_hashes(hashcount)
self.resourcedir = os.path.dirname(__file__) + '/'
# Get the list of backgrounds and RobotSets # Get the list of backgrounds and RobotSets
self.sets = self._listdirs('sets') self.sets = self._listdirs(self.resourcedir + 'sets')
self.bgsets = self._listdirs('backgrounds') self.bgsets = self._listdirs(self.resourcedir + 'backgrounds')
# Get the colors in set1 # Get the colors in set1
self.colors = self._listdirs('sets/set1') self.colors = self._listdirs(self.resourcedir + 'sets/set1')
self.format = 'png'
def _remove_exts(self,string):
"""
Sets the string, to create the Robohash
"""
# If the user hasn't disabled it, we will detect image extensions, such as .png, .jpg, etc.
# We'll remove them from the string before hashing.
# This ensures that /Bear.png and /Bear.bmp will send back the same image, in different formats.
if string.lower().endswith(('.png','.gif','.jpg','.bmp','.jpeg','.ppm','.datauri')):
format = string[string.rfind('.') +1 :len(string)]
if format.lower() == 'jpg':
format = 'jpeg'
self.format = format
string = string[0:string.rfind('.')]
return string
def _create_hashes(self,count): def _create_hashes(self,count):
""" """
@ -55,7 +80,6 @@ class Robohash(object):
Go through each subdirectory of `path`, and choose one file from each to use in our hash. Go through each subdirectory of `path`, and choose one file from each to use in our hash.
Continue to increase self.iter, so we use a different 'slot' of randomness each time. Continue to increase self.iter, so we use a different 'slot' of randomness each time.
""" """
chosen_files = [] chosen_files = []
# Get a list of all subdirectories # Get a list of all subdirectories
@ -79,18 +103,44 @@ class Robohash(object):
return chosen_files return chosen_files
def assemble(self,roboset=None,format='png',bgset=None,sizex=300,sizey=300): def assemble(self,roboset=None,color=None,format=None,bgset=None,sizex=300,sizey=300):
""" """
Build our Robot! Build our Robot!
Returns the robot image itself. Returns the robot image itself.
""" """
# Set a default set for the robot # Allow users to manually specify a robot 'set' that they like.
if roboset is None: # Ensure that this is one of the allowed choices, or allow all
# If they don't set one, take the first entry from sets above.
if roboset == 'any':
roboset = self.sets[self.hasharray[1] % len(self.sets) ]
elif roboset in self.sets:
roboset = roboset
else:
roboset = self.sets[0] roboset = self.sets[0]
# Only set1 is setup to be color-seletable. The others don't have enough pieces in various colors.
# This could/should probably be expanded at some point..
# Right now, this feature is almost never used. ( It was < 44 requests this year, out of 78M reqs )
if roboset == 'set1': if roboset == 'set1':
randomcolor = self.colors[self.hasharray[0] % len(self.colors) ] if color in self.colors:
roboset = 'set1/' + randomcolor roboset = 'set1/' + color
else:
randomcolor = self.colors[self.hasharray[0] % len(self.colors) ]
roboset = 'set1/' + randomcolor
# If they specified a background, ensure it's legal, then give it to them.
if bgset in self.bgsets:
bgset = bgset
elif bgset == 'any':
bgset = self.bgsets[ self.hasharray[2] % len(self.bgsets) ]
# If we set a format based on extension earlier, use that. Otherwise, PNG.
if format is None:
format = self.format
# Each directory in our set represents one piece of the Robot, such as the eyes, nose, mouth, etc. # Each directory in our set represents one piece of the Robot, such as the eyes, nose, mouth, etc.
@ -102,17 +152,17 @@ class Robohash(object):
# First, we'll get a list of parts of our robot. # First, we'll get a list of parts of our robot.
roboparts = self._get_list_of_files('sets/' + roboset) roboparts = self._get_list_of_files(self.resourcedir + 'sets/' + roboset)
# Now that we've sorted them by the first number, we need to sort each sub-category by the second. # Now that we've sorted them by the first number, we need to sort each sub-category by the second.
roboparts.sort(key=lambda x: x.split("#")[1]) roboparts.sort(key=lambda x: x.split("#")[1])
if bgset is not None: if bgset is not None:
bglist = [] bglist = []
backgrounds = os.listdir('backgrounds/' + bgset) backgrounds = os.listdir(self.resourcedir + 'backgrounds/' + bgset)
backgrounds.sort() backgrounds.sort()
for ls in backgrounds: for ls in backgrounds:
if not ls.startswith("."): if not ls.startswith("."):
bglist.append('backgrounds/' + bgset + "/" + ls) bglist.append(self.resourcedir + 'backgrounds/' + bgset + "/" + ls)
background = bglist[self.hasharray[3] % len(bglist)] background = bglist[self.hasharray[3] % len(bglist)]
# Paste in each piece of the Robot. # Paste in each piece of the Robot.

View File

@ -223,6 +223,7 @@ class ImgHandler(tornado.web.RequestHandler):
sizey = 300 sizey = 300
format = "png" format = "png"
bgset = None bgset = None
color = None
# Normally, we pass in arguments with standard HTTP GET variables, such as # Normally, we pass in arguments with standard HTTP GET variables, such as
# ?set=any and &size=100x100 # ?set=any and &size=100x100
@ -259,16 +260,10 @@ class ImgHandler(tornado.web.RequestHandler):
string = self.request.remote_ip string = self.request.remote_ip
# If the user hasn't disabled it, detect if there is requested extension. # Detect if the user has passed in a flag to ignore extensions.
# If so, remove it from the string, but set the format. # Pass this along to to Robohash obj later on.
# This ensures that /Bear.png and /Bear.bmp will send back the same image, in different formats.
if args.get('ignoreext','false').lower() != 'true':
if string.lower().endswith(('.png','.gif','.jpg','.bmp','.jpeg','.ppm','.datauri')):
format = string[string.rfind('.') +1 :len(string)]
if format.lower() == 'jpg':
format = 'jpeg'
string = string[0:string.rfind('.')]
ignoreext = args.get('ignoreext','false').lower() == 'true'
# Split the size variable in to sizex and sizey # Split the size variable in to sizex and sizey
if "size" in args: if "size" in args:
@ -306,6 +301,7 @@ class ImgHandler(tornado.web.RequestHandler):
# Create our Robohashing object # Create our Robohashing object
r = Robohash(string) r = Robohash(string)
# Allow users to manually specify a robot 'set' that they like. # Allow users to manually specify a robot 'set' that they like.
# Ensure that this is one of the allowed choices, or allow all # Ensure that this is one of the allowed choices, or allow all
# If they don't set one, take the first entry from sets above. # If they don't set one, take the first entry from sets above.
@ -333,25 +329,23 @@ class ImgHandler(tornado.web.RequestHandler):
# Right now, this feature is almost never used. ( It was < 44 requests this year, out of 78M reqs ) # Right now, this feature is almost never used. ( It was < 44 requests this year, out of 78M reqs )
if args.get('color') in r.colors: if args.get('color') in r.colors:
roboset = 'set1/' + args.get('color') roboset = 'set1'
color = args.get('color')
# If they DID choose set1, randomly choose a color. # If they DID choose set1, randomly choose a color.
if roboset == 'set1': if roboset == 'set1' and color is None:
randomcolor = r.colors[r.hasharray[0] % len(r.colors) ] color = r.colors[r.hasharray[0] % len(r.colors) ]
roboset = 'set1/' + randomcolor roboset = 'set1'
# Allow them to set a background, or default to None # Allow them to set a background, or keep as None
if args.get('bgset') in r.bgsets: if args.get('bgset') in r.bgsets + ['any']:
bgset = args.get('bgset') bgset = args.get('bgset')
elif args.get('bgset','').lower() == 'any':
bgset = r.bgsets[ r.hasharray[2] % len(r.bgsets) ]
# We're going to be returning the image directly, so tell the browser to expect a binary. # We're going to be returning the image directly, so tell the browser to expect a binary.
self.set_header("Content-Type", "image/" + format) self.set_header("Content-Type", "image/" + format)
# Build our Robot. # Build our Robot.
r.assemble(roboset=roboset,format=format,bgset=bgset,sizex=sizex,sizey=sizey) r.assemble(roboset=roboset,format=format,bgset=bgset,color=color,sizex=sizex,sizey=sizey)
# Print the Robot to the handler, as a file-like obj # Print the Robot to the handler, as a file-like obj
if r.format != 'datauri': if r.format != 'datauri':