Identicons #542
|
@ -56,54 +56,68 @@ def _translate(context, text):
|
||||||
return QtGui.QApplication.translate(context, text)
|
return QtGui.QApplication.translate(context, text)
|
||||||
|
|
||||||
def identiconize(address):
|
def identiconize(address):
|
||||||
youdontwantidenticons = False
|
size = 1
|
||||||
if youdontwantidenticons == True:
|
|
||||||
idcon = QtGui.QIcon()
|
|
||||||
return idcon
|
|
||||||
size = 3
|
|
||||||
|
|
||||||
str_broadcast_subscribers = '[Broadcast subscribers]'
|
str_broadcast_subscribers = '[Broadcast subscribers]'
|
||||||
if address == str_broadcast_subscribers:
|
if address == str_broadcast_subscribers:
|
||||||
idcon = QtGui.QIcon(":/newPrefix/images/can-icon-24px.png")
|
idcon = QtGui.QIcon(":/newPrefix/images/can-icon-24px.png")
|
||||||
return idcon
|
return idcon
|
||||||
|
try:
|
||||||
suffix = "asdf"
|
identiconsuffix = shared.config.get('bitmessagesettings', 'identiconsuffix')
|
||||||
|
except:
|
||||||
|
identiconsuffix = ''
|
||||||
# here you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators
|
# here you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators
|
||||||
# instead, you could also use a pseudo-password to salt the generation of the identicons
|
# instead, you could also use a pseudo-password to salt the generation of the identicons
|
||||||
# Attacks where someone creates an address to mimic someone else's identicon should be impossible then
|
# Attacks where someone creates an address to mimic someone else's identicon should be impossible then
|
||||||
# i think it should generate a random string by default
|
# i think it should generate a random string by default
|
||||||
|
|
||||||
identicon_lib = 'qidenticon'
|
try:
|
||||||
if identicon_lib == 'qidenticon':
|
identicon_lib = shared.config.get('bitmessagesettings', 'identicon')
|
||||||
|
except:
|
||||||
|
identicon_lib = 'qidenticon'
|
||||||
|
|
||||||
|
|
||||||
|
if (identicon_lib[:len('qidenticon')] == 'qidenticon'):
|
||||||
|
# print identicon_lib
|
||||||
# originally by:
|
# originally by:
|
||||||
# :Author:Shin Adachi <shn@glucose.jp>
|
# :Author:Shin Adachi <shn@glucose.jp>
|
||||||
# Licesensed under FreeBSD License.
|
# Licesensed under FreeBSD License.
|
||||||
# stripped from PIL and uses QT instead
|
# stripped from PIL and uses QT instead
|
||||||
import qidenticon
|
import qidenticon
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
hash = hashlib.md5(addBMIfNotPresent(address)+suffix).hexdigest()
|
hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest()
|
||||||
image = qidenticon.render_identicon(int(hash, 16), 48)
|
use_two_colors = (identicon_lib[:len('qidenticon_two')] == 'qidenticon_two')
|
||||||
|
transparent = (identicon_lib == 'qidenticon_x') | (identicon_lib == 'qidenticon_two_x')
|
||||||
|
penwidth = 0
|
||||||
|
pixmap = qidenticon.render_identicon(int(hash, 16), 48, use_two_colors, transparent, penwidth)
|
||||||
idcon = QtGui.QIcon()
|
idcon = QtGui.QIcon()
|
||||||
idcon.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
idcon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
return idcon
|
return idcon
|
||||||
|
elif identicon_lib == 'pydenticon':
|
||||||
elif identicon_lib == 'pydenticon': # pydenticon.py
|
|
||||||
# print identicon_lib
|
# print identicon_lib
|
||||||
# load another identicon code
|
# Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source)
|
||||||
# http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py
|
|
||||||
from pydenticon import Pydenticon
|
from pydenticon import Pydenticon
|
||||||
# GPLv3 !!!
|
# It is not included in the source, because it is licensed under GPLv3
|
||||||
idcon_render = Pydenticon(addBMIfNotPresent(address)+suffix)
|
# GPLv3 is a copyleft license that would influence our licensing
|
||||||
image = idcon_render._render()
|
# Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py
|
||||||
# im = Image.open('images/'+hash+'.png')
|
# note that it requires PIL to be installed: http://www.pythonware.com/products/pil/
|
||||||
# http://stackoverflow.com/questions/6756820/python-pil-image-tostring
|
idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size)
|
||||||
data = image.convert("RGBA").tostring("raw", "RGBA")
|
rendering = idcon_render._render()
|
||||||
image = QImage(data, image.size[0], image.size[1], QImage.Format_ARGB32)
|
data = rendering.convert("RGBA").tostring("raw", "RGBA")
|
||||||
pix = QPixmap.fromImage(image)
|
qim = QImage(data, size, size, QImage.Format_ARGB32)
|
||||||
|
pix = QPixmap.fromImage(qim)
|
||||||
idcon = QtGui.QIcon()
|
idcon = QtGui.QIcon()
|
||||||
idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
return idcon
|
return idcon
|
||||||
|
elif identicon_lib == False:
|
||||||
|
idcon = QtGui.QIcon()
|
||||||
|
return idcon
|
||||||
|
else:
|
||||||
|
if identicon_lib & len(identicon_lib) > 0:
|
||||||
|
print 'Error: couldn\'t find this identicon library: ', identicon_lib
|
||||||
|
print 'Control for typos!'
|
||||||
|
idcon = QtGui.QIcon()
|
||||||
|
return idcon
|
||||||
|
|
||||||
class MyForm(QtGui.QMainWindow):
|
class MyForm(QtGui.QMainWindow):
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,6 @@ by Shin Adachi <shn@glucose.jp>
|
||||||
|
|
||||||
= usage =
|
= usage =
|
||||||
|
|
||||||
== commandline ==
|
|
||||||
>>> python identicon.py [code]
|
|
||||||
|
|
||||||
== python ==
|
== python ==
|
||||||
>>> import qtidenticon
|
>>> import qtidenticon
|
||||||
>>> qtidenticon.render_identicon(code, size)
|
>>> qtidenticon.render_identicon(code, size)
|
||||||
|
@ -59,80 +56,6 @@ from PyQt4.QtGui import *
|
||||||
|
|
||||||
__all__ = ['render_identicon', 'IdenticonRendererBase']
|
__all__ = ['render_identicon', 'IdenticonRendererBase']
|
||||||
|
|
||||||
|
|
||||||
class Matrix2D(list):
|
|
||||||
"""Matrix for Patch rotation"""
|
|
||||||
def __init__(self, initial=[0.] * 9):
|
|
||||||
assert isinstance(initial, list) and len(initial) == 9
|
|
||||||
list.__init__(self, initial)
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
for i in xrange(9):
|
|
||||||
self[i] = 0.
|
|
||||||
|
|
||||||
def set_identity(self):
|
|
||||||
self.clear()
|
|
||||||
for i in xrange(3):
|
|
||||||
self[i] = 1.
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '[%s]' % ', '.join('%3.2f' % v for v in self)
|
|
||||||
|
|
||||||
def __mul__(self, other):
|
|
||||||
r = []
|
|
||||||
if isinstance(other, Matrix2D):
|
|
||||||
for y in xrange(3):
|
|
||||||
for x in xrange(3):
|
|
||||||
v = 0.0
|
|
||||||
for i in xrange(3):
|
|
||||||
v += (self[i * 3 + x] * other[y * 3 + i])
|
|
||||||
r.append(v)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
return Matrix2D(r)
|
|
||||||
|
|
||||||
def for_PIL(self):
|
|
||||||
return self[0:6]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def translate(kls, x, y):
|
|
||||||
return kls([1.0, 0.0, float(x),
|
|
||||||
0.0, 1.0, float(y),
|
|
||||||
0.0, 0.0, 1.0])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def scale(kls, x, y):
|
|
||||||
return kls([float(x), 0.0, 0.0,
|
|
||||||
0.0, float(y), 0.0,
|
|
||||||
0.0, 0.0, 1.0])
|
|
||||||
|
|
||||||
"""
|
|
||||||
# need `import math`
|
|
||||||
@classmethod
|
|
||||||
def rotate(kls, theta, pivot=None):
|
|
||||||
c = math.cos(theta)
|
|
||||||
s = math.sin(theta)
|
|
||||||
|
|
||||||
matR = kls([c, -s, 0., s, c, 0., 0., 0., 1.])
|
|
||||||
if not pivot:
|
|
||||||
return matR
|
|
||||||
return kls.translate(-pivot[0], -pivot[1]) * matR *
|
|
||||||
kls.translate(*pivot)
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def rotateSquare(kls, theta, pivot=None):
|
|
||||||
theta = theta % 4
|
|
||||||
c = [1., 0., -1., 0.][theta]
|
|
||||||
s = [0., 1., 0., -1.][theta]
|
|
||||||
|
|
||||||
matR = kls([c, -s, 0., s, c, 0., 0., 0., 1.])
|
|
||||||
if not pivot:
|
|
||||||
return matR
|
|
||||||
return kls.translate(-pivot[0], -pivot[1]) * matR * \
|
|
||||||
kls.translate(*pivot)
|
|
||||||
|
|
||||||
|
|
||||||
class IdenticonRendererBase(object):
|
class IdenticonRendererBase(object):
|
||||||
PATH_SET = []
|
PATH_SET = []
|
||||||
|
|
||||||
|
@ -144,7 +67,7 @@ class IdenticonRendererBase(object):
|
||||||
code = int(code)
|
code = int(code)
|
||||||
self.code = code
|
self.code = code
|
||||||
|
|
||||||
def render(self, size):
|
def render(self, size, twoColor, transparent, penwidth):
|
||||||
"""
|
"""
|
||||||
render identicon to QPixmap
|
render identicon to QPixmap
|
||||||
|
|
||||||
|
@ -153,30 +76,34 @@ class IdenticonRendererBase(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# decode the code
|
# decode the code
|
||||||
middle, corner, side, foreColor, backColor = self.decode(self.code)
|
middle, corner, side, foreColor, secondColor, swap_cross = self.decode(self.code, twoColor)
|
||||||
|
|
||||||
# make image
|
# make image
|
||||||
image = QPixmap(QSize(size * 3, size * 3))
|
image = QPixmap(QSize(size * 3 +penwidth, size * 3 +penwidth))
|
||||||
|
|
||||||
# fill background
|
# fill background
|
||||||
image.fill(QtGui.QColor(0,0,0))
|
backColor = QtGui.QColor(255,255,255,(not transparent) * 255)
|
||||||
|
image.fill(backColor)
|
||||||
|
|
||||||
kwds = {
|
kwds = {
|
||||||
'image': image,
|
'image': image,
|
||||||
'size': size,
|
'size': size,
|
||||||
'foreColor': foreColor,
|
'foreColor': foreColor if swap_cross else secondColor,
|
||||||
|
'penwidth': penwidth,
|
||||||
'backColor': backColor}
|
'backColor': backColor}
|
||||||
|
|
||||||
# middle patch
|
# middle patch
|
||||||
image = self.drawPatchQt((1, 1), middle[2], middle[1], middle[0], **kwds)
|
image = self.drawPatchQt((1, 1), middle[2], middle[1], middle[0], **kwds)
|
||||||
|
|
||||||
# side patch
|
# side patch
|
||||||
|
kwds['foreColor'] = foreColor
|
||||||
kwds['type'] = side[0]
|
kwds['type'] = side[0]
|
||||||
for i in xrange(4):
|
for i in xrange(4):
|
||||||
pos = [(1, 0), (2, 1), (1, 2), (0, 1)][i]
|
pos = [(1, 0), (2, 1), (1, 2), (0, 1)][i]
|
||||||
image = self.drawPatchQt(pos, side[2] + 1 + i, side[1], **kwds)
|
image = self.drawPatchQt(pos, side[2] + 1 + i, side[1], **kwds)
|
||||||
|
|
||||||
# corner patch
|
# corner patch
|
||||||
|
kwds['foreColor'] = secondColor
|
||||||
kwds['type'] = corner[0]
|
kwds['type'] = corner[0]
|
||||||
for i in xrange(4):
|
for i in xrange(4):
|
||||||
pos = [(0, 0), (2, 0), (2, 2), (0, 2)][i]
|
pos = [(0, 0), (2, 0), (2, 2), (0, 2)][i]
|
||||||
|
@ -186,7 +113,7 @@ class IdenticonRendererBase(object):
|
||||||
|
|
||||||
|
|
||||||
def drawPatchQt(self, pos, turn, invert, type, image, size, foreColor,
|
def drawPatchQt(self, pos, turn, invert, type, image, size, foreColor,
|
||||||
backColor):
|
backColor, penwidth):
|
||||||
"""
|
"""
|
||||||
@param size patch size
|
@param size patch size
|
||||||
"""
|
"""
|
||||||
|
@ -200,28 +127,35 @@ class IdenticonRendererBase(object):
|
||||||
polygon = QPolygonF([QPointF(x*size,y*size) for x,y in path])
|
polygon = QPolygonF([QPointF(x*size,y*size) for x,y in path])
|
||||||
|
|
||||||
rot = turn % 4
|
rot = turn % 4
|
||||||
rot_trans = [QPointF(0.,0.), QPointF(size, 0.), QPointF(size, size), QPointF(0., size)]
|
rect = [QPointF(0.,0.), QPointF(size, 0.), QPointF(size, size), QPointF(0., size)]
|
||||||
rotation = [0,90,180,270]
|
rotation = [0,90,180,270]
|
||||||
# print rotation[rot], rot_trans[rot], turn
|
|
||||||
pen_color = QtGui.QColor(255, 255, 255, 0)
|
nopen = QtGui.QPen(foreColor, Qt.NoPen)
|
||||||
pen = QtGui.QPen(pen_color, Qt.SolidPattern)
|
|
||||||
foreBrush = QtGui.QBrush(foreColor, Qt.SolidPattern)
|
foreBrush = QtGui.QBrush(foreColor, Qt.SolidPattern)
|
||||||
backBrush = QtGui.QBrush(backColor, Qt.SolidPattern)
|
if penwidth > 0:
|
||||||
if invert:
|
pen_color = QtGui.QColor(223, 223, 223)
|
||||||
foreBrush, backBrush = backBrush, foreBrush
|
pen = QtGui.QPen(pen_color, Qt.SolidPattern)
|
||||||
|
pen.setWidth(penwidth)
|
||||||
|
|
||||||
painter = QPainter()
|
painter = QPainter()
|
||||||
painter.begin(image)
|
painter.begin(image)
|
||||||
painter.setPen(pen)
|
painter.setPen(nopen)
|
||||||
|
|
||||||
painter.translate(pos[0]*size, pos[1]*size)
|
painter.translate(pos[0]*size +penwidth/2, pos[1]*size +penwidth/2)
|
||||||
painter.translate(rot_trans[rot])
|
painter.translate(rect[rot])
|
||||||
painter.rotate(rotation[rot])
|
painter.rotate(rotation[rot])
|
||||||
|
|
||||||
painter.setBrush(backBrush)
|
if invert:
|
||||||
painter.drawRect(0,0, size, size)
|
# subtract the actual polygon from a rectangle to invert it
|
||||||
|
rect_polygon = QPolygonF(rect)
|
||||||
|
polygon = rect_polygon.subtracted(polygon)
|
||||||
painter.setBrush(foreBrush)
|
painter.setBrush(foreBrush)
|
||||||
|
if penwidth > 0:
|
||||||
|
# draw the borders
|
||||||
|
painter.setPen(pen)
|
||||||
|
painter.drawPolygon(polygon, Qt.WindingFill)
|
||||||
|
# draw the fill
|
||||||
|
painter.setPen(nopen)
|
||||||
painter.drawPolygon(polygon, Qt.WindingFill)
|
painter.drawPolygon(polygon, Qt.WindingFill)
|
||||||
|
|
||||||
painter.end()
|
painter.end()
|
||||||
|
@ -263,56 +197,42 @@ class DonRenderer(IdenticonRendererBase):
|
||||||
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])
|
||||||
PATH_SET[idx] = p + p[:1]
|
PATH_SET[idx] = p + p[:1]
|
||||||
|
|
||||||
def decode(self, code):
|
def decode(self, code, twoColor):
|
||||||
# decode the code
|
# decode the code
|
||||||
middleType = self.MIDDLE_PATCH_SET[code & 0x03]
|
shift = 0; middleType = (code >> shift) & 0x03
|
||||||
middleInvert= (code >> 2) & 0x01
|
shift += 2; middleInvert= (code >> shift) & 0x01
|
||||||
cornerType = (code >> 3) & 0x0F
|
shift += 1; cornerType = (code >> shift) & 0x0F
|
||||||
cornerInvert= (code >> 7) & 0x01
|
shift += 4; cornerInvert= (code >> shift) & 0x01
|
||||||
cornerTurn = (code >> 8) & 0x03
|
shift += 1; cornerTurn = (code >> shift) & 0x03
|
||||||
sideType = (code >> 10) & 0x0F
|
shift += 2; sideType = (code >> shift) & 0x0F
|
||||||
sideInvert = (code >> 14) & 0x01
|
shift += 4; sideInvert = (code >> shift) & 0x01
|
||||||
sideTurn = (code >> 15) & 0x03
|
shift += 1; sideTurn = (code >> shift) & 0x03
|
||||||
# bug reported by Masato Hagiwara
|
shift += 2; blue = (code >> shift) & 0x1F
|
||||||
# http://lilyx.net/iconlang-en/
|
shift += 5; green = (code >> shift) & 0x1F
|
||||||
# blue = (code >> 16) & 0x1F
|
shift += 5; red = (code >> shift) & 0x1F
|
||||||
# green = (code >> 21) & 0x1F
|
shift += 5; second_blue = (code >> shift) & 0x1F
|
||||||
blue = (code >> 17) & 0x1F
|
shift += 5; second_green= (code >> shift) & 0x1F
|
||||||
green = (code >> 22) & 0x1F
|
shift += 5; second_red = (code >> shift) & 0x1F
|
||||||
red = (code >> 27) & 0x1F
|
shift += 1; swap_cross = (code >> shift) & 0x01
|
||||||
|
|
||||||
|
middleType = self.MIDDLE_PATCH_SET[middleType]
|
||||||
|
|
||||||
foreColor = (red << 3, green << 3, blue << 3)
|
foreColor = (red << 3, green << 3, blue << 3)
|
||||||
foreColor = QtGui.QColor(*foreColor)
|
foreColor = QtGui.QColor(*foreColor)
|
||||||
|
|
||||||
bgcolor = QtGui.QColor(255,255,255)
|
if twoColor:
|
||||||
|
secondColor = (second_blue << 3, second_green << 3, second_red << 3)
|
||||||
|
secondColor = QtGui.QColor(*secondColor)
|
||||||
|
else:
|
||||||
|
secondColor = foreColor
|
||||||
|
|
||||||
return (middleType, middleInvert, 0),\
|
return (middleType, middleInvert, 0),\
|
||||||
(cornerType, cornerInvert, cornerTurn),\
|
(cornerType, cornerInvert, cornerTurn),\
|
||||||
(sideType, sideInvert, sideTurn),\
|
(sideType, sideInvert, sideTurn),\
|
||||||
foreColor, bgcolor
|
foreColor, secondColor, swap_cross
|
||||||
|
|
||||||
|
|
||||||
def render_identicon(code, size, renderer=None):
|
def render_identicon(code, size, twoColor=False, transparent=False, penwidth=0, renderer=None):
|
||||||
if not renderer:
|
if not renderer:
|
||||||
renderer = DonRenderer
|
renderer = DonRenderer
|
||||||
return renderer(code).render(size)
|
return renderer(code).render(size, twoColor, transparent, penwidth)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print 'usage: python identicon.py [CODE]....'
|
|
||||||
raise SystemExit
|
|
||||||
|
|
||||||
for code in sys.argv[1:]:
|
|
||||||
if code.startswith('0x') or code.startswith('0X'):
|
|
||||||
code = int(code[2:], 16)
|
|
||||||
elif code.startswith('0'):
|
|
||||||
code = int(code[1:], 8)
|
|
||||||
else:
|
|
||||||
code = int(code)
|
|
||||||
|
|
||||||
app = Qt.QApplication(sys.argv)
|
|
||||||
icon = render_identicon(code, 24)
|
|
||||||
icon.save('%08x.png' % code, 'PNG')
|
|
Reference in New Issue
Block a user