Identicons #542

Merged
Atheros1 merged 26 commits from master into master 2013-11-02 23:16:08 +01:00
2 changed files with 98 additions and 164 deletions
Showing only changes of commit 0959c9c07c - Show all commits

View File

@ -56,54 +56,68 @@ def _translate(context, text):
return QtGui.QApplication.translate(context, text)
def identiconize(address):
youdontwantidenticons = False
if youdontwantidenticons == True:
idcon = QtGui.QIcon()
return idcon
size = 3
size = 1
str_broadcast_subscribers = '[Broadcast subscribers]'
if address == str_broadcast_subscribers:
idcon = QtGui.QIcon(":/newPrefix/images/can-icon-24px.png")
return idcon
suffix = "asdf"
try:
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
# 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
# i think it should generate a random string by default
try:
identicon_lib = shared.config.get('bitmessagesettings', 'identicon')
except:
identicon_lib = 'qidenticon'
if identicon_lib == 'qidenticon':
if (identicon_lib[:len('qidenticon')] == 'qidenticon'):
# print identicon_lib
# originally by:
# :Author:Shin Adachi <shn@glucose.jp>
# Licesensed under FreeBSD License.
# stripped from PIL and uses QT instead
import qidenticon
import hashlib
hash = hashlib.md5(addBMIfNotPresent(address)+suffix).hexdigest()
image = qidenticon.render_identicon(int(hash, 16), 48)
hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest()
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.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off)
idcon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.Off)
return idcon
elif identicon_lib == 'pydenticon': # pydenticon.py
elif identicon_lib == 'pydenticon':
# print identicon_lib
# load another identicon code
# http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py
# Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source)
from pydenticon import Pydenticon
# GPLv3 !!!
idcon_render = Pydenticon(addBMIfNotPresent(address)+suffix)
image = idcon_render._render()
# im = Image.open('images/'+hash+'.png')
# http://stackoverflow.com/questions/6756820/python-pil-image-tostring
data = image.convert("RGBA").tostring("raw", "RGBA")
image = QImage(data, image.size[0], image.size[1], QImage.Format_ARGB32)
pix = QPixmap.fromImage(image)
# It is not included in the source, because it is licensed under GPLv3
# GPLv3 is a copyleft license that would influence our licensing
# Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py
# note that it requires PIL to be installed: http://www.pythonware.com/products/pil/
idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size)
rendering = idcon_render._render()
data = rendering.convert("RGBA").tostring("raw", "RGBA")
qim = QImage(data, size, size, QImage.Format_ARGB32)
pix = QPixmap.fromImage(qim)
idcon = QtGui.QIcon()
idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off)
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):

View File

@ -41,9 +41,6 @@ by Shin Adachi <shn@glucose.jp>
= usage =
== commandline ==
>>> python identicon.py [code]
== python ==
>>> import qtidenticon
>>> qtidenticon.render_identicon(code, size)
@ -59,80 +56,6 @@ from PyQt4.QtGui import *
__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):
PATH_SET = []
@ -144,7 +67,7 @@ class IdenticonRendererBase(object):
code = int(code)
self.code = code
def render(self, size):
def render(self, size, twoColor, transparent, penwidth):
"""
render identicon to QPixmap
@ -153,30 +76,34 @@ class IdenticonRendererBase(object):
"""
# 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
image = QPixmap(QSize(size * 3, size * 3))
image = QPixmap(QSize(size * 3 +penwidth, size * 3 +penwidth))
# fill background
image.fill(QtGui.QColor(0,0,0))
backColor = QtGui.QColor(255,255,255,(not transparent) * 255)
image.fill(backColor)
kwds = {
'image': image,
'size': size,
'foreColor': foreColor,
'foreColor': foreColor if swap_cross else secondColor,
'penwidth': penwidth,
'backColor': backColor}
# middle patch
image = self.drawPatchQt((1, 1), middle[2], middle[1], middle[0], **kwds)
# side patch
kwds['foreColor'] = foreColor
kwds['type'] = side[0]
for i in xrange(4):
pos = [(1, 0), (2, 1), (1, 2), (0, 1)][i]
image = self.drawPatchQt(pos, side[2] + 1 + i, side[1], **kwds)
# corner patch
kwds['foreColor'] = secondColor
kwds['type'] = corner[0]
for i in xrange(4):
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,
backColor):
backColor, penwidth):
"""
@param size patch size
"""
@ -200,28 +127,35 @@ class IdenticonRendererBase(object):
polygon = QPolygonF([QPointF(x*size,y*size) for x,y in path])
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]
# print rotation[rot], rot_trans[rot], turn
pen_color = QtGui.QColor(255, 255, 255, 0)
pen = QtGui.QPen(pen_color, Qt.SolidPattern)
nopen = QtGui.QPen(foreColor, Qt.NoPen)
foreBrush = QtGui.QBrush(foreColor, Qt.SolidPattern)
backBrush = QtGui.QBrush(backColor, Qt.SolidPattern)
if invert:
foreBrush, backBrush = backBrush, foreBrush
if penwidth > 0:
pen_color = QtGui.QColor(223, 223, 223)
pen = QtGui.QPen(pen_color, Qt.SolidPattern)
pen.setWidth(penwidth)
painter = QPainter()
painter.begin(image)
painter.setPen(pen)
painter.setPen(nopen)
painter.translate(pos[0]*size, pos[1]*size)
painter.translate(rot_trans[rot])
painter.translate(pos[0]*size +penwidth/2, pos[1]*size +penwidth/2)
painter.translate(rect[rot])
painter.rotate(rotation[rot])
painter.setBrush(backBrush)
painter.drawRect(0,0, size, size)
if invert:
# subtract the actual polygon from a rectangle to invert it
rect_polygon = QPolygonF(rect)
polygon = rect_polygon.subtracted(polygon)
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.end()
@ -263,56 +197,42 @@ class DonRenderer(IdenticonRendererBase):
p = map(lambda vec: (vec[0] / 4.0, vec[1] / 4.0), PATH_SET[idx])
PATH_SET[idx] = p + p[:1]
def decode(self, code):
def decode(self, code, twoColor):
# 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
# bug reported by Masato Hagiwara
# http://lilyx.net/iconlang-en/
# blue = (code >> 16) & 0x1F
# green = (code >> 21) & 0x1F
blue = (code >> 17) & 0x1F
green = (code >> 22) & 0x1F
red = (code >> 27) & 0x1F
shift = 0; middleType = (code >> shift) & 0x03
shift += 2; middleInvert= (code >> shift) & 0x01
shift += 1; cornerType = (code >> shift) & 0x0F
shift += 4; cornerInvert= (code >> shift) & 0x01
shift += 1; cornerTurn = (code >> shift) & 0x03
shift += 2; sideType = (code >> shift) & 0x0F
shift += 4; sideInvert = (code >> shift) & 0x01
shift += 1; sideTurn = (code >> shift) & 0x03
shift += 2; blue = (code >> shift) & 0x1F
shift += 5; green = (code >> shift) & 0x1F
shift += 5; red = (code >> shift) & 0x1F
shift += 5; second_blue = (code >> shift) & 0x1F
shift += 5; second_green= (code >> shift) & 0x1F
shift += 5; second_red = (code >> shift) & 0x1F
shift += 1; swap_cross = (code >> shift) & 0x01
middleType = self.MIDDLE_PATCH_SET[middleType]
foreColor = (red << 3, green << 3, blue << 3)
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),\
(cornerType, cornerInvert, cornerTurn),\
(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:
renderer = DonRenderer
return renderer(code).render(size)
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')
return renderer(code).render(size, twoColor, transparent, penwidth)