Skip to content

Instantly share code, notes, and snippets.

@ajsb85
Created January 6, 2017 18:25
Show Gist options
  • Save ajsb85/e823d04a087abd771faf85713023d4a8 to your computer and use it in GitHub Desktop.
Save ajsb85/e823d04a087abd771faf85713023d4a8 to your computer and use it in GitHub Desktop.
Robohash blueprints
// This Python file uses the following encoding: utf-8
var os = require('os');
var hashlib = require('hashlib');
from PIL var Image = require('Image');
var natsort = require('natsort');
class Robohash(object)) {
/*
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.
*/;
}
function __init__(self,string,hashcount=11,ignoreext = true) {
/*
Creates our Robohasher
Takes in the string to make a Robohash out of.
*/;
}
// Optionally remove an images extension before hashing.
if (ignoreext === true) {
Stringing = self._remove_exts(string);
}
Stringing = Stringing.encode('utf-8');
hash = hashlib.sha512();
hash.update(string);
self.hexdigest = hash.hexdigest();
self.hasharray = [];
#Start this at 4, so earlier === reserved;
#0 = Color;
#1 = Set;
#2 = bgset;
#3 = BG;
self.iter = 4;
self._create_hashes(hashcount);
self.resourcedir = os.path.dirname(__file__) + '/';
// Get the list of backgrounds and RobotSets
self.sets = self._listdirs(self.resourcedir + 'sets');
self.bgsets = self._listdirs(self.resourcedir + 'backgrounds');
// Get the colors in set1
self.colors = self._listdirs(self.resourcedir + 'sets/set1');
self.format = 'png';
function _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 = Stringing[string.rfind('.') +1 :len(string)]
if (format.lower() == 'jpg') {
format = 'jpeg'
self.format = format
Stringing = Stringing[0:string.rfind('.')]
return Stringing;
}
function _create_hashes(self,count) {
/*
Breaks up our hash into slots, so we can pull them out later.
Essentially, it splits our SHA/MD5/etc into X parts.
*/
for (i in range(0,count)) {
#Get 1/numblocks of the hash;
blocksize = Number(len(self.hexdigest) / count);
currentstart = (1 + i) * blocksize - blocksize;
currentend = (1 +i) * blocksize;
self.hasharray.push(int(self.hexdigest[currentstart:currentend],16));
}
function _listdirs(self,path) {
return [d for (d in natsort.natsorted(os.listdir(path)) if (os.path.isdir(os.path.join(path, d))];
function _get_list_of_files(self,path) {
/*
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.
*/
chosen_files = [];
}
// Get a list of all subdirectories
directories = [];
for (root, dirs, files in natsort.natsorted(os.walk(path, topdown=false))) {
for (name in dirs) {
if (name[:1] !== '.') {
directories.push(os.path.join(root, name));
directories = natsort.natsorted(directories);
// Go through each directory in the list, and choose one file from each.
// Add this file to our master list of robotparts.
for (directory in directories) {
files_in_dir = [];
for (imagefile in natsort.natsorted(os.listdir(directory))) {
files_in_dir.push(os.path.join(directory,imagefile));
files_in_dir = natsort.natsorted(files_in_dir);
// Use some of our hash bits to choose which file
element_in_list = self.hasharray[self.iter] % len(files_in_dir);
chosen_files.push(files_in_dir[element_in_list]);
self.iter += 1;
}
return chosen_files;
}
function assemble(self,roboset=null,color=null,format=null,bgset=null,sizex=300,sizey=300) {
/*
Build our Robot!
Returns the robot image itself.
*/;
}
// Allow users to manually specify a robot 'set' that they like.
// 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) ];
} else if (roboset in self.sets) {
roboset = roboset;
} else {
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 (col|| in self.colors) {
roboset = 'set1/' + color;
} else {
randomcol|| = 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;
} else if (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 === null) {
format = self.format;
}
// Each directory in our set represents one piece of the Robot, such as the eyes, nose, mouth, etc.
}
// Each directory is named with two numbers - The number before the # is the sort order.
// This ensures that they always go in the same order when choosing pieces, regardless of OS.
}
// The second number is the order in which to apply the pieces.
// For instance, the head has to go down BEFORE the eyes, or the eyes would be hidden.
}
// First, we'll get a list of parts of our robot.
}
roboparts = self._get_list_of_files(self.resourcedir + 'sets/' + roboset);
console.log(roboparts);
// 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]);
console.log(roboparts);
if (bgset !== null) {
bglist = [];
backgrounds = natsort.natsorted(os.listdir(self.resourcedir + 'backgrounds/' + bgset));
backgrounds.sort();
for (ls in backgrounds) {
if (!ls.startswith('.')) {
bglist.push(self.resourcedir + 'backgrounds/' + bgset + '/' + ls);
background = bglist[self.hasharray[3] % len(bglist)];
// Paste in each piece of the Robot.
roboimg = Image.open(roboparts[0]);
roboimg = roboimg.resize((1024,1024));
for (png in roboparts) {
img = Image.open(png)
img = img.resize((1024,1024));
roboimg.paste(img,(0,0),img);
}
// If we're a BMP, flatten the image.
if (format == 'bmp') {
#Flatten bmps;
r, g, b, a = roboimg.split();
roboimg = Image.merge('RGB', (r, g, b));
if (bgset !== null) {
bg = Image.open(background);
bg = bg.resize((1024,1024));
bg.paste(roboimg,(0,0),roboimg);
roboimg = bg
self.img = roboimg.resize((sizex,sizey),Image.ANTIALIAS)
self.format = format;
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment