tqrcodewidget.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
tqrcodewidget.py (3689B)
---
1 ''' Kivy Widget that accepts data and displays qrcode
2 '''
3
4 from threading import Thread
5 from functools import partial
6
7 import qrcode
8 from qrcode import exceptions
9
10 from kivy.uix.floatlayout import FloatLayout
11 from kivy.graphics.texture import Texture
12 from kivy.properties import StringProperty
13 from kivy.properties import ObjectProperty, StringProperty, ListProperty,\
14 BooleanProperty
15 from kivy.lang import Builder
16 from kivy.clock import Clock
17
18
19
20 Builder.load_string('''
21 <QRCodeWidget>
22 canvas.before:
23 # Draw white Rectangle
24 Color:
25 rgba: root.background_color
26 Rectangle:
27 size: self.size
28 pos: self.pos
29 canvas.after:
30 Color:
31 rgba: root.foreground_color
32 Rectangle:
33 size: self.size
34 pos: self.pos
35 Image
36 id: qrimage
37 pos_hint: {'center_x': .5, 'center_y': .5}
38 allow_stretch: True
39 size_hint: None, None
40 size: root.width * .9, root.height * .9
41 ''')
42
43 class QRCodeWidget(FloatLayout):
44
45 data = StringProperty(None, allow_none=True)
46 background_color = ListProperty((1, 1, 1, 1))
47 foreground_color = ListProperty((0, 0, 0, 0))
48
49 def __init__(self, **kwargs):
50 super(QRCodeWidget, self).__init__(**kwargs)
51 self.data = None
52 self.qr = None
53 self._qrtexture = None
54 self.failure_cb = None
55
56 def on_data(self, instance, value):
57 if not (self.canvas or value):
58 return
59 try:
60 self.update_qr()
61 except qrcode.exceptions.DataOverflowError:
62 if self.failure_cb:
63 self.failure_cb()
64 else:
65 raise
66
67 def set_data(self, data, failure_cb=None):
68 if self.data == data:
69 return
70 self.failure_cb = failure_cb
71 MinSize = 210 if len(data) < 128 else 500
72 self.setMinimumSize((MinSize, MinSize))
73 self.data = data
74 self.qr = None
75
76 def update_qr(self):
77 if not self.data and self.qr:
78 return
79 L = qrcode.constants.ERROR_CORRECT_L
80 data = self.data
81 self.qr = qr = qrcode.QRCode(
82 version=None,
83 error_correction=L,
84 box_size=10,
85 border=0,
86 )
87 qr.add_data(data)
88 qr.make(fit=True)
89 self.update_texture()
90
91 def setMinimumSize(self, size):
92 # currently unused, do we need this?
93 self._texture_size = size
94
95 def _create_texture(self, k):
96 self._qrtexture = texture = Texture.create(size=(k,k), colorfmt='rgb')
97 # don't interpolate texture
98 texture.min_filter = 'nearest'
99 texture.mag_filter = 'nearest'
100
101 def update_texture(self):
102 if not self.qr:
103 return
104 matrix = self.qr.get_matrix()
105 k = len(matrix)
106 # create the texture
107 self._create_texture(k)
108 buff = []
109 bext = buff.extend
110 cr, cg, cb, ca = self.background_color[:]
111 cr, cg, cb = cr*255, cg*255, cb*255
112 for r in range(k):
113 for c in range(k):
114 bext([0, 0, 0] if matrix[k-1-r][c] else [cr, cg, cb])
115 # then blit the buffer
116 buff = bytes(buff)
117 # update texture
118 self._upd_texture(buff)
119
120 def _upd_texture(self, buff):
121 texture = self._qrtexture
122 texture.blit_buffer(buff, colorfmt='rgb', bufferfmt='ubyte')
123 img = self.ids.qrimage
124 img.anim_delay = -1
125 img.texture = texture
126 img.canvas.ask_update()
127
128 if __name__ == '__main__':
129 from kivy.app import runTouchApp
130 import sys
131 data = str(sys.argv[1:])
132 runTouchApp(QRCodeWidget(data=data))
133
134