electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

qrcodewidget.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