Identicons #542
|
@ -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
|
||||
|
||||
identicon_lib = 'qidenticon'
|
||||
if identicon_lib == 'qidenticon':
|
||||
try:
|
||||
identicon_lib = shared.config.get('bitmessagesettings', 'identicon')
|
||||
except:
|
||||
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):
|
||||
|
||||
|
|
|
@ -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)
|
Reference in New Issue
Block a user