kivyblocks/kivyblocks/qrdata.py
2020-08-02 10:08:57 +08:00

146 lines
3.6 KiB
Python

''' Kivy Widget that accepts data and displays qrcode
'''
from threading import Thread
from functools import partial
from kivy.factory import Factory
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty, StringProperty, ListProperty,\
BooleanProperty
from kivy.lang import Builder
from kivy.clock import Clock
import qrcode
class QRCodeWidget(FloatLayout):
data = StringProperty(None, allow_none=True)
''' Data using which the qrcode is generated.
:data:`data` is a :class:`~kivy.properties.StringProperty`, defaulting to
`None`.
'''
loading_image = StringProperty('data/images/image-loading.gif')
'''Intermediate image to be displayed while the widget ios being loaded.
:data:`loading_image` is a :class:`~kivy.properties.StringProperty`,
defaulting to `'data/images/image-loading.gif'`.
'''
def __init__(self, **kwargs):
self.qrimage = Image(allow_stretch=True)
self.addr = None
super(QRCodeWidget, self).__init__(**kwargs)
self.background_color = [1,1,1,1]
self.qr = None
self._qrtexture = None
self.qrimage.pos_hint = {'center_x':0.5, 'center_y':0.5}
self.add_widget(self.qrimage)
def on_size(self,o,s):
self.qrimage.width = self.width
self.qrimage.height = self.height
self.on_data(None,self.data)
def on_data(self, instance, value):
if not (self.canvas or value):
return
img = self.qrimage
img.anim_delay = .25
img.source = self.loading_image
self.generate_qr(value)
def generate_qr(self, value):
self.set_addr(value)
self.update_qr()
def set_addr(self, addr):
if self.addr == addr:
return
MinSize = 210 if len(addr) < 128 else 500
self.setMinimumSize((MinSize, MinSize))
self.addr = addr
self.qr = None
def update_qr(self):
if not self.addr and self.qr:
return
QRCode = qrcode.QRCode
L = qrcode.constants.ERROR_CORRECT_L
addr = self.addr
try:
self.qr = qr = QRCode(
version=None,
error_correction=L,
box_size=10,
border=0,
)
qr.add_data(addr)
qr.make(fit=True)
self.qr = qr
self.update_texture()
except Exception as e:
print('eeeee',e)
self.qr=None
def setMinimumSize(self, size):
# currently unused, do we need this?
self._texture_size = size
def _create_texture(self, k):
self._qrtexture = texture = Texture.create(size=(k,k), colorfmt='rgb')
# don't interpolate texture
texture.min_filter = 'nearest'
texture.mag_filter = 'nearest'
def update_texture(self):
if not self.addr:
return
matrix = self.qr.get_matrix()
k = len(matrix)
self._create_texture(k)
cr, cg, cb = 255, 255, 255
###used bytearray for python 3.5 eliminates need for btext
buff = bytearray()
for r in range(k):
for c in range(k):
buff.extend([0, 0, 0] if matrix[r][c] else [cr, cg, cb])
# then blit the buffer
# join not neccesarry when using a byte array
# buff =''.join(map(chr, buff))
# update texture in UI thread.
self._upd_texture(buff)
def _upd_texture(self, buff):
texture = self._qrtexture
if not texture:
# if texture hasn't yet been created delay the texture updation
Clock.schedule_once(lambda dt: self._upd_texture(buff))
return
texture.blit_buffer(buff, colorfmt='rgb', bufferfmt='ubyte')
texture.flip_vertical()
img = self.qrimage
img.anim_delay = -1
img.texture = texture
img.canvas.ask_update()
Factory.register('QRCodeWidget',QRCodeWidget)
if __name__ == '__main__':
from kivy.app import runTouchApp
import sys
data = str(sys.argv[1:])
data = """{
"host":"122.22.22.33",
"port":12345
}"""
runTouchApp(Factory.QRCodeWidget(data=data))