|
@@ -26,7 +26,9 @@ __all__ = ['render_identicon', 'IdenticonRendererBase']
|
|
|
|
|
|
|
|
|
|
class Matrix2D(list):
|
|
class Matrix2D(list):
|
|
|
|
+
|
|
"""Matrix for Patch rotation"""
|
|
"""Matrix for Patch rotation"""
|
|
|
|
+
|
|
def __init__(self, initial=[0.] * 9):
|
|
def __init__(self, initial=[0.] * 9):
|
|
assert isinstance(initial, list) and len(initial) == 9
|
|
assert isinstance(initial, list) and len(initial) == 9
|
|
list.__init__(self, initial)
|
|
list.__init__(self, initial)
|
|
@@ -84,7 +86,7 @@ class Matrix2D(list):
|
|
return kls.translate(-pivot[0], -pivot[1]) * matR *
|
|
return kls.translate(-pivot[0], -pivot[1]) * matR *
|
|
kls.translate(*pivot)
|
|
kls.translate(*pivot)
|
|
"""
|
|
"""
|
|
-
|
|
|
|
|
|
+
|
|
@classmethod
|
|
@classmethod
|
|
def rotateSquare(kls, theta, pivot=None):
|
|
def rotateSquare(kls, theta, pivot=None):
|
|
theta = theta % 4
|
|
theta = theta % 4
|
|
@@ -100,7 +102,7 @@ class Matrix2D(list):
|
|
|
|
|
|
class IdenticonRendererBase(object):
|
|
class IdenticonRendererBase(object):
|
|
PATH_SET = []
|
|
PATH_SET = []
|
|
-
|
|
|
|
|
|
+
|
|
def __init__(self, code):
|
|
def __init__(self, code):
|
|
"""
|
|
"""
|
|
@param code code for icon
|
|
@param code code for icon
|
|
@@ -108,25 +110,25 @@ class IdenticonRendererBase(object):
|
|
if not isinstance(code, int):
|
|
if not isinstance(code, int):
|
|
code = int(code)
|
|
code = int(code)
|
|
self.code = code
|
|
self.code = code
|
|
-
|
|
|
|
|
|
+
|
|
def render(self, size):
|
|
def render(self, size):
|
|
"""
|
|
"""
|
|
render identicon to PIL.Image
|
|
render identicon to PIL.Image
|
|
-
|
|
|
|
|
|
+
|
|
@param size identicon patchsize. (image size is 3 * [size])
|
|
@param size identicon patchsize. (image size is 3 * [size])
|
|
@return PIL.Image
|
|
@return PIL.Image
|
|
"""
|
|
"""
|
|
-
|
|
|
|
|
|
+
|
|
# decode the code
|
|
# decode the code
|
|
middle, corner, side, foreColor, backColor = self.decode(self.code)
|
|
middle, corner, side, foreColor, backColor = self.decode(self.code)
|
|
size = int(size)
|
|
size = int(size)
|
|
- # make image
|
|
|
|
|
|
+ # make image
|
|
image = Image.new("RGB", (size * 3, size * 3))
|
|
image = Image.new("RGB", (size * 3, size * 3))
|
|
draw = ImageDraw.Draw(image)
|
|
draw = ImageDraw.Draw(image)
|
|
-
|
|
|
|
|
|
+
|
|
# fill background
|
|
# fill background
|
|
draw.rectangle((0, 0, image.size[0], image.size[1]), fill=0)
|
|
draw.rectangle((0, 0, image.size[0], image.size[1]), fill=0)
|
|
-
|
|
|
|
|
|
+
|
|
kwds = {
|
|
kwds = {
|
|
'draw': draw,
|
|
'draw': draw,
|
|
'size': size,
|
|
'size': size,
|
|
@@ -140,17 +142,17 @@ class IdenticonRendererBase(object):
|
|
for i in range(4):
|
|
for i in range(4):
|
|
pos = [(1, 0), (2, 1), (1, 2), (0, 1)][i]
|
|
pos = [(1, 0), (2, 1), (1, 2), (0, 1)][i]
|
|
self.drawPatch(pos, side[2] + 1 + i, side[1], **kwds)
|
|
self.drawPatch(pos, side[2] + 1 + i, side[1], **kwds)
|
|
-
|
|
|
|
|
|
+
|
|
# corner patch
|
|
# corner patch
|
|
kwds['type'] = corner[0]
|
|
kwds['type'] = corner[0]
|
|
for i in range(4):
|
|
for i in range(4):
|
|
pos = [(0, 0), (2, 0), (2, 2), (0, 2)][i]
|
|
pos = [(0, 0), (2, 0), (2, 2), (0, 2)][i]
|
|
self.drawPatch(pos, corner[2] + 1 + i, corner[1], **kwds)
|
|
self.drawPatch(pos, corner[2] + 1 + i, corner[1], **kwds)
|
|
-
|
|
|
|
|
|
+
|
|
return image
|
|
return image
|
|
-
|
|
|
|
|
|
+
|
|
def drawPatch(self, pos, turn, invert, type, draw, size, foreColor,
|
|
def drawPatch(self, pos, turn, invert, type, draw, size, foreColor,
|
|
- backColor):
|
|
|
|
|
|
+ backColor):
|
|
"""
|
|
"""
|
|
@param size patch size
|
|
@param size patch size
|
|
"""
|
|
"""
|
|
@@ -162,27 +164,28 @@ class IdenticonRendererBase(object):
|
|
patch = ImagePath.Path(path)
|
|
patch = ImagePath.Path(path)
|
|
if invert:
|
|
if invert:
|
|
foreColor, backColor = backColor, foreColor
|
|
foreColor, backColor = backColor, foreColor
|
|
-
|
|
|
|
|
|
+
|
|
mat = Matrix2D.rotateSquare(turn, pivot=(0.5, 0.5)) *\
|
|
mat = Matrix2D.rotateSquare(turn, pivot=(0.5, 0.5)) *\
|
|
- Matrix2D.translate(*pos) *\
|
|
|
|
- Matrix2D.scale(size, size)
|
|
|
|
-
|
|
|
|
|
|
+ Matrix2D.translate(*pos) *\
|
|
|
|
+ Matrix2D.scale(size, size)
|
|
|
|
+
|
|
patch.transform(mat.for_PIL())
|
|
patch.transform(mat.for_PIL())
|
|
draw.rectangle((pos[0] * size, pos[1] * size, (pos[0] + 1) * size,
|
|
draw.rectangle((pos[0] * size, pos[1] * size, (pos[0] + 1) * size,
|
|
- (pos[1] + 1) * size), fill=backColor)
|
|
|
|
|
|
+ (pos[1] + 1) * size), fill=backColor)
|
|
draw.polygon(patch, fill=foreColor, outline=foreColor)
|
|
draw.polygon(patch, fill=foreColor, outline=foreColor)
|
|
|
|
|
|
- ### virtual functions
|
|
|
|
|
|
+ # virtual functions
|
|
def decode(self, code):
|
|
def decode(self, code):
|
|
raise NotImplementedError
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
class DonRenderer(IdenticonRendererBase):
|
|
class DonRenderer(IdenticonRendererBase):
|
|
|
|
+
|
|
"""
|
|
"""
|
|
Don Park's implementation of identicon
|
|
Don Park's implementation of identicon
|
|
see : http://www.docuverse.com/blog/donpark/2007/01/19/identicon-updated-and-source-released
|
|
see : http://www.docuverse.com/blog/donpark/2007/01/19/identicon-updated-and-source-released
|
|
"""
|
|
"""
|
|
-
|
|
|
|
|
|
+
|
|
PATH_SET = [
|
|
PATH_SET = [
|
|
[(0, 0), (4, 0), (4, 4), (0, 4)], # 0
|
|
[(0, 0), (4, 0), (4, 4), (0, 4)], # 0
|
|
[(0, 0), (4, 0), (0, 4)],
|
|
[(0, 0), (4, 0), (0, 4)],
|
|
@@ -192,7 +195,7 @@ class DonRenderer(IdenticonRendererBase):
|
|
[(0, 0), (4, 2), (4, 4), (2, 4)],
|
|
[(0, 0), (4, 2), (4, 4), (2, 4)],
|
|
[(2, 0), (4, 4), (2, 4), (3, 2), (1, 2), (2, 4), (0, 4)],
|
|
[(2, 0), (4, 4), (2, 4), (3, 2), (1, 2), (2, 4), (0, 4)],
|
|
[(0, 0), (4, 2), (2, 4)],
|
|
[(0, 0), (4, 2), (2, 4)],
|
|
- [(1, 1), (3, 1), (3, 3), (1, 3)], # 8
|
|
|
|
|
|
+ [(1, 1), (3, 1), (3, 3), (1, 3)], # 8
|
|
[(2, 0), (4, 0), (0, 4), (0, 2), (2, 2)],
|
|
[(2, 0), (4, 0), (0, 4), (0, 2), (2, 2)],
|
|
[(0, 0), (2, 0), (2, 2), (0, 2)],
|
|
[(0, 0), (2, 0), (2, 2), (0, 2)],
|
|
[(0, 2), (4, 2), (2, 4)],
|
|
[(0, 2), (4, 2), (2, 4)],
|
|
@@ -201,34 +204,34 @@ class DonRenderer(IdenticonRendererBase):
|
|
[(0, 0), (2, 0), (0, 2)],
|
|
[(0, 0), (2, 0), (0, 2)],
|
|
[]] # 15
|
|
[]] # 15
|
|
MIDDLE_PATCH_SET = [0, 4, 8, 15]
|
|
MIDDLE_PATCH_SET = [0, 4, 8, 15]
|
|
-
|
|
|
|
|
|
+
|
|
# modify path set
|
|
# modify path set
|
|
for idx in range(len(PATH_SET)):
|
|
for idx in range(len(PATH_SET)):
|
|
if PATH_SET[idx]:
|
|
if PATH_SET[idx]:
|
|
p = map(lambda vec: (vec[0] / 4.0, vec[1] / 4.0), PATH_SET[idx])
|
|
p = map(lambda vec: (vec[0] / 4.0, vec[1] / 4.0), PATH_SET[idx])
|
|
p = list(p)
|
|
p = list(p)
|
|
PATH_SET[idx] = p + p[:1]
|
|
PATH_SET[idx] = p + p[:1]
|
|
-
|
|
|
|
|
|
+
|
|
def decode(self, code):
|
|
def decode(self, code):
|
|
- # decode the code
|
|
|
|
- middleType = self.MIDDLE_PATCH_SET[code & 0x03]
|
|
|
|
- middleInvert= (code >> 2) & 0x01
|
|
|
|
- cornerType = (code >> 3) & 0x0F
|
|
|
|
- cornerInvert= (code >> 7) & 0x01
|
|
|
|
- cornerTurn = (code >> 8) & 0x03
|
|
|
|
- sideType = (code >> 10) & 0x0F
|
|
|
|
- sideInvert = (code >> 14) & 0x01
|
|
|
|
- sideTurn = (code >> 15) & 0x03
|
|
|
|
- blue = (code >> 16) & 0x1F
|
|
|
|
- green = (code >> 21) & 0x1F
|
|
|
|
- red = (code >> 27) & 0x1F
|
|
|
|
-
|
|
|
|
|
|
+ # decode the code
|
|
|
|
+ middleType = self.MIDDLE_PATCH_SET[code & 0x03]
|
|
|
|
+ middleInvert = (code >> 2) & 0x01
|
|
|
|
+ cornerType = (code >> 3) & 0x0F
|
|
|
|
+ cornerInvert = (code >> 7) & 0x01
|
|
|
|
+ cornerTurn = (code >> 8) & 0x03
|
|
|
|
+ sideType = (code >> 10) & 0x0F
|
|
|
|
+ sideInvert = (code >> 14) & 0x01
|
|
|
|
+ sideTurn = (code >> 15) & 0x03
|
|
|
|
+ blue = (code >> 16) & 0x1F
|
|
|
|
+ green = (code >> 21) & 0x1F
|
|
|
|
+ red = (code >> 27) & 0x1F
|
|
|
|
+
|
|
foreColor = (red << 3, green << 3, blue << 3)
|
|
foreColor = (red << 3, green << 3, blue << 3)
|
|
-
|
|
|
|
|
|
+
|
|
return (middleType, middleInvert, 0),\
|
|
return (middleType, middleInvert, 0),\
|
|
(cornerType, cornerInvert, cornerTurn),\
|
|
(cornerType, cornerInvert, cornerTurn),\
|
|
(sideType, sideInvert, sideTurn),\
|
|
(sideType, sideInvert, sideTurn),\
|
|
- foreColor, ImageColor.getrgb('white')
|
|
|
|
|
|
+ foreColor, ImageColor.getrgb('white')
|
|
|
|
|
|
|
|
|
|
def render_identicon(code, size, renderer=None):
|
|
def render_identicon(code, size, renderer=None):
|
|
@@ -239,11 +242,11 @@ def render_identicon(code, size, renderer=None):
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if __name__ == '__main__':
|
|
import sys
|
|
import sys
|
|
-
|
|
|
|
|
|
+
|
|
if len(sys.argv) < 2:
|
|
if len(sys.argv) < 2:
|
|
print('usage: python identicon.py [CODE]....')
|
|
print('usage: python identicon.py [CODE]....')
|
|
raise SystemExit
|
|
raise SystemExit
|
|
-
|
|
|
|
|
|
+
|
|
for code in sys.argv[1:]:
|
|
for code in sys.argv[1:]:
|
|
if code.startswith('0x') or code.startswith('0X'):
|
|
if code.startswith('0x') or code.startswith('0X'):
|
|
code = int(code[2:], 16)
|
|
code = int(code[2:], 16)
|
|
@@ -251,6 +254,6 @@ if __name__ == '__main__':
|
|
code = int(code[1:], 8)
|
|
code = int(code[1:], 8)
|
|
else:
|
|
else:
|
|
code = int(code)
|
|
code = int(code)
|
|
-
|
|
|
|
|
|
+
|
|
icon = render_identicon(code, 24)
|
|
icon = render_identicon(code, 24)
|
|
icon.save('%08x.png' % code, 'PNG')
|
|
icon.save('%08x.png' % code, 'PNG')
|