From 0959c9c07c2534d12bdde3c62060e07c1dfad61b Mon Sep 17 00:00:00 2001 From: sendiulo Date: Tue, 17 Sep 2013 10:55:26 +0200 Subject: [PATCH] ... --- src/bitmessageqt/__init__.py | 64 ++++++----- src/qidenticon.py | 198 +++++++++++------------------------ 2 files changed, 98 insertions(+), 164 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1ceca0eb..42ccb7ae 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -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 # 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): diff --git a/src/qidenticon.py b/src/qidenticon.py index 5d77aeb6..ffc25eea 100644 --- a/src/qidenticon.py +++ b/src/qidenticon.py @@ -41,9 +41,6 @@ by Shin Adachi = 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,30 +127,37 @@ 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() return image @@ -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): - # 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 + def decode(self, code, twoColor): + # decode the code + 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) \ No newline at end of file